Commit beb9e315 authored by Joe Lawrence's avatar Joe Lawrence Committed by Christoph Hellwig

qla2xxx: Prevent removal and board_disable race

Introduce mutual exclusion between the qla2xxx_remove_one PCI driver
callback and qla2x00_disable_board_on_pci_error, which is scheduled as
board_disable work by qla2x00_check_reg{32,16}_for_disconnect:

* Leave the driver-specific data attached to the underlying PCI device
intact in qla2x00_disable_board_on_pci_error, so that qla2x00_remove_one
has enough breadcrumbs to determine that any board_disable work has been
completed.

* In qla2xxx_remove_one, set a bit to prevent any subsequent
board_disable work from scheduling, then cancel and wait until pending
work has completed.

* Reuse the PCI device enable count check in qla2x00_remove_one to
determine if board_disable has occured. The original purpose of this
check was unnecessary since the driver remove function wasn't called
when the probe fails.
Signed-off-by: default avatarJoe Lawrence <joe.lawrence@stratus.com>
Acked-by: default avatarChad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 232792b6
...@@ -3404,6 +3404,7 @@ typedef struct scsi_qla_host { ...@@ -3404,6 +3404,7 @@ typedef struct scsi_qla_host {
unsigned long pci_flags; unsigned long pci_flags;
#define PFLG_DISCONNECTED 0 /* PCI device removed */ #define PFLG_DISCONNECTED 0 /* PCI device removed */
#define PFLG_DRIVER_REMOVING 1 /* PCI driver .remove */
uint32_t device_flags; uint32_t device_flags;
#define SWITCH_FOUND BIT_0 #define SWITCH_FOUND BIT_0
......
...@@ -117,7 +117,8 @@ qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg) ...@@ -117,7 +117,8 @@ qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
{ {
/* Check for PCI disconnection */ /* Check for PCI disconnection */
if (reg == 0xffffffff) { if (reg == 0xffffffff) {
if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags)) { if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
!test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags)) {
/* /*
* Schedule this (only once) on the default system * Schedule this (only once) on the default system
* workqueue so that all the adapter workqueues and the * workqueue so that all the adapter workqueues and the
......
...@@ -3131,15 +3131,25 @@ qla2x00_remove_one(struct pci_dev *pdev) ...@@ -3131,15 +3131,25 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_qla_host_t *base_vha; scsi_qla_host_t *base_vha;
struct qla_hw_data *ha; struct qla_hw_data *ha;
base_vha = pci_get_drvdata(pdev);
ha = base_vha->hw;
/* Indicate device removal to prevent future board_disable and wait
* until any pending board_disable has completed. */
set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags);
cancel_work_sync(&ha->board_disable);
/* /*
* If the PCI device is disabled that means that probe failed and any * If the PCI device is disabled then there was a PCI-disconnect and
* resources should be have cleaned up on probe exit. * qla2x00_disable_board_on_pci_error has taken care of most of the
* resources.
*/ */
if (!atomic_read(&pdev->enable_cnt)) if (!atomic_read(&pdev->enable_cnt)) {
scsi_host_put(base_vha->host);
kfree(ha);
pci_set_drvdata(pdev, NULL);
return; return;
}
base_vha = pci_get_drvdata(pdev);
ha = base_vha->hw;
qla2x00_wait_for_hba_ready(base_vha); qla2x00_wait_for_hba_ready(base_vha);
...@@ -4799,18 +4809,15 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) ...@@ -4799,18 +4809,15 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
qla82xx_md_free(base_vha); qla82xx_md_free(base_vha);
qla2x00_free_queues(ha); qla2x00_free_queues(ha);
scsi_host_put(base_vha->host);
qla2x00_unmap_iobases(ha); qla2x00_unmap_iobases(ha);
pci_release_selected_regions(ha->pdev, ha->bars); pci_release_selected_regions(ha->pdev, ha->bars);
kfree(ha);
ha = NULL;
pci_disable_pcie_error_reporting(pdev); pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
/*
* Let qla2x00_remove_one cleanup qla_hw_data on device removal.
*/
} }
/************************************************************************** /**************************************************************************
......
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