Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Bhanu Prakash Gollapudi and committed by
James Bottomley
c1bb4f33 de9c05fa

+70 -47
+60 -46
drivers/scsi/bnx2fc/bnx2fc_io.c
··· 1089 1089 return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); 1090 1090 } 1091 1091 1092 + int 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 1135 * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding 1094 1136 * SCSI command ··· 1145 1103 struct fc_rport_libfc_priv *rp = rport->dd_data; 1146 1104 struct bnx2fc_cmd *io_req; 1147 1105 struct fc_lport *lport; 1148 - struct fc_rport_priv *rdata; 1149 1106 struct bnx2fc_rport *tgt; 1150 - int logo_issued; 1151 - int wait_cnt = 0; 1152 1107 int rc = FAILED; 1153 1108 1154 1109 ··· 1222 1183 list_add_tail(&io_req->link, &tgt->io_retire_queue); 1223 1184 1224 1185 init_completion(&io_req->tm_done); 1225 - io_req->wait_for_comp = 1; 1226 1186 1227 - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { 1228 - /* Cancel the current timer running on this io_req */ 1229 - if (cancel_delayed_work(&io_req->timeout_work)) 1230 - kref_put(&io_req->refcount, 1231 - bnx2fc_cmd_release); /* drop timer hold */ 1232 - set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); 1233 - rc = bnx2fc_initiate_abts(io_req); 1234 - } else { 1187 + if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { 1235 1188 printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " 1236 1189 "already in abts processing\n", io_req->xid); 1237 1190 if (cancel_delayed_work(&io_req->timeout_work)) 1238 1191 kref_put(&io_req->refcount, 1239 1192 bnx2fc_cmd_release); /* drop timer hold */ 1193 + rc = bnx2fc_expl_logo(lport, io_req); 1194 + goto out; 1195 + } 1196 + 1197 + /* Cancel the current timer running on this io_req */ 1198 + if (cancel_delayed_work(&io_req->timeout_work)) 1199 + kref_put(&io_req->refcount, 1200 + bnx2fc_cmd_release); /* drop timer hold */ 1201 + set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); 1202 + io_req->wait_for_comp = 1; 1203 + rc = bnx2fc_initiate_abts(io_req); 1204 + if (rc == FAILED) { 1240 1205 bnx2fc_initiate_cleanup(io_req); 1241 - 1242 1206 spin_unlock_bh(&tgt->tgt_lock); 1243 - 1244 1207 wait_for_completion(&io_req->tm_done); 1245 - 1246 1208 spin_lock_bh(&tgt->tgt_lock); 1247 1209 io_req->wait_for_comp = 0; 1248 - rdata = io_req->tgt->rdata; 1249 - logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, 1250 - &tgt->flags); 1251 - kref_put(&io_req->refcount, bnx2fc_cmd_release); 1252 - spin_unlock_bh(&tgt->tgt_lock); 1253 - 1254 - if (!logo_issued) { 1255 - BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", 1256 - tgt->flags); 1257 - mutex_lock(&lport->disc.disc_mutex); 1258 - lport->tt.rport_logoff(rdata); 1259 - mutex_unlock(&lport->disc.disc_mutex); 1260 - do { 1261 - msleep(BNX2FC_RELOGIN_WAIT_TIME); 1262 - /* 1263 - * If session not recovered, let SCSI-ml 1264 - * escalate error recovery. 1265 - */ 1266 - if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) 1267 - return FAILED; 1268 - } while (!test_bit(BNX2FC_FLAG_SESSION_READY, 1269 - &tgt->flags)); 1270 - } 1271 - return SUCCESS; 1272 - } 1273 - if (rc == FAILED) { 1274 - kref_put(&io_req->refcount, bnx2fc_cmd_release); 1275 - spin_unlock_bh(&tgt->tgt_lock); 1276 - return rc; 1210 + goto done; 1277 1211 } 1278 1212 spin_unlock_bh(&tgt->tgt_lock); 1279 1213 ··· 1259 1247 /* Let the scsi-ml try to recover this command */ 1260 1248 printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", 1261 1249 io_req->xid); 1262 - rc = FAILED; 1250 + rc = bnx2fc_expl_logo(lport, io_req); 1251 + goto out; 1263 1252 } else { 1264 1253 /* 1265 1254 * We come here even when there was a race condition ··· 1272 1259 bnx2fc_scsi_done(io_req, DID_ABORT); 1273 1260 kref_put(&io_req->refcount, bnx2fc_cmd_release); 1274 1261 } 1275 - 1262 + done: 1276 1263 /* release the reference taken in eh_abort */ 1277 1264 kref_put(&io_req->refcount, bnx2fc_cmd_release); 1265 + out: 1278 1266 spin_unlock_bh(&tgt->tgt_lock); 1279 1267 return rc; 1280 1268 }
+10 -1
drivers/scsi/bnx2fc/bnx2fc_tgt.c
··· 213 213 214 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 225 kref_put(&io_req->refcount, bnx2fc_cmd_release); 226 + } 218 227 219 228 clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); 220 229 }