diff options
author | James Smart <james.smart@emulex.com> | 2012-05-09 21:17:07 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-05-17 05:57:29 -0400 |
commit | 4f2e66c6d225a14fcf77d826fe71f6137cb27352 (patch) | |
tree | b6235968d1a223d83e750d41aab8100f912a68ea | |
parent | a7dd9c0f44966b4328b52c5e32f8c3345e3482e5 (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.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 48 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 23 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 2 |
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 | |||
254 | lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, | 254 | lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, |
255 | struct lpfc_sli_ring *, uint32_t); | 255 | struct lpfc_sli_ring *, uint32_t); |
256 | 256 | ||
257 | struct lpfc_iocbq *__lpfc_sli_get_iocbq(struct lpfc_hba *); | ||
257 | struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); | 258 | struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); |
258 | void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); | 259 | void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); |
259 | uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); | 260 | uint16_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: | 4510 | out_unlock: |
4511 | spin_unlock_irq(&phba->hbalock); | ||
4512 | out: | ||
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 | **/ |
505 | static struct lpfc_iocbq * | 505 | struct 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 */ |