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 /drivers/scsi/lpfc/lpfc_scsi.c | |
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>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 48 |
1 files changed, 37 insertions, 11 deletions
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, |