Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 783e0dc4 authored by Sawan Chandak's avatar Sawan Chandak Committed by Martin K. Petersen
Browse files

qla2xxx: Check for device state before unloading the driver.



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: default avatarSawan Chandak <sawan.chandak@qlogic.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@qlogic.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c6dc9905
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -14,7 +14,7 @@
 * | Module Init and Probe        |       0x018f       | 0x0146         |
 * | Module Init and Probe        |       0x018f       | 0x0146         |
 * |                              |                    | 0x015b-0x0160	|
 * |                              |                    | 0x015b-0x0160	|
 * |                              |                    | 0x016e		|
 * |                              |                    | 0x016e		|
 * | Mailbox commands             |       0x1192       |		|
 * | Mailbox commands             |       0x1191       | 		|
 * |                              |                    |		|
 * |                              |                    |		|
 * | Device Discovery             |       0x2003       | 0x2016		|
 * | Device Discovery             |       0x2003       | 0x2016		|
 * |                              |                    | 0x2011-0x2012, |
 * |                              |                    | 0x2011-0x2012, |
+1 −0
Original line number Original line Diff line number Diff line
@@ -3658,6 +3658,7 @@ typedef struct scsi_qla_host {
#define PFLG_DISCONNECTED	0	/* PCI device removed */
#define PFLG_DISCONNECTED	0	/* PCI device removed */
#define PFLG_DRIVER_REMOVING	1	/* PCI driver .remove */
#define PFLG_DRIVER_REMOVING	1	/* PCI driver .remove */
#define PFLG_DRIVER_PROBING	2	/* PCI driver .probe */
#define PFLG_DRIVER_PROBING	2	/* PCI driver .probe */
#define PCI_ERR			30


	uint32_t	device_flags;
	uint32_t	device_flags;
#define SWITCH_FOUND		BIT_0
#define SWITCH_FOUND		BIT_0
+33 −8
Original line number Original line Diff line number Diff line
@@ -64,6 +64,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
		return QLA_FUNCTION_TIMEOUT;
		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;
	reg = ha->iobase;
	io_lock_on = base_vha->flags.init_done;
	io_lock_on = base_vha->flags.init_done;


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


		uint16_t mb0;
		uint16_t mb0;
		uint32_t ictrl;
		uint32_t ictrl;
		uint16_t        w;


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


		/*
		/* Capture FW dump only, if PCI device active */
		 * Attempt to capture a firmware dump for further analysis
		if (!pci_channel_offline(vha->hw->pdev)) {
		 * of the current firmware state.  We do not need to do this
			pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
		 * if we are intentionally generating a dump.
			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;
			}

			/* 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)
			if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
				ha->isp_ops->fw_dump(vha, 0);
				ha->isp_ops->fw_dump(vha, 0);

			rval = QLA_FUNCTION_TIMEOUT;
			rval = QLA_FUNCTION_TIMEOUT;
		 }
		 }
	}


	ha->flags.mbox_busy = 0;
	ha->flags.mbox_busy = 0;


+17 −4
Original line number Original line Diff line number Diff line
@@ -897,13 +897,17 @@ static void
qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
{
{
	struct qla_hw_data *ha = vha->hw;
	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 ||
	while (((qla2x00_reset_active(vha)) || ha->dpc_active ||
	    ha->flags.mbox_busy) ||
	    ha->flags.mbox_busy) ||
		test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
		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);
		msleep(1000);
	}
	}
}


int
int
qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
@@ -2954,10 +2958,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
	ha = NULL;
	ha = NULL;


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


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


	qla2x00_wait_for_hba_ready(base_vha);
	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);
	set_bit(UNLOADING, &base_vha->dpc_flags);


	if (IS_QLAFX00(ha))
	if (IS_QLAFX00(ha))
@@ -4917,6 +4924,12 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
	struct pci_dev *pdev = ha->pdev;
	struct pci_dev *pdev = ha->pdev;
	scsi_qla_host_t *base_vha = pci_get_drvdata(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,
	ql_log(ql_log_warn, base_vha, 0x015b,
	    "Disabling adapter.\n");
	    "Disabling adapter.\n");