[SCSI] scsi_lib: fix recognition of cache type of Initio SBP-2 bridges
[safe/jmp/linux-2.6] / drivers / scsi / scsi_scan.c
index b86f170..94b86d5 100644 (file)
@@ -9,7 +9,7 @@
  * global variable (boot or module load time) settings.
  *
  * A specific LUN is scanned via an INQUIRY command; if the LUN has a
- * device attached, a Scsi_Device is allocated and setup for it.
+ * device attached, a scsi_device is allocated and setup for it.
  *
  * For every id of every channel on the given host:
  *
@@ -17,7 +17,7 @@
  *     device or storage attached to LUN 0):
  *
  *             If LUN 0 has a device attached, allocate and setup a
- *             Scsi_Device for it.
+ *             scsi_device for it.
  *
  *             If target is SCSI-3 or up, issue a REPORT LUN, and scan
  *             all of the LUNs returned by the REPORT LUN; else,
@@ -74,7 +74,7 @@
 #define SCSI_SCAN_TARGET_PRESENT       1
 #define SCSI_SCAN_LUN_PRESENT          2
 
-static char *scsi_null_device_strs = "nullnullnullnull";
+static const char *scsi_null_device_strs = "nullnullnullnull";
 
 #define MAX_SCSI_LUNS  512
 
@@ -205,12 +205,11 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        int display_failure_msg = 1, ret;
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
-       sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
+       sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
                       GFP_ATOMIC);
        if (!sdev)
                goto out;
 
-       memset(sdev, 0, sizeof(*sdev));
        sdev->vendor = scsi_null_device_strs;
        sdev->model = scsi_null_device_strs;
        sdev->rev = scsi_null_device_strs;
@@ -266,8 +265,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
                        /*
                         * if LLDD reports slave not present, don't clutter
                         * console with alloc failure messages
-
-
                         */
                        if (ret == -ENXIO)
                                display_failure_msg = 0;
@@ -279,7 +276,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
 
 out_device_destroy:
        transport_destroy_device(&sdev->sdev_gendev);
-       scsi_free_queue(sdev->request_queue);
        put_device(&sdev->sdev_gendev);
 out:
        if (display_failure_msg)
@@ -337,25 +333,11 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        struct scsi_target *starget;
        struct scsi_target *found_target;
 
-       /*
-        * Obtain the real parent from the transport. The transport
-        * is allowed to fail (no error) if there is nothing at that
-        * target id.
-        */
-       if (shost->transportt->target_parent) {
-               spin_lock_irqsave(shost->host_lock, flags);
-               parent = shost->transportt->target_parent(shost, channel, id);
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               if (!parent)
-                       return NULL;
-       }
-
-       starget = kmalloc(size, GFP_KERNEL);
+       starget = kzalloc(size, GFP_KERNEL);
        if (!starget) {
                printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
                return NULL;
        }
-       memset(starget, 0, size);
        dev = &starget->dev;
        device_initialize(dev);
        starget->reap_ref = 1;
@@ -403,30 +385,41 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        return found_target;
 }
 
-/**
- * scsi_target_reap - check to see if target is in use and destroy if not
- *
- * @starget: target to be checked
- *
- * This is used after removing a LUN or doing a last put of the target
- * it checks atomically that nothing is using the target and removes
- * it if so.
- */
-void scsi_target_reap(struct scsi_target *starget)
+static void scsi_target_reap_usercontext(void *data)
 {
+       struct scsi_target *starget = data;
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        unsigned long flags;
+
        spin_lock_irqsave(shost->host_lock, flags);
 
        if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
                list_del_init(&starget->siblings);
                spin_unlock_irqrestore(shost->host_lock, flags);
+               transport_remove_device(&starget->dev);
                device_del(&starget->dev);
-               transport_unregister_device(&starget->dev);
+               transport_destroy_device(&starget->dev);
                put_device(&starget->dev);
                return;
+
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
+
+       return;
+}
+
+/**
+ * scsi_target_reap - check to see if target is in use and destroy if not
+ *
+ * @starget: target to be checked
+ *
+ * This is used after removing a LUN or doing a last put of the target
+ * it checks atomically that nothing is using the target and removes
+ * it if so.
+ */
+void scsi_target_reap(struct scsi_target *starget)
+{
+       scsi_execute_in_process_context(scsi_target_reap_usercontext, starget);
 }
 
 /**
@@ -441,7 +434,7 @@ void scsi_target_reap(struct scsi_target *starget)
  *
  *     If the INQUIRY is successful, zero is returned and the
  *     INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
- *     are copied to the Scsi_Device any flags value is stored in *@bflags.
+ *     are copied to the scsi_device any flags value is stored in *@bflags.
  **/
 static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
                          int result_len, int *bflags)
@@ -462,10 +455,9 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
        pass = 1;
 
  next_pass:
-       SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY pass %d "
-                       "to host %d channel %d id %d lun %d, length %d\n",
-                       pass, sdev->host->host_no, sdev->channel,
-                       sdev->id, sdev->lun, try_inquiry_len));
+       SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev,
+                               "scsi scan: INQUIRY pass %d length %d\n",
+                               pass, try_inquiry_len));
 
        /* Each pass gets up to three chances to ignore Unit Attention */
        for (count = 0; count < 3; ++count) {
@@ -510,8 +502,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
                /*
                 * Get any flags for this device.
                 *
-                * XXX add a bflags to Scsi_Device, and replace the
-                * corresponding bit fields in Scsi_Device, so bflags
+                * XXX add a bflags to scsi_device, and replace the
+                * corresponding bit fields in scsi_device, so bflags
                 * need not be passed as an argument.
                 */
                *bflags = scsi_get_device_flags(sdev, &inq_result[8],
@@ -587,26 +579,27 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
        if (sdev->scsi_level >= 2 ||
            (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
                sdev->scsi_level++;
+       sdev->sdev_target->scsi_level = sdev->scsi_level;
 
        return 0;
 }
 
 /**
- * scsi_add_lun - allocate and fully initialze a Scsi_Device
- * @sdevscan:  holds information to be stored in the new Scsi_Device
- * @sdevnew:   store the address of the newly allocated Scsi_Device
+ * scsi_add_lun - allocate and fully initialze a scsi_device
+ * @sdevscan:  holds information to be stored in the new scsi_device
+ * @sdevnew:   store the address of the newly allocated scsi_device
  * @inq_result:        holds the result of a previous INQUIRY to the LUN
  * @bflags:    black/white list flag
  *
  * Description:
- *     Allocate and initialize a Scsi_Device matching sdevscan. Optionally
+ *     Allocate and initialize a scsi_device matching sdevscan. Optionally
  *     set fields based on values in *@bflags. If @sdevnew is not
- *     NULL, store the address of the new Scsi_Device in *@sdevnew (needed
+ *     NULL, store the address of the new scsi_device in *@sdevnew (needed
  *     when scanning a particular LUN).
  *
  * Return:
- *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
- *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
+ *     SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
  **/
 static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
 {
@@ -674,7 +667,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
         *
         * The above is vague, as it implies that we could treat 001 and
         * 011 the same. Stay compatible with previous code, and create a
-        * Scsi_Device for a PQ of 1
+        * scsi_device for a PQ of 1
         *
         * Don't set the device offline here; rather let the upper
         * level drivers eval the PQ to decide whether they should
@@ -694,12 +687,8 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
        if (inq_result[7] & 0x10)
                sdev->sdtr = 1;
 
-       sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d",
-                               sdev->host->host_no, sdev->channel,
-                               sdev->id, sdev->lun);
-
        /*
-        * End driverfs/devfs code.
+        * End sysfs code.
         */
 
        if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
@@ -771,12 +760,21 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
        return SCSI_SCAN_LUN_PRESENT;
 }
 
+static inline void scsi_destroy_sdev(struct scsi_device *sdev)
+{
+       if (sdev->host->hostt->slave_destroy)
+               sdev->host->hostt->slave_destroy(sdev);
+       transport_destroy_device(&sdev->sdev_gendev);
+       put_device(&sdev->sdev_gendev);
+}
+
+
 /**
  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
  * @starget:   pointer to target device structure
  * @lun:       LUN of target device
- * @sdevscan:  probe the LUN corresponding to this Scsi_Device
- * @sdevnew:   store the value of any new Scsi_Device allocated
+ * @sdevscan:  probe the LUN corresponding to this scsi_device
+ * @sdevnew:   store the value of any new scsi_device allocated
  * @bflagsp:   store bflags here if not NULL
  *
  * Description:
@@ -784,10 +782,10 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
  *     allocate and set it up by calling scsi_add_lun.
  *
  * Return:
- *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
  *     SCSI_SCAN_TARGET_PRESENT: target responded, but no device is
  *         attached at the LUN
- *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ *     SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
  **/
 static int scsi_probe_and_add_lun(struct scsi_target *starget,
                                  uint lun, int *bflagsp,
@@ -803,9 +801,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
         * The rescan flag is used as an optimization, the first scan of a
         * host adapter calls into here with rescan == 0.
         */
-       if (rescan) {
-               sdev = scsi_device_lookup_by_target(starget, lun);
-               if (sdev) {
+       sdev = scsi_device_lookup_by_target(starget, lun);
+       if (sdev) {
+               if (rescan || sdev->sdev_state != SDEV_CREATED) {
                        SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
                                "scsi scan: device exists on %s\n",
                                sdev->sdev_gendev.bus_id));
@@ -820,9 +818,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
                                                                 sdev->model);
                        return SCSI_SCAN_LUN_PRESENT;
                }
-       }
-
-       sdev = scsi_alloc_sdev(starget, lun, hostdata);
+               scsi_device_put(sdev);
+       } else
+               sdev = scsi_alloc_sdev(starget, lun, hostdata);
        if (!sdev)
                goto out;
 
@@ -855,6 +853,19 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
                goto out_free_result;
        }
 
+       /*
+        * Non-standard SCSI targets may set the PDT to 0x1f (unknown or
+        * no device type) instead of using the Peripheral Qualifier to
+        * indicate that no LUN is present.  For example, USB UFI does this.
+        */
+       if (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f) {
+               SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
+                                       "scsi scan: peripheral device type"
+                                       " of 31, no device added\n"));
+               res = SCSI_SCAN_TARGET_PRESENT;
+               goto out_free_result;
+       }
+
        res = scsi_add_lun(sdev, result, &bflags);
        if (res == SCSI_SCAN_LUN_PRESENT) {
                if (bflags & BLIST_KEY) {
@@ -877,12 +888,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
                                res = SCSI_SCAN_NO_RESPONSE;
                        }
                }
-       } else {
-               if (sdev->host->hostt->slave_destroy)
-                       sdev->host->hostt->slave_destroy(sdev);
-               transport_destroy_device(&sdev->sdev_gendev);
-               put_device(&sdev->sdev_gendev);
-       }
+       } else
+               scsi_destroy_sdev(sdev);
  out:
        return res;
 }
@@ -1041,7 +1048,7 @@ EXPORT_SYMBOL(int_to_scsilun);
 
 /**
  * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
- * @sdevscan:  scan the host, channel, and id of this Scsi_Device
+ * @sdevscan:  scan the host, channel, and id of this scsi_device
  *
  * Description:
  *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
@@ -1054,7 +1061,7 @@ EXPORT_SYMBOL(int_to_scsilun);
  *     0: scan completed (or no memory, so further scanning is futile)
  *     1: no report lun scan, or not configured
  **/
-static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
+static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
                                int rescan)
 {
        char devname[64];
@@ -1067,7 +1074,9 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
        struct scsi_lun *lunp, *lun_data;
        u8 *data;
        struct scsi_sense_hdr sshdr;
-       struct scsi_target *starget = scsi_target(sdev);
+       struct scsi_device *sdev;
+       struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+       int ret = 0;
 
        /*
         * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
@@ -1075,15 +1084,23 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
         * support more than 8 LUNs.
         */
        if ((bflags & BLIST_NOREPORTLUN) || 
-            sdev->scsi_level < SCSI_2 ||
-           (sdev->scsi_level < SCSI_3 && 
-            (!(bflags & BLIST_REPORTLUN2) || sdev->host->max_lun <= 8)) )
+            starget->scsi_level < SCSI_2 ||
+           (starget->scsi_level < SCSI_3 && 
+            (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) )
                return 1;
        if (bflags & BLIST_NOLUN)
                return 0;
 
+       if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
+               sdev = scsi_alloc_sdev(starget, 0, NULL);
+               if (!sdev)
+                       return 0;
+               if (scsi_device_get(sdev))
+                       return 0;
+       }
+
        sprintf(devname, "host %d channel %d id %d",
-               sdev->host->host_no, sdev->channel, sdev->id);
+               shost->host_no, sdev->channel, sdev->id);
 
        /*
         * Allocate enough to hold the header (the same size as one scsi_lun)
@@ -1098,8 +1115,10 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
        length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun);
        lun_data = kmalloc(length, GFP_ATOMIC |
                           (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
-       if (!lun_data)
+       if (!lun_data) {
+               printk(ALLOC_FAILURE_MSG, __FUNCTION__);
                goto out;
+       }
 
        scsi_cmd[0] = REPORT_LUNS;
 
@@ -1153,8 +1172,8 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
                /*
                 * The device probably does not support a REPORT LUN command
                 */
-               kfree(lun_data);
-               return 1;
+               ret = 1;
+               goto out_err;
        }
 
        /*
@@ -1173,9 +1192,8 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
                num_luns = max_scsi_report_luns;
        }
 
-       SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUN scan of"
-                       " host %d channel %d id %d\n", sdev->host->host_no,
-                       sdev->channel, sdev->id));
+       SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
+               "scsi scan: REPORT LUN scan\n"));
 
        /*
         * Scan the luns in lun_data. The entry at offset 0 is really
@@ -1201,10 +1219,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
                        for (i = 0; i < sizeof(struct scsi_lun); i++)
                                printk("%02x", data[i]);
                        printk(" has a LUN larger than currently supported.\n");
-               } else if (lun == 0) {
-                       /*
-                        * LUN 0 has already been scanned.
-                        */
                } else if (lun > sdev->host->max_lun) {
                        printk(KERN_WARNING "scsi: %s lun%d has a LUN larger"
                               " than allowed by the host adapter\n",
@@ -1218,45 +1232,43 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
                                /*
                                 * Got some results, but now none, abort.
                                 */
-                               printk(KERN_ERR "scsi: Unexpected response"
-                                      " from %s lun %d while scanning, scan"
-                                      " aborted\n", devname, lun);
+                               sdev_printk(KERN_ERR, sdev,
+                                       "Unexpected response"
+                                       " from lun %d while scanning, scan"
+                                       " aborted\n", lun);
                                break;
                        }
                }
        }
 
+ out_err:
        kfree(lun_data);
-       return 0;
-
  out:
-       /*
-        * We are out of memory, don't try scanning any further.
-        */
-       printk(ALLOC_FAILURE_MSG, __FUNCTION__);
-       return 0;
+       scsi_device_put(sdev);
+       if (sdev->sdev_state == SDEV_CREATED)
+               /*
+                * the sdev we used didn't appear in the report luns scan
+                */
+               scsi_destroy_sdev(sdev);
+       return ret;
 }
 
 struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
                                      uint id, uint lun, void *hostdata)
 {
-       struct scsi_device *sdev;
+       struct scsi_device *sdev = ERR_PTR(-ENODEV);
        struct device *parent = &shost->shost_gendev;
-       int res;
-       struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
+       struct scsi_target *starget;
 
+       starget = scsi_alloc_target(parent, channel, id);
        if (!starget)
                return ERR_PTR(-ENOMEM);
 
        get_device(&starget->dev);
-       down(&shost->scan_mutex);
-       if (scsi_host_scan_allowed(shost)) {
-               res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
-                                            hostdata);
-               if (res != SCSI_SCAN_LUN_PRESENT)
-                       sdev = ERR_PTR(-ENODEV);
-       }
-       up(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
+       if (scsi_host_scan_allowed(shost))
+               scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+       mutex_unlock(&shost->scan_mutex);
        scsi_target_reap(starget);
        put_device(&starget->dev);
 
@@ -1299,7 +1311,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
        struct Scsi_Host *shost = dev_to_shost(parent);
        int bflags = 0;
        int res;
-       struct scsi_device *sdev = NULL;
        struct scsi_target *starget;
 
        if (shost->this_id == id)
@@ -1325,27 +1336,16 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
         * Scan LUN 0, if there is some response, scan further. Ideally, we
         * would not configure LUN 0 until all LUNs are scanned.
         */
-       res = scsi_probe_and_add_lun(starget, 0, &bflags, &sdev, rescan, NULL);
-       if (res == SCSI_SCAN_LUN_PRESENT) {
-               if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
+       res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL);
+       if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) {
+               if (scsi_report_lun_scan(starget, bflags, rescan) != 0)
                        /*
                         * The REPORT LUN did not scan the target,
                         * do a sequential scan.
                         */
                        scsi_sequential_lun_scan(starget, bflags,
-                                       res, sdev->scsi_level, rescan);
-       } else if (res == SCSI_SCAN_TARGET_PRESENT) {
-               /*
-                * There's a target here, but lun 0 is offline so we
-                * can't use the report_lun scan.  Fall back to a
-                * sequential lun scan with a bflags of SPARSELUN and
-                * a default scsi level of SCSI_2
-                */
-               scsi_sequential_lun_scan(starget, BLIST_SPARSELUN,
-                               SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
+                                       res, starget->scsi_level, rescan);
        }
-       if (sdev)
-               scsi_device_put(sdev);
 
  out_reap:
        /* now determine if the target has any children at all
@@ -1376,10 +1376,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
 {
        struct Scsi_Host *shost = dev_to_shost(parent);
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost))
                __scsi_scan_target(parent, channel, id, lun, rescan);
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_scan_target);
 
@@ -1417,15 +1417,16 @@ static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
 int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
                            unsigned int id, unsigned int lun, int rescan)
 {
-       SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
-               __FUNCTION__, shost->host_no, channel, id, lun));
+       SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
+               "%s: <%u:%u:%u>\n",
+               __FUNCTION__, channel, id, lun));
 
        if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
            ((id != SCAN_WILD_CARD) && (id > shost->max_id)) ||
            ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
                return -EINVAL;
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost)) {
                if (channel == SCAN_WILD_CARD)
                        for (channel = 0; channel <= shost->max_channel;
@@ -1435,7 +1436,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
                else
                        scsi_scan_channel(shost, channel, id, lun, rescan);
        }
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
 
        return 0;
 }
@@ -1451,38 +1452,19 @@ void scsi_scan_host(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL(scsi_scan_host);
 
-/**
- * scsi_scan_single_target - scan the given SCSI target
- * @shost:         adapter to scan
- * @chan:          channel to scan
- * @id:            target id to scan
- **/
-void scsi_scan_single_target(struct Scsi_Host *shost, 
-       unsigned int chan, unsigned int id)
-{
-       scsi_scan_host_selected(shost, chan, id, SCAN_WILD_CARD, 1);
-}
-EXPORT_SYMBOL(scsi_scan_single_target);
-
 void scsi_forget_host(struct Scsi_Host *shost)
 {
-       struct scsi_target *starget, *tmp;
+       struct scsi_device *sdev;
        unsigned long flags;
 
-       /*
-        * Ok, this look a bit strange.  We always look for the first device
-        * on the list as scsi_remove_device removes them from it - thus we
-        * also have to release the lock.
-        * We don't need to get another reference to the device before
-        * releasing the lock as we already own the reference from
-        * scsi_register_device that's release in scsi_remove_device.  And
-        * after that we don't look at sdev anymore.
-        */
+ restart:
        spin_lock_irqsave(shost->host_lock, flags);
-       list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
+       list_for_each_entry(sdev, &shost->__devices, siblings) {
+               if (sdev->sdev_state == SDEV_DEL)
+                       continue;
                spin_unlock_irqrestore(shost->host_lock, flags);
-               scsi_remove_target(&starget->dev);
-               spin_lock_irqsave(shost->host_lock, flags);
+               __scsi_remove_device(sdev);
+               goto restart;
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
 }
@@ -1490,16 +1472,16 @@ void scsi_forget_host(struct Scsi_Host *shost)
 /*
  * Function:    scsi_get_host_dev()
  *
- * Purpose:     Create a Scsi_Device that points to the host adapter itself.
+ * Purpose:     Create a scsi_device that points to the host adapter itself.
  *
- * Arguments:   SHpnt   - Host that needs a Scsi_Device
+ * Arguments:   SHpnt   - Host that needs a scsi_device
  *
  * Lock status: None assumed.
  *
- * Returns:     The Scsi_Device or NULL
+ * Returns:     The scsi_device or NULL
  *
  * Notes:
- *     Attach a single Scsi_Device to the Scsi_Host - this should
+ *     Attach a single scsi_device to the Scsi_Host - this should
  *     be made to look like a "pseudo-device" that points to the
  *     HA itself.
  *
@@ -1512,7 +1494,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
        struct scsi_device *sdev = NULL;
        struct scsi_target *starget;
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (!scsi_host_scan_allowed(shost))
                goto out;
        starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
@@ -1526,7 +1508,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
        }
        put_device(&starget->dev);
  out:
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
        return sdev;
 }
 EXPORT_SYMBOL(scsi_get_host_dev);
@@ -1536,7 +1518,7 @@ EXPORT_SYMBOL(scsi_get_host_dev);
  *
  * Purpose:     Free a scsi_device that points to the host adapter itself.
  *
- * Arguments:   SHpnt   - Host that needs a Scsi_Device
+ * Arguments:   SHpnt   - Host that needs a scsi_device
  *
  * Lock status: None assumed.
  *
@@ -1548,10 +1530,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
 {
        BUG_ON(sdev->id != sdev->host->this_id);
 
-       if (sdev->host->hostt->slave_destroy)
-               sdev->host->hostt->slave_destroy(sdev);
-       transport_destroy_device(&sdev->sdev_gendev);
-       put_device(&sdev->sdev_gendev);
+       scsi_destroy_sdev(sdev);
 }
 EXPORT_SYMBOL(scsi_free_host_dev);