Commit 6175c02a authored by James.Smart@Emulex.Com's avatar James.Smart@Emulex.Com Committed by James Bottomley

[SCSI] lpfc 8.1.1 : Fixes to error handlers

- Release task management command before counting outstanding commands.
  TMF was being erroneously counted as an active outstanding command.
- Serialize EH calls and block requests when EH function is running.
Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 63c59c3b
...@@ -167,6 +167,7 @@ struct lpfc_hba { ...@@ -167,6 +167,7 @@ struct lpfc_hba {
dma_addr_t slim2p_mapping; dma_addr_t slim2p_mapping;
uint16_t pci_cfg_value; uint16_t pci_cfg_value;
struct semaphore hba_can_block;
uint32_t hba_state; uint32_t hba_state;
#define LPFC_INIT_START 1 /* Initial state after board reset */ #define LPFC_INIT_START 1 /* Initial state after board reset */
......
...@@ -1345,7 +1345,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -1345,7 +1345,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_put_host; goto out_put_host;
host->unique_id = phba->brd_no; host->unique_id = phba->brd_no;
init_MUTEX(&phba->hba_can_block);
INIT_LIST_HEAD(&phba->ctrspbuflist); INIT_LIST_HEAD(&phba->ctrspbuflist);
INIT_LIST_HEAD(&phba->rnidrspbuflist); INIT_LIST_HEAD(&phba->rnidrspbuflist);
INIT_LIST_HEAD(&phba->freebufList); INIT_LIST_HEAD(&phba->freebufList);
......
...@@ -41,6 +41,20 @@ ...@@ -41,6 +41,20 @@
#define LPFC_ABORT_WAIT 2 #define LPFC_ABORT_WAIT 2
static inline void
lpfc_block_requests(struct lpfc_hba * phba)
{
down(&phba->hba_can_block);
scsi_block_requests(phba->host);
}
static inline void
lpfc_unblock_requests(struct lpfc_hba * phba)
{
scsi_unblock_requests(phba->host);
up(&phba->hba_can_block);
}
/* /*
* This routine allocates a scsi buffer, which contains all the necessary * This routine allocates a scsi buffer, which contains all the necessary
* information needed to initiate a SCSI I/O. The non-DMAable buffer region * information needed to initiate a SCSI I/O. The non-DMAable buffer region
...@@ -774,6 +788,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ...@@ -774,6 +788,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
unsigned int loop_count = 0; unsigned int loop_count = 0;
int ret = SUCCESS; int ret = SUCCESS;
lpfc_block_requests(phba);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
...@@ -853,6 +868,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ...@@ -853,6 +868,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
cmnd->device->lun, cmnd->serial_number); cmnd->device->lun, cmnd->serial_number);
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_unblock_requests(phba);
return ret; return ret;
} }
...@@ -866,9 +882,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) ...@@ -866,9 +882,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
struct lpfc_iocbq *iocbq, *iocbqrsp; struct lpfc_iocbq *iocbq, *iocbqrsp;
struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *pnode = rdata->pnode; struct lpfc_nodelist *pnode = rdata->pnode;
uint32_t cmd_result = 0, cmd_status = 0;
int ret = FAILED; int ret = FAILED;
int cnt, loopcnt; int cnt, loopcnt;
lpfc_block_requests(phba);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
/* /*
* If target is not in a MAPPED state, delay the reset until * If target is not in a MAPPED state, delay the reset until
...@@ -912,26 +930,28 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) ...@@ -912,26 +930,28 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (ret == IOCB_SUCCESS) if (ret == IOCB_SUCCESS)
ret = SUCCESS; ret = SUCCESS;
lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
lpfc_cmd->status = iocbqrsp->iocb.ulpStatus; cmd_result = iocbqrsp->iocb.un.ulpWord[4];
if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT) cmd_status = iocbqrsp->iocb.ulpStatus;
if (lpfc_cmd->result & IOERR_DRVR_MASK)
lpfc_cmd->status = IOSTAT_DRIVER_REJECT; lpfc_sli_release_iocbq(phba, iocbqrsp);
lpfc_release_scsi_buf(phba, lpfc_cmd);
/* /*
* All outstanding txcmplq I/Os should have been aborted by the target. * All outstanding txcmplq I/Os should have been aborted by the device.
* Unfortunately, some targets do not abide by this forcing the driver * Unfortunately, some targets do not abide by this forcing the driver
* to double check. * to double check.
*/ */
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
cmnd->device->id, cmnd->device->lun, 0, cmnd->device->id, cmnd->device->lun,
LPFC_CTX_LUN); LPFC_CTX_LUN);
if (cnt)
lpfc_sli_abort_iocb(phba,
&phba->sli.ring[phba->sli.fcp_ring],
cmnd->device->id, cmnd->device->lun,
0, LPFC_CTX_LUN);
loopcnt = 0; loopcnt = 0;
while((cnt = lpfc_sli_sum_iocb(phba, while(cnt) {
&phba->sli.ring[phba->sli.fcp_ring],
cmnd->device->id, cmnd->device->lun,
LPFC_CTX_LUN))) {
spin_unlock_irq(phba->host->host_lock); spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
spin_lock_irq(phba->host->host_lock); spin_lock_irq(phba->host->host_lock);
...@@ -939,6 +959,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) ...@@ -939,6 +959,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (++loopcnt if (++loopcnt
> (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT) > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
break; break;
cnt = lpfc_sli_sum_iocb(phba,
&phba->sli.ring[phba->sli.fcp_ring],
cmnd->device->id, cmnd->device->lun,
LPFC_CTX_LUN);
} }
if (cnt) { if (cnt) {
...@@ -948,18 +973,16 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) ...@@ -948,18 +973,16 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
ret = FAILED; ret = FAILED;
} }
lpfc_sli_release_iocbq(phba, iocbqrsp);
out_free_scsi_buf: out_free_scsi_buf:
lpfc_printf_log(phba, KERN_ERR, LOG_FCP, lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 SCSI layer issued LUN reset (%d, %d) " "%d:0713 SCSI layer issued LUN reset (%d, %d) "
"Data: x%x x%x x%x\n", "Data: x%x x%x x%x\n",
phba->brd_no, lpfc_cmd->pCmd->device->id, phba->brd_no, cmnd->device->id,cmnd->device->lun,
lpfc_cmd->pCmd->device->lun, ret, lpfc_cmd->status, ret, cmd_status, cmd_result);
lpfc_cmd->result);
lpfc_release_scsi_buf(phba, lpfc_cmd);
out: out:
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_unblock_requests(phba);
return ret; return ret;
} }
...@@ -975,6 +998,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) ...@@ -975,6 +998,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
unsigned int midlayer_id = 0; unsigned int midlayer_id = 0;
struct lpfc_scsi_buf * lpfc_cmd; struct lpfc_scsi_buf * lpfc_cmd;
lpfc_block_requests(phba);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_sli_get_scsi_buf (phba); lpfc_cmd = lpfc_sli_get_scsi_buf (phba);
...@@ -1008,18 +1032,31 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) ...@@ -1008,18 +1032,31 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data; lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data;
ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba); ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba);
if (ret != SUCCESS) { if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_INFO, LOG_FCP, lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 Bus Reset on target %d failed\n", "%d:0713 Bus Reset on target %d failed\n",
phba->brd_no, i); phba->brd_no, i);
err_count++; err_count++;
} }
} }
if (err_count == 0)
ret = SUCCESS;
lpfc_release_scsi_buf(phba, lpfc_cmd);
/*
* All outstanding txcmplq I/Os should have been aborted by
* the targets. Unfortunately, some targets do not abide by
* this forcing the driver to double check.
*/
cmnd->device->id = midlayer_id; cmnd->device->id = midlayer_id;
cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
0, 0, LPFC_CTX_HOST);
if (cnt)
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
0, 0, 0, LPFC_CTX_HOST);
loopcnt = 0; loopcnt = 0;
while((cnt = lpfc_sli_sum_iocb(phba, while(cnt) {
&phba->sli.ring[phba->sli.fcp_ring],
0, 0, LPFC_CTX_HOST))) {
spin_unlock_irq(phba->host->host_lock); spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
spin_lock_irq(phba->host->host_lock); spin_lock_irq(phba->host->host_lock);
...@@ -1027,25 +1064,19 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) ...@@ -1027,25 +1064,19 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
if (++loopcnt if (++loopcnt
> (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT) > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
break; break;
cnt = lpfc_sli_sum_iocb(phba,
&phba->sli.ring[phba->sli.fcp_ring],
0, 0, LPFC_CTX_HOST);
} }
if (cnt) { if (cnt) {
/* flush all outstanding commands on the host */ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
i = lpfc_sli_abort_iocb(phba,
&phba->sli.ring[phba->sli.fcp_ring], 0, 0, 0,
LPFC_CTX_HOST);
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
"%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n", "%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n",
phba->brd_no, cnt, i); phba->brd_no, cnt, i);
}
if (cnt == 0)
ret = SUCCESS;
else
ret = FAILED; ret = FAILED;
}
lpfc_release_scsi_buf(phba, lpfc_cmd);
lpfc_printf_log(phba, lpfc_printf_log(phba,
KERN_ERR, KERN_ERR,
LOG_FCP, LOG_FCP,
...@@ -1053,6 +1084,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) ...@@ -1053,6 +1084,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
phba->brd_no, ret); phba->brd_no, ret);
out: out:
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_unblock_requests(phba);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment