@@ -155,6 +155,9 @@ static long ibmvscsis_unregister_command_q(struct scsi_info *vscsi)
155155 qrc = h_free_crq (vscsi -> dds .unit_id );
156156 switch (qrc ) {
157157 case H_SUCCESS :
158+ spin_lock_bh (& vscsi -> intr_lock );
159+ vscsi -> flags &= ~PREP_FOR_SUSPEND_FLAGS ;
160+ spin_unlock_bh (& vscsi -> intr_lock );
158161 break ;
159162
160163 case H_HARDWARE :
@@ -422,6 +425,9 @@ static void ibmvscsis_disconnect(struct work_struct *work)
422425 new_state = vscsi -> new_state ;
423426 vscsi -> new_state = 0 ;
424427
428+ vscsi -> flags |= DISCONNECT_SCHEDULED ;
429+ vscsi -> flags &= ~SCHEDULE_DISCONNECT ;
430+
425431 pr_debug ("disconnect: flags 0x%x, state 0x%hx\n" , vscsi -> flags ,
426432 vscsi -> state );
427433
@@ -802,6 +808,13 @@ static long ibmvscsis_establish_new_q(struct scsi_info *vscsi)
802808 long rc = ADAPT_SUCCESS ;
803809 uint format ;
804810
811+ rc = h_vioctl (vscsi -> dds .unit_id , H_ENABLE_PREPARE_FOR_SUSPEND , 30000 ,
812+ 0 , 0 , 0 , 0 );
813+ if (rc == H_SUCCESS )
814+ vscsi -> flags |= PREP_FOR_SUSPEND_ENABLED ;
815+ else if (rc != H_NOT_FOUND )
816+ pr_err ("Error from Enable Prepare for Suspend: %ld\n" , rc );
817+
805818 vscsi -> flags &= PRESERVE_FLAG_FIELDS ;
806819 vscsi -> rsp_q_timer .timer_pops = 0 ;
807820 vscsi -> debit = 0 ;
@@ -950,6 +963,63 @@ static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
950963 }
951964}
952965
966+ /**
967+ * ibmvscsis_ready_for_suspend() - Helper function to call VIOCTL
968+ * @vscsi: Pointer to our adapter structure
969+ * @idle: Indicates whether we were called from adapter_idle. This
970+ * is important to know if we need to do a disconnect, since if
971+ * we're called from adapter_idle, we're still processing the
972+ * current disconnect, so we can't just call post_disconnect.
973+ *
974+ * This function is called when the adapter is idle when phyp has sent
975+ * us a Prepare for Suspend Transport Event.
976+ *
977+ * EXECUTION ENVIRONMENT:
978+ * Process or interrupt environment called with interrupt lock held
979+ */
980+ static long ibmvscsis_ready_for_suspend (struct scsi_info * vscsi , bool idle )
981+ {
982+ long rc = 0 ;
983+ struct viosrp_crq * crq ;
984+
985+ /* See if there is a Resume event in the queue */
986+ crq = vscsi -> cmd_q .base_addr + vscsi -> cmd_q .index ;
987+
988+ pr_debug ("ready_suspend: flags 0x%x, state 0x%hx crq_valid:%x\n" ,
989+ vscsi -> flags , vscsi -> state , (int )crq -> valid );
990+
991+ if (!(vscsi -> flags & PREP_FOR_SUSPEND_ABORTED ) && !(crq -> valid )) {
992+ rc = h_vioctl (vscsi -> dds .unit_id , H_READY_FOR_SUSPEND , 0 , 0 , 0 ,
993+ 0 , 0 );
994+ if (rc ) {
995+ pr_err ("Ready for Suspend Vioctl failed: %ld\n" , rc );
996+ rc = 0 ;
997+ }
998+ } else if (((vscsi -> flags & PREP_FOR_SUSPEND_OVERWRITE ) &&
999+ (vscsi -> flags & PREP_FOR_SUSPEND_ABORTED )) ||
1000+ ((crq -> valid ) && ((crq -> valid != VALID_TRANS_EVENT ) ||
1001+ (crq -> format != RESUME_FROM_SUSP )))) {
1002+ if (idle ) {
1003+ vscsi -> state = ERR_DISCONNECT_RECONNECT ;
1004+ ibmvscsis_reset_queue (vscsi );
1005+ rc = -1 ;
1006+ } else if (vscsi -> state == CONNECTED ) {
1007+ ibmvscsis_post_disconnect (vscsi ,
1008+ ERR_DISCONNECT_RECONNECT , 0 );
1009+ }
1010+
1011+ vscsi -> flags &= ~PREP_FOR_SUSPEND_OVERWRITE ;
1012+
1013+ if ((crq -> valid ) && ((crq -> valid != VALID_TRANS_EVENT ) ||
1014+ (crq -> format != RESUME_FROM_SUSP )))
1015+ pr_err ("Invalid element in CRQ after Prepare for Suspend" );
1016+ }
1017+
1018+ vscsi -> flags &= ~(PREP_FOR_SUSPEND_PENDING | PREP_FOR_SUSPEND_ABORTED );
1019+
1020+ return rc ;
1021+ }
1022+
9531023/**
9541024 * ibmvscsis_trans_event() - Handle a Transport Event
9551025 * @vscsi: Pointer to our adapter structure
@@ -974,18 +1044,8 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi,
9741044 case PARTNER_FAILED :
9751045 case PARTNER_DEREGISTER :
9761046 ibmvscsis_delete_client_info (vscsi , true);
977- break ;
978-
979- default :
980- rc = ERROR ;
981- dev_err (& vscsi -> dev , "trans_event: invalid format %d\n" ,
982- (uint )crq -> format );
983- ibmvscsis_post_disconnect (vscsi , ERR_DISCONNECT ,
984- RESPONSE_Q_DOWN );
985- break ;
986- }
987-
988- if (rc == ADAPT_SUCCESS ) {
1047+ if (crq -> format == MIGRATED )
1048+ vscsi -> flags &= ~PREP_FOR_SUSPEND_OVERWRITE ;
9891049 switch (vscsi -> state ) {
9901050 case NO_QUEUE :
9911051 case ERR_DISCONNECTED :
@@ -1034,6 +1094,60 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi,
10341094 vscsi -> flags |= (RESPONSE_Q_DOWN | TRANS_EVENT );
10351095 break ;
10361096 }
1097+ break ;
1098+
1099+ case PREPARE_FOR_SUSPEND :
1100+ pr_debug ("Prep for Suspend, crq status = 0x%x\n" ,
1101+ (int )crq -> status );
1102+ switch (vscsi -> state ) {
1103+ case ERR_DISCONNECTED :
1104+ case WAIT_CONNECTION :
1105+ case CONNECTED :
1106+ ibmvscsis_ready_for_suspend (vscsi , false);
1107+ break ;
1108+ case SRP_PROCESSING :
1109+ vscsi -> resume_state = vscsi -> state ;
1110+ vscsi -> flags |= PREP_FOR_SUSPEND_PENDING ;
1111+ if (crq -> status == CRQ_ENTRY_OVERWRITTEN )
1112+ vscsi -> flags |= PREP_FOR_SUSPEND_OVERWRITE ;
1113+ ibmvscsis_post_disconnect (vscsi , WAIT_IDLE , 0 );
1114+ break ;
1115+ case NO_QUEUE :
1116+ case UNDEFINED :
1117+ case UNCONFIGURING :
1118+ case WAIT_ENABLED :
1119+ case ERR_DISCONNECT :
1120+ case ERR_DISCONNECT_RECONNECT :
1121+ case WAIT_IDLE :
1122+ pr_err ("Invalid state for Prepare for Suspend Trans Event: 0x%x\n" ,
1123+ vscsi -> state );
1124+ break ;
1125+ }
1126+ break ;
1127+
1128+ case RESUME_FROM_SUSP :
1129+ pr_debug ("Resume from Suspend, crq status = 0x%x\n" ,
1130+ (int )crq -> status );
1131+ if (vscsi -> flags & PREP_FOR_SUSPEND_PENDING ) {
1132+ vscsi -> flags |= PREP_FOR_SUSPEND_ABORTED ;
1133+ } else {
1134+ if ((crq -> status == CRQ_ENTRY_OVERWRITTEN ) ||
1135+ (vscsi -> flags & PREP_FOR_SUSPEND_OVERWRITE )) {
1136+ ibmvscsis_post_disconnect (vscsi ,
1137+ ERR_DISCONNECT_RECONNECT ,
1138+ 0 );
1139+ vscsi -> flags &= ~PREP_FOR_SUSPEND_OVERWRITE ;
1140+ }
1141+ }
1142+ break ;
1143+
1144+ default :
1145+ rc = ERROR ;
1146+ dev_err (& vscsi -> dev , "trans_event: invalid format %d\n" ,
1147+ (uint )crq -> format );
1148+ ibmvscsis_post_disconnect (vscsi , ERR_DISCONNECT ,
1149+ RESPONSE_Q_DOWN );
1150+ break ;
10371151 }
10381152
10391153 rc = vscsi -> flags & SCHEDULE_DISCONNECT ;
@@ -1201,6 +1315,7 @@ static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
12011315static void ibmvscsis_adapter_idle (struct scsi_info * vscsi )
12021316{
12031317 int free_qs = false;
1318+ long rc = 0 ;
12041319
12051320 pr_debug ("adapter_idle: flags 0x%x, state 0x%hx\n" , vscsi -> flags ,
12061321 vscsi -> state );
@@ -1240,7 +1355,14 @@ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
12401355 vscsi -> rsp_q_timer .timer_pops = 0 ;
12411356 vscsi -> debit = 0 ;
12421357 vscsi -> credit = 0 ;
1243- if (vscsi -> flags & TRANS_EVENT ) {
1358+ if (vscsi -> flags & PREP_FOR_SUSPEND_PENDING ) {
1359+ vscsi -> state = vscsi -> resume_state ;
1360+ vscsi -> resume_state = 0 ;
1361+ rc = ibmvscsis_ready_for_suspend (vscsi , true);
1362+ vscsi -> flags &= ~DISCONNECT_SCHEDULED ;
1363+ if (rc )
1364+ break ;
1365+ } else if (vscsi -> flags & TRANS_EVENT ) {
12441366 vscsi -> state = WAIT_CONNECTION ;
12451367 vscsi -> flags &= PRESERVE_FLAG_FIELDS ;
12461368 } else {
0 commit comments