[SCSI] aic7xxx/aic79xx: fix module removal path not to panic
authorJames Bottomley <James.Bottomley@steeleye.com>
Sun, 2 Oct 2005 20:22:35 +0000 (15:22 -0500)
committerJames Bottomley <jejb@mulgrave.(none)>
Sun, 2 Oct 2005 20:32:25 +0000 (15:32 -0500)
In these drivers, scsi_remove_host() is called too late, at the point
it is called, the driver has already shut down too far to accept any
I/O that the shutdown might generate.  Any generated I/O actually
triggers a panic.

Fix this by calling scsi_remove_host() as early as possible and not
calling scsi_host_put() until just before we kfree the ahc_softc.

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/aic7xxx/aic7770_osm.c
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic79xx_osm_pci.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/aic7xxx/aic7xxx_osm_pci.c

index 70c5fb59c9ea4c07c4ec6fa04eacaeb6028907a4..d754b32678631dd9984ff273d3ee32f1ce6d2c5e 100644 (file)
@@ -112,6 +112,9 @@ aic7770_remove(struct device *dev)
        struct ahc_softc *ahc = dev_get_drvdata(dev);
        u_long s;
 
+       if (ahc->platform_data && ahc->platform_data->host)
+                       scsi_remove_host(ahc->platform_data->host);
+
        ahc_lock(ahc, &s);
        ahc_intr_enable(ahc, FALSE);
        ahc_unlock(ahc, &s);
index 6b6d4e287793acd5b3c044e7f80e7cf4ab7bba5f..95c285cc83e469a4e20c11b9593597b985c03574 100644 (file)
@@ -1192,11 +1192,6 @@ ahd_platform_free(struct ahd_softc *ahd)
        int i, j;
 
        if (ahd->platform_data != NULL) {
-               if (ahd->platform_data->host != NULL) {
-                       scsi_remove_host(ahd->platform_data->host);
-                       scsi_host_put(ahd->platform_data->host);
-               }
-
                /* destroy all of the device and target objects */
                for (i = 0; i < AHD_NUM_TARGETS; i++) {
                        starget = ahd->platform_data->starget[i];
@@ -1226,6 +1221,9 @@ ahd_platform_free(struct ahd_softc *ahd)
                        release_mem_region(ahd->platform_data->mem_busaddr,
                                           0x1000);
                }
+               if (ahd->platform_data->host)
+                       scsi_host_put(ahd->platform_data->host);
+
                free(ahd->platform_data, M_DEVBUF);
        }
 }
index 390b53852d4b9cfdfd6644d57f6f3881d7528502..bf360ae021abb0582482d4702e903a9eda4ac7f8 100644 (file)
@@ -95,6 +95,9 @@ ahd_linux_pci_dev_remove(struct pci_dev *pdev)
        struct ahd_softc *ahd = pci_get_drvdata(pdev);
        u_long s;
 
+       if (ahd->platform_data && ahd->platform_data->host)
+                       scsi_remove_host(ahd->platform_data->host);
+
        ahd_lock(ahd, &s);
        ahd_intr_enable(ahd, FALSE);
        ahd_unlock(ahd, &s);
index 876d1de8480d1388f0b740e40271ca9d21c2e2e2..6ee1435d37fac9efbce4d3a3ecd763c4ed2cfe5e 100644 (file)
@@ -1209,11 +1209,6 @@ ahc_platform_free(struct ahc_softc *ahc)
        int i, j;
 
        if (ahc->platform_data != NULL) {
-               if (ahc->platform_data->host != NULL) {
-                       scsi_remove_host(ahc->platform_data->host);
-                       scsi_host_put(ahc->platform_data->host);
-               }
-
                /* destroy all of the device and target objects */
                for (i = 0; i < AHC_NUM_TARGETS; i++) {
                        starget = ahc->platform_data->starget[i];
@@ -1242,6 +1237,9 @@ ahc_platform_free(struct ahc_softc *ahc)
                                           0x1000);
                }
 
+               if (ahc->platform_data->host)
+                       scsi_host_put(ahc->platform_data->host);
+
                free(ahc->platform_data, M_DEVBUF);
        }
 }
index 3ce77ddc889e8a6a2cefe4f54092bbaf218b65d5..cb30d9c1153d5394c08db57f6b64486bfcd1592a 100644 (file)
@@ -143,6 +143,9 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev)
        struct ahc_softc *ahc = pci_get_drvdata(pdev);
        u_long s;
 
+       if (ahc->platform_data && ahc->platform_data->host)
+                       scsi_remove_host(ahc->platform_data->host);
+
        ahc_lock(ahc, &s);
        ahc_intr_enable(ahc, FALSE);
        ahc_unlock(ahc, &s);