aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBhanu Prakash Gollapudi <bprakash@broadcom.com>2012-04-24 18:26:02 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-05-22 05:00:06 -0400
commitc1bb4f33de87ad18ace1cf484ed0c78683d933a1 (patch)
treec141deace94fc5d923d19bb4e85bacf506bce215 /drivers/scsi
parentde9c05fafc296aa95b58352bad7f23f6199aa90d (diff)
[SCSI] bnx2fc: Decrememnt io ref count when abort times out
When IO abort times out during eh_abort or a flush operation is performed while abort is pending, the driver is not cleaning up the IO and thus not reducing the IO reference count. With this change, as part of explicit logout, the IO is cleaned up. Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c106
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c11
2 files changed, 70 insertions, 47 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index e897ce975bb8..43258c3c90ae 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1089,6 +1089,48 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
1089 return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); 1089 return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
1090} 1090}
1091 1091
1092int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req)
1093{
1094 struct bnx2fc_rport *tgt = io_req->tgt;
1095 struct fc_rport_priv *rdata = tgt->rdata;
1096 int logo_issued;
1097 int rc = SUCCESS;
1098 int wait_cnt = 0;
1099
1100 BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n",
1101 tgt->flags);
1102 logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO,
1103 &tgt->flags);
1104 io_req->wait_for_comp = 1;
1105 bnx2fc_initiate_cleanup(io_req);
1106
1107 spin_unlock_bh(&tgt->tgt_lock);
1108
1109 wait_for_completion(&io_req->tm_done);
1110
1111 io_req->wait_for_comp = 0;
1112 /*
1113 * release the reference taken in eh_abort to allow the
1114 * target to re-login after flushing IOs
1115 */
1116 kref_put(&io_req->refcount, bnx2fc_cmd_release);
1117
1118 if (!logo_issued) {
1119 clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
1120 mutex_lock(&lport->disc.disc_mutex);
1121 lport->tt.rport_logoff(rdata);
1122 mutex_unlock(&lport->disc.disc_mutex);
1123 do {
1124 msleep(BNX2FC_RELOGIN_WAIT_TIME);
1125 if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) {
1126 rc = FAILED;
1127 break;
1128 }
1129 } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags));
1130 }
1131 spin_lock_bh(&tgt->tgt_lock);
1132 return rc;
1133}
1092/** 1134/**
1093 * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding 1135 * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding
1094 * SCSI command 1136 * SCSI command
@@ -1103,10 +1145,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
1103 struct fc_rport_libfc_priv *rp = rport->dd_data; 1145 struct fc_rport_libfc_priv *rp = rport->dd_data;
1104 struct bnx2fc_cmd *io_req; 1146 struct bnx2fc_cmd *io_req;
1105 struct fc_lport *lport; 1147 struct fc_lport *lport;
1106 struct fc_rport_priv *rdata;
1107 struct bnx2fc_rport *tgt; 1148 struct bnx2fc_rport *tgt;
1108 int logo_issued;
1109 int wait_cnt = 0;
1110 int rc = FAILED; 1149 int rc = FAILED;
1111 1150
1112 1151
@@ -1183,58 +1222,31 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
1183 list_add_tail(&io_req->link, &tgt->io_retire_queue); 1222 list_add_tail(&io_req->link, &tgt->io_retire_queue);
1184 1223
1185 init_completion(&io_req->tm_done); 1224 init_completion(&io_req->tm_done);
1186 io_req->wait_for_comp = 1;
1187 1225
1188 if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { 1226 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) " 1227 printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
1197 "already in abts processing\n", io_req->xid); 1228 "already in abts processing\n", io_req->xid);
1198 if (cancel_delayed_work(&io_req->timeout_work)) 1229 if (cancel_delayed_work(&io_req->timeout_work))
1199 kref_put(&io_req->refcount, 1230 kref_put(&io_req->refcount,
1200 bnx2fc_cmd_release); /* drop timer hold */ 1231 bnx2fc_cmd_release); /* drop timer hold */
1201 bnx2fc_initiate_cleanup(io_req); 1232 rc = bnx2fc_expl_logo(lport, io_req);
1233 goto out;
1234 }
1202 1235
1236 /* Cancel the current timer running on this io_req */
1237 if (cancel_delayed_work(&io_req->timeout_work))
1238 kref_put(&io_req->refcount,
1239 bnx2fc_cmd_release); /* drop timer hold */
1240 set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
1241 io_req->wait_for_comp = 1;
1242 rc = bnx2fc_initiate_abts(io_req);
1243 if (rc == FAILED) {
1244 bnx2fc_initiate_cleanup(io_req);
1203 spin_unlock_bh(&tgt->tgt_lock); 1245 spin_unlock_bh(&tgt->tgt_lock);
1204
1205 wait_for_completion(&io_req->tm_done); 1246 wait_for_completion(&io_req->tm_done);
1206
1207 spin_lock_bh(&tgt->tgt_lock); 1247 spin_lock_bh(&tgt->tgt_lock);
1208 io_req->wait_for_comp = 0; 1248 io_req->wait_for_comp = 0;
1209 rdata = io_req->tgt->rdata; 1249 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 } 1250 }
1239 spin_unlock_bh(&tgt->tgt_lock); 1251 spin_unlock_bh(&tgt->tgt_lock);
1240 1252
@@ -1247,7 +1259,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
1247 /* Let the scsi-ml try to recover this command */ 1259 /* Let the scsi-ml try to recover this command */
1248 printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", 1260 printk(KERN_ERR PFX "abort failed, xid = 0x%x\n",
1249 io_req->xid); 1261 io_req->xid);
1250 rc = FAILED; 1262 rc = bnx2fc_expl_logo(lport, io_req);
1263 goto out;
1251 } else { 1264 } else {
1252 /* 1265 /*
1253 * We come here even when there was a race condition 1266 * We come here even when there was a race condition
@@ -1259,9 +1272,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
1259 bnx2fc_scsi_done(io_req, DID_ABORT); 1272 bnx2fc_scsi_done(io_req, DID_ABORT);
1260 kref_put(&io_req->refcount, bnx2fc_cmd_release); 1273 kref_put(&io_req->refcount, bnx2fc_cmd_release);
1261 } 1274 }
1262 1275done:
1263 /* release the reference taken in eh_abort */ 1276 /* release the reference taken in eh_abort */
1264 kref_put(&io_req->refcount, bnx2fc_cmd_release); 1277 kref_put(&io_req->refcount, bnx2fc_cmd_release);
1278out:
1265 spin_unlock_bh(&tgt->tgt_lock); 1279 spin_unlock_bh(&tgt->tgt_lock);
1266 return rc; 1280 return rc;
1267} 1281}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index c1800b531270..d3ee231a5680 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -213,8 +213,17 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
213 213
214 BNX2FC_IO_DBG(io_req, "retire_queue flush\n"); 214 BNX2FC_IO_DBG(io_req, "retire_queue flush\n");
215 215
216 if (cancel_delayed_work(&io_req->timeout_work)) 216 if (cancel_delayed_work(&io_req->timeout_work)) {
217 if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
218 &io_req->req_flags)) {
219 /* Handle eh_abort timeout */
220 BNX2FC_IO_DBG(io_req, "eh_abort for IO "
221 "in retire_q\n");
222 if (io_req->wait_for_comp)
223 complete(&io_req->tm_done);
224 }
217 kref_put(&io_req->refcount, bnx2fc_cmd_release); 225 kref_put(&io_req->refcount, bnx2fc_cmd_release);
226 }
218 227
219 clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); 228 clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags);
220 } 229 }