aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <james.smart@emulex.com>2012-05-09 21:17:07 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-05-17 05:57:29 -0400
commit4f2e66c6d225a14fcf77d826fe71f6137cb27352 (patch)
treeb6235968d1a223d83e750d41aab8100f912a68ea
parenta7dd9c0f44966b4328b52c5e32f8c3345e3482e5 (diff)
[SCSI] lpfc 8.3.31: Fixed system panic due to midlayer abort and driver complete race on SCSI cmd
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com> Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/lpfc/lpfc.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c48
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c23
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
5 files changed, 54 insertions, 21 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 3a1ffdd6d831..3099047d3faf 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -620,6 +620,7 @@ struct lpfc_hba {
620#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */ 620#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */
621#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ 621#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */
622#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ 622#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */
623#define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */
623 uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ 624 uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
624 struct lpfc_dmabuf slim2p; 625 struct lpfc_dmabuf slim2p;
625 626
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 620fa45866dc..9b2a16f3bc79 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -254,6 +254,7 @@ int
254lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, 254lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
255 struct lpfc_sli_ring *, uint32_t); 255 struct lpfc_sli_ring *, uint32_t);
256 256
257struct lpfc_iocbq *__lpfc_sli_get_iocbq(struct lpfc_hba *);
257struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); 258struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
258void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); 259void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *);
259uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); 260uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index bf0048a7a302..cdc5fb92c9f5 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -4396,8 +4396,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
4396 ret = fc_block_scsi_eh(cmnd); 4396 ret = fc_block_scsi_eh(cmnd);
4397 if (ret) 4397 if (ret)
4398 return ret; 4398 return ret;
4399
4400 spin_lock_irq(&phba->hbalock);
4401 /* driver queued commands are in process of being flushed */
4402 if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) {
4403 spin_unlock_irq(&phba->hbalock);
4404 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
4405 "3168 SCSI Layer abort requested I/O has been "
4406 "flushed by LLD.\n");
4407 return FAILED;
4408 }
4409
4399 lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; 4410 lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
4400 if (!lpfc_cmd) { 4411 if (!lpfc_cmd) {
4412 spin_unlock_irq(&phba->hbalock);
4401 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, 4413 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
4402 "2873 SCSI Layer I/O Abort Request IO CMPL Status " 4414 "2873 SCSI Layer I/O Abort Request IO CMPL Status "
4403 "x%x ID %d LUN %d\n", 4415 "x%x ID %d LUN %d\n",
@@ -4405,23 +4417,34 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
4405 return SUCCESS; 4417 return SUCCESS;
4406 } 4418 }
4407 4419
4420 iocb = &lpfc_cmd->cur_iocbq;
4421 /* the command is in process of being cancelled */
4422 if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) {
4423 spin_unlock_irq(&phba->hbalock);
4424 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
4425 "3169 SCSI Layer abort requested I/O has been "
4426 "cancelled by LLD.\n");
4427 return FAILED;
4428 }
4408 /* 4429 /*
4409 * If pCmd field of the corresponding lpfc_scsi_buf structure 4430 * If pCmd field of the corresponding lpfc_scsi_buf structure
4410 * points to a different SCSI command, then the driver has 4431 * points to a different SCSI command, then the driver has
4411 * already completed this command, but the midlayer did not 4432 * already completed this command, but the midlayer did not
4412 * see the completion before the eh fired. Just return 4433 * see the completion before the eh fired. Just return SUCCESS.
4413 * SUCCESS.
4414 */ 4434 */
4415 iocb = &lpfc_cmd->cur_iocbq; 4435 if (lpfc_cmd->pCmd != cmnd) {
4416 if (lpfc_cmd->pCmd != cmnd) 4436 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
4417 goto out; 4437 "3170 SCSI Layer abort requested I/O has been "
4438 "completed by LLD.\n");
4439 goto out_unlock;
4440 }
4418 4441
4419 BUG_ON(iocb->context1 != lpfc_cmd); 4442 BUG_ON(iocb->context1 != lpfc_cmd);
4420 4443
4421 abtsiocb = lpfc_sli_get_iocbq(phba); 4444 abtsiocb = __lpfc_sli_get_iocbq(phba);
4422 if (abtsiocb == NULL) { 4445 if (abtsiocb == NULL) {
4423 ret = FAILED; 4446 ret = FAILED;
4424 goto out; 4447 goto out_unlock;
4425 } 4448 }
4426 4449
4427 /* 4450 /*
@@ -4453,6 +4476,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
4453 4476
4454 abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; 4477 abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
4455 abtsiocb->vport = vport; 4478 abtsiocb->vport = vport;
4479 /* no longer need the lock after this point */
4480 spin_unlock_irq(&phba->hbalock);
4481
4456 if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == 4482 if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) ==
4457 IOCB_ERROR) { 4483 IOCB_ERROR) {
4458 lpfc_sli_release_iocbq(phba, abtsiocb); 4484 lpfc_sli_release_iocbq(phba, abtsiocb);
@@ -4469,10 +4495,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
4469 wait_event_timeout(waitq, 4495 wait_event_timeout(waitq,
4470 (lpfc_cmd->pCmd != cmnd), 4496 (lpfc_cmd->pCmd != cmnd),
4471 (2*vport->cfg_devloss_tmo*HZ)); 4497 (2*vport->cfg_devloss_tmo*HZ));
4472
4473 spin_lock_irq(shost->host_lock);
4474 lpfc_cmd->waitq = NULL; 4498 lpfc_cmd->waitq = NULL;
4475 spin_unlock_irq(shost->host_lock);
4476 4499
4477 if (lpfc_cmd->pCmd == cmnd) { 4500 if (lpfc_cmd->pCmd == cmnd) {
4478 ret = FAILED; 4501 ret = FAILED;
@@ -4482,8 +4505,11 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
4482 "LUN %d\n", 4505 "LUN %d\n",
4483 ret, cmnd->device->id, cmnd->device->lun); 4506 ret, cmnd->device->id, cmnd->device->lun);
4484 } 4507 }
4508 goto out;
4485 4509
4486 out: 4510out_unlock:
4511 spin_unlock_irq(&phba->hbalock);
4512out:
4487 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, 4513 lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
4488 "0749 SCSI Layer I/O Abort Request Status x%x ID %d " 4514 "0749 SCSI Layer I/O Abort Request Status x%x ID %d "
4489 "LUN %d\n", ret, cmnd->device->id, 4515 "LUN %d\n", ret, cmnd->device->id,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 57eaaa51e1d6..7c4067913c29 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -502,7 +502,7 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
502 * allocation is successful, it returns pointer to the newly 502 * allocation is successful, it returns pointer to the newly
503 * allocated iocb object else it returns NULL. 503 * allocated iocb object else it returns NULL.
504 **/ 504 **/
505static struct lpfc_iocbq * 505struct lpfc_iocbq *
506__lpfc_sli_get_iocbq(struct lpfc_hba *phba) 506__lpfc_sli_get_iocbq(struct lpfc_hba *phba)
507{ 507{
508 struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; 508 struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
@@ -1259,7 +1259,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1259 struct lpfc_iocbq *piocb) 1259 struct lpfc_iocbq *piocb)
1260{ 1260{
1261 list_add_tail(&piocb->list, &pring->txcmplq); 1261 list_add_tail(&piocb->list, &pring->txcmplq);
1262 piocb->iocb_flag |= LPFC_IO_ON_Q; 1262 piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
1263 pring->txcmplq_cnt++; 1263 pring->txcmplq_cnt++;
1264 if (pring->txcmplq_cnt > pring->txcmplq_max) 1264 if (pring->txcmplq_cnt > pring->txcmplq_max)
1265 pring->txcmplq_max = pring->txcmplq_cnt; 1265 pring->txcmplq_max = pring->txcmplq_cnt;
@@ -2558,9 +2558,9 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
2558 if (iotag != 0 && iotag <= phba->sli.last_iotag) { 2558 if (iotag != 0 && iotag <= phba->sli.last_iotag) {
2559 cmd_iocb = phba->sli.iocbq_lookup[iotag]; 2559 cmd_iocb = phba->sli.iocbq_lookup[iotag];
2560 list_del_init(&cmd_iocb->list); 2560 list_del_init(&cmd_iocb->list);
2561 if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { 2561 if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
2562 pring->txcmplq_cnt--; 2562 pring->txcmplq_cnt--;
2563 cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; 2563 cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
2564 } 2564 }
2565 return cmd_iocb; 2565 return cmd_iocb;
2566 } 2566 }
@@ -2593,14 +2593,14 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
2593 2593
2594 if (iotag != 0 && iotag <= phba->sli.last_iotag) { 2594 if (iotag != 0 && iotag <= phba->sli.last_iotag) {
2595 cmd_iocb = phba->sli.iocbq_lookup[iotag]; 2595 cmd_iocb = phba->sli.iocbq_lookup[iotag];
2596 list_del_init(&cmd_iocb->list); 2596 if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
2597 if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { 2597 /* remove from txcmpl queue list */
2598 cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; 2598 list_del_init(&cmd_iocb->list);
2599 cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
2599 pring->txcmplq_cnt--; 2600 pring->txcmplq_cnt--;
2601 return cmd_iocb;
2600 } 2602 }
2601 return cmd_iocb;
2602 } 2603 }
2603
2604 lpfc_printf_log(phba, KERN_ERR, LOG_SLI, 2604 lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
2605 "0372 iotag x%x is out off range: max iotag (x%x)\n", 2605 "0372 iotag x%x is out off range: max iotag (x%x)\n",
2606 iotag, phba->sli.last_iotag); 2606 iotag, phba->sli.last_iotag);
@@ -3468,6 +3468,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
3468 /* Retrieve everything on the txcmplq */ 3468 /* Retrieve everything on the txcmplq */
3469 list_splice_init(&pring->txcmplq, &txcmplq); 3469 list_splice_init(&pring->txcmplq, &txcmplq);
3470 pring->txcmplq_cnt = 0; 3470 pring->txcmplq_cnt = 0;
3471
3472 /* Indicate the I/O queues are flushed */
3473 phba->hba_flag |= HBA_FCP_IOQ_FLUSH;
3471 spin_unlock_irq(&phba->hbalock); 3474 spin_unlock_irq(&phba->hbalock);
3472 3475
3473 /* Flush the txq */ 3476 /* Flush the txq */
@@ -6069,6 +6072,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
6069 else 6072 else
6070 phba->hba_flag &= ~HBA_FIP_SUPPORT; 6073 phba->hba_flag &= ~HBA_FIP_SUPPORT;
6071 6074
6075 phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH;
6076
6072 if (phba->sli_rev != LPFC_SLI_REV4) { 6077 if (phba->sli_rev != LPFC_SLI_REV4) {
6073 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, 6078 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
6074 "0376 READ_REV Error. SLI Level %d " 6079 "0376 READ_REV Error. SLI Level %d "
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 3290b8e7ab65..2626f58c0747 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -68,7 +68,7 @@ struct lpfc_iocbq {
68#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ 68#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
69#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ 69#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
70#define DSS_SECURITY_OP 0x100 /* security IO */ 70#define DSS_SECURITY_OP 0x100 /* security IO */
71#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */ 71#define LPFC_IO_ON_TXCMPLQ 0x200 /* The IO is still on the TXCMPLQ */
72#define LPFC_IO_DIF 0x400 /* T10 DIF IO */ 72#define LPFC_IO_DIF 0x400 /* T10 DIF IO */
73 73
74#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ 74#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */