diff options
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_io.c')
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_io.c | 122 |
1 files changed, 75 insertions, 47 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index e897ce975bb8..4f7453b9e41e 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c | |||
@@ -810,8 +810,22 @@ retry_tmf: | |||
810 | spin_lock_bh(&tgt->tgt_lock); | 810 | spin_lock_bh(&tgt->tgt_lock); |
811 | 811 | ||
812 | io_req->wait_for_comp = 0; | 812 | io_req->wait_for_comp = 0; |
813 | if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) | 813 | if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) { |
814 | set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); | 814 | set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); |
815 | if (io_req->on_tmf_queue) { | ||
816 | list_del_init(&io_req->link); | ||
817 | io_req->on_tmf_queue = 0; | ||
818 | } | ||
819 | io_req->wait_for_comp = 1; | ||
820 | bnx2fc_initiate_cleanup(io_req); | ||
821 | spin_unlock_bh(&tgt->tgt_lock); | ||
822 | rc = wait_for_completion_timeout(&io_req->tm_done, | ||
823 | BNX2FC_FW_TIMEOUT); | ||
824 | spin_lock_bh(&tgt->tgt_lock); | ||
825 | io_req->wait_for_comp = 0; | ||
826 | if (!rc) | ||
827 | kref_put(&io_req->refcount, bnx2fc_cmd_release); | ||
828 | } | ||
815 | 829 | ||
816 | spin_unlock_bh(&tgt->tgt_lock); | 830 | spin_unlock_bh(&tgt->tgt_lock); |
817 | 831 | ||
@@ -1089,6 +1103,48 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) | |||
1089 | return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); | 1103 | return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); |
1090 | } | 1104 | } |
1091 | 1105 | ||
1106 | int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) | ||
1107 | { | ||
1108 | struct bnx2fc_rport *tgt = io_req->tgt; | ||
1109 | struct fc_rport_priv *rdata = tgt->rdata; | ||
1110 | int logo_issued; | ||
1111 | int rc = SUCCESS; | ||
1112 | int wait_cnt = 0; | ||
1113 | |||
1114 | BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", | ||
1115 | tgt->flags); | ||
1116 | logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, | ||
1117 | &tgt->flags); | ||
1118 | io_req->wait_for_comp = 1; | ||
1119 | bnx2fc_initiate_cleanup(io_req); | ||
1120 | |||
1121 | spin_unlock_bh(&tgt->tgt_lock); | ||
1122 | |||
1123 | wait_for_completion(&io_req->tm_done); | ||
1124 | |||
1125 | io_req->wait_for_comp = 0; | ||
1126 | /* | ||
1127 | * release the reference taken in eh_abort to allow the | ||
1128 | * target to re-login after flushing IOs | ||
1129 | */ | ||
1130 | kref_put(&io_req->refcount, bnx2fc_cmd_release); | ||
1131 | |||
1132 | if (!logo_issued) { | ||
1133 | clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); | ||
1134 | mutex_lock(&lport->disc.disc_mutex); | ||
1135 | lport->tt.rport_logoff(rdata); | ||
1136 | mutex_unlock(&lport->disc.disc_mutex); | ||
1137 | do { | ||
1138 | msleep(BNX2FC_RELOGIN_WAIT_TIME); | ||
1139 | if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) { | ||
1140 | rc = FAILED; | ||
1141 | break; | ||
1142 | } | ||
1143 | } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)); | ||
1144 | } | ||
1145 | spin_lock_bh(&tgt->tgt_lock); | ||
1146 | return rc; | ||
1147 | } | ||
1092 | /** | 1148 | /** |
1093 | * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding | 1149 | * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding |
1094 | * SCSI command | 1150 | * SCSI command |
@@ -1103,10 +1159,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) | |||
1103 | struct fc_rport_libfc_priv *rp = rport->dd_data; | 1159 | struct fc_rport_libfc_priv *rp = rport->dd_data; |
1104 | struct bnx2fc_cmd *io_req; | 1160 | struct bnx2fc_cmd *io_req; |
1105 | struct fc_lport *lport; | 1161 | struct fc_lport *lport; |
1106 | struct fc_rport_priv *rdata; | ||
1107 | struct bnx2fc_rport *tgt; | 1162 | struct bnx2fc_rport *tgt; |
1108 | int logo_issued; | ||
1109 | int wait_cnt = 0; | ||
1110 | int rc = FAILED; | 1163 | int rc = FAILED; |
1111 | 1164 | ||
1112 | 1165 | ||
@@ -1183,58 +1236,31 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) | |||
1183 | list_add_tail(&io_req->link, &tgt->io_retire_queue); | 1236 | list_add_tail(&io_req->link, &tgt->io_retire_queue); |
1184 | 1237 | ||
1185 | init_completion(&io_req->tm_done); | 1238 | init_completion(&io_req->tm_done); |
1186 | io_req->wait_for_comp = 1; | ||
1187 | 1239 | ||
1188 | if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { | 1240 | if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { |
1189 | /* Cancel the current timer running on this io_req */ | ||
1190 | if (cancel_delayed_work(&io_req->timeout_work)) | ||
1191 | kref_put(&io_req->refcount, | ||
1192 | bnx2fc_cmd_release); /* drop timer hold */ | ||
1193 | set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); | ||
1194 | rc = bnx2fc_initiate_abts(io_req); | ||
1195 | } else { | ||
1196 | printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " | 1241 | printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " |
1197 | "already in abts processing\n", io_req->xid); | 1242 | "already in abts processing\n", io_req->xid); |
1198 | if (cancel_delayed_work(&io_req->timeout_work)) | 1243 | if (cancel_delayed_work(&io_req->timeout_work)) |
1199 | kref_put(&io_req->refcount, | 1244 | kref_put(&io_req->refcount, |
1200 | bnx2fc_cmd_release); /* drop timer hold */ | 1245 | bnx2fc_cmd_release); /* drop timer hold */ |
1201 | bnx2fc_initiate_cleanup(io_req); | 1246 | rc = bnx2fc_expl_logo(lport, io_req); |
1247 | goto out; | ||
1248 | } | ||
1202 | 1249 | ||
1250 | /* Cancel the current timer running on this io_req */ | ||
1251 | if (cancel_delayed_work(&io_req->timeout_work)) | ||
1252 | kref_put(&io_req->refcount, | ||
1253 | bnx2fc_cmd_release); /* drop timer hold */ | ||
1254 | set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); | ||
1255 | io_req->wait_for_comp = 1; | ||
1256 | rc = bnx2fc_initiate_abts(io_req); | ||
1257 | if (rc == FAILED) { | ||
1258 | bnx2fc_initiate_cleanup(io_req); | ||
1203 | spin_unlock_bh(&tgt->tgt_lock); | 1259 | spin_unlock_bh(&tgt->tgt_lock); |
1204 | |||
1205 | wait_for_completion(&io_req->tm_done); | 1260 | wait_for_completion(&io_req->tm_done); |
1206 | |||
1207 | spin_lock_bh(&tgt->tgt_lock); | 1261 | spin_lock_bh(&tgt->tgt_lock); |
1208 | io_req->wait_for_comp = 0; | 1262 | io_req->wait_for_comp = 0; |
1209 | rdata = io_req->tgt->rdata; | 1263 | goto done; |
1210 | logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, | ||
1211 | &tgt->flags); | ||
1212 | kref_put(&io_req->refcount, bnx2fc_cmd_release); | ||
1213 | spin_unlock_bh(&tgt->tgt_lock); | ||
1214 | |||
1215 | if (!logo_issued) { | ||
1216 | BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", | ||
1217 | tgt->flags); | ||
1218 | mutex_lock(&lport->disc.disc_mutex); | ||
1219 | lport->tt.rport_logoff(rdata); | ||
1220 | mutex_unlock(&lport->disc.disc_mutex); | ||
1221 | do { | ||
1222 | msleep(BNX2FC_RELOGIN_WAIT_TIME); | ||
1223 | /* | ||
1224 | * If session not recovered, let SCSI-ml | ||
1225 | * escalate error recovery. | ||
1226 | */ | ||
1227 | if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) | ||
1228 | return FAILED; | ||
1229 | } while (!test_bit(BNX2FC_FLAG_SESSION_READY, | ||
1230 | &tgt->flags)); | ||
1231 | } | ||
1232 | return SUCCESS; | ||
1233 | } | ||
1234 | if (rc == FAILED) { | ||
1235 | kref_put(&io_req->refcount, bnx2fc_cmd_release); | ||
1236 | spin_unlock_bh(&tgt->tgt_lock); | ||
1237 | return rc; | ||
1238 | } | 1264 | } |
1239 | spin_unlock_bh(&tgt->tgt_lock); | 1265 | spin_unlock_bh(&tgt->tgt_lock); |
1240 | 1266 | ||
@@ -1247,7 +1273,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) | |||
1247 | /* Let the scsi-ml try to recover this command */ | 1273 | /* Let the scsi-ml try to recover this command */ |
1248 | printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", | 1274 | printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", |
1249 | io_req->xid); | 1275 | io_req->xid); |
1250 | rc = FAILED; | 1276 | rc = bnx2fc_expl_logo(lport, io_req); |
1277 | goto out; | ||
1251 | } else { | 1278 | } else { |
1252 | /* | 1279 | /* |
1253 | * We come here even when there was a race condition | 1280 | * We come here even when there was a race condition |
@@ -1259,9 +1286,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) | |||
1259 | bnx2fc_scsi_done(io_req, DID_ABORT); | 1286 | bnx2fc_scsi_done(io_req, DID_ABORT); |
1260 | kref_put(&io_req->refcount, bnx2fc_cmd_release); | 1287 | kref_put(&io_req->refcount, bnx2fc_cmd_release); |
1261 | } | 1288 | } |
1262 | 1289 | done: | |
1263 | /* release the reference taken in eh_abort */ | 1290 | /* release the reference taken in eh_abort */ |
1264 | kref_put(&io_req->refcount, bnx2fc_cmd_release); | 1291 | kref_put(&io_req->refcount, bnx2fc_cmd_release); |
1292 | out: | ||
1265 | spin_unlock_bh(&tgt->tgt_lock); | 1293 | spin_unlock_bh(&tgt->tgt_lock); |
1266 | return rc; | 1294 | return rc; |
1267 | } | 1295 | } |