Skip to content

Commit

Permalink
qla2xxx: Check for device state before unloading the driver.
Browse files Browse the repository at this point in the history
During hot swap of PCI device, there can be PCI error on device,
during normal driver unload. The race between normal driver unload and
driver unload due to PCI error, can lead to system crash.Fix is to check
if there is unload going on and allow that function to unload the driver.

Signed-off-by: Sawan Chandak <sawan.chandak@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Sawan Chandak authored and Martin K. Petersen committed Jul 15, 2016
1 parent c6dc990 commit 783e0dc
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 13 deletions.
2 changes: 1 addition & 1 deletion drivers/scsi/qla2xxx/qla_dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* | Module Init and Probe | 0x018f | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e |
* | Mailbox commands | 0x1192 | |
* | Mailbox commands | 0x1191 | |
* | | | |
* | Device Discovery | 0x2003 | 0x2016 |
* | | | 0x2011-0x2012, |
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -3658,6 +3658,7 @@ typedef struct scsi_qla_host {
#define PFLG_DISCONNECTED 0 /* PCI device removed */
#define PFLG_DRIVER_REMOVING 1 /* PCI driver .remove */
#define PFLG_DRIVER_PROBING 2 /* PCI driver .probe */
#define PCI_ERR 30

uint32_t device_flags;
#define SWITCH_FOUND BIT_0
Expand Down
41 changes: 33 additions & 8 deletions drivers/scsi/qla2xxx/qla_mbx.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
return QLA_FUNCTION_TIMEOUT;
}

/* if PCI error, then avoid mbx processing.*/
if (test_bit(PCI_ERR, &base_vha->dpc_flags)) {
ql_log(ql_log_warn, vha, 0x1191,
"PCI error, exiting.\n");
return QLA_FUNCTION_TIMEOUT;
}

reg = ha->iobase;
io_lock_on = base_vha->flags.init_done;

Expand Down Expand Up @@ -266,6 +273,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)

uint16_t mb0;
uint32_t ictrl;
uint16_t w;

if (IS_FWI2_CAPABLE(ha)) {
mb0 = RD_REG_WORD(&reg->isp24.mailbox0);
Expand All @@ -279,15 +287,32 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
"mb[0]=0x%x\n", command, ictrl, jiffies, mb0);
ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019);

/*
* Attempt to capture a firmware dump for further analysis
* of the current firmware state. We do not need to do this
* if we are intentionally generating a dump.
*/
if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
ha->isp_ops->fw_dump(vha, 0);
/* Capture FW dump only, if PCI device active */
if (!pci_channel_offline(vha->hw->pdev)) {
pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
if (w == 0xffff || ictrl == 0xffffffff) {
/* This is special case if there is unload
* of driver happening and if PCI device go
* into bad state due to PCI error condition
* then only PCI ERR flag would be set.
* we will do premature exit for above case.
*/
if (test_bit(UNLOADING, &base_vha->dpc_flags))
set_bit(PCI_ERR, &base_vha->dpc_flags);
ha->flags.mbox_busy = 0;
rval = QLA_FUNCTION_TIMEOUT;
goto premature_exit;
}

rval = QLA_FUNCTION_TIMEOUT;
/* Attempt to capture firmware dump for further
* anallysis of the current formware state. we do not
* need to do this if we are intentionally generating
* a dump
*/
if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
ha->isp_ops->fw_dump(vha, 0);
rval = QLA_FUNCTION_TIMEOUT;
}
}

ha->flags.mbox_busy = 0;
Expand Down
21 changes: 17 additions & 4 deletions drivers/scsi/qla2xxx/qla_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -897,12 +897,16 @@ static void
qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);

while (((qla2x00_reset_active(vha)) || ha->dpc_active ||
ha->flags.mbox_busy) ||
test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
test_bit(FX00_TARGET_SCAN, &vha->dpc_flags))
test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) {
if (test_bit(UNLOADING, &base_vha->dpc_flags))
break;
msleep(1000);
}
}

int
Expand Down Expand Up @@ -2954,10 +2958,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha = NULL;

probe_out:
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
if (test_bit(UNLOADING, &base_vha->dpc_flags))
return -ENODEV;
return ret;
}

Expand Down Expand Up @@ -3138,6 +3139,12 @@ qla2x00_remove_one(struct pci_dev *pdev)

qla2x00_wait_for_hba_ready(base_vha);

/* if UNLOAD flag is already set, then continue unload,
* where it was set first.
*/
if (test_bit(UNLOADING, &base_vha->dpc_flags))
return;

set_bit(UNLOADING, &base_vha->dpc_flags);

if (IS_QLAFX00(ha))
Expand Down Expand Up @@ -4917,6 +4924,12 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
struct pci_dev *pdev = ha->pdev;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);

/* if UNLOAD flag is already set, then continue unload,
* where it was set first.
*/
if (test_bit(UNLOADING, &base_vha->dpc_flags))
return;

ql_log(ql_log_warn, base_vha, 0x015b,
"Disabling adapter.\n");

Expand Down

0 comments on commit 783e0dc

Please sign in to comment.