regulator: Fix check of unsigned return value and transmit errors in wm831x_gp_ldo_ge...
[safe/jmp/linux-2.6] / drivers / scsi / scsi_scan.c
index 14e635a..0547a7f 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/spinlock.h>
+#include <linux/async.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -54,7 +55,7 @@
 #define SCSI_TIMEOUT (2*HZ)
 
 /*
- * Prefix values for the SCSI id's (stored in driverfs name field)
+ * Prefix values for the SCSI id's (stored in sysfs name field)
  */
 #define SCSI_UID_SER_NUM 'S'
 #define SCSI_UID_UNKNOWN 'Z'
@@ -85,7 +86,7 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
 static unsigned int max_scsi_luns = 1;
 #endif
 
-module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(max_luns,
                 "last scsi LUN (should be between 1 and 2^32-1)");
 
@@ -109,18 +110,19 @@ MODULE_PARM_DESC(scan, "sync, async or none");
  */
 static unsigned int max_scsi_report_luns = 511;
 
-module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(max_report_luns,
                 "REPORT LUNS maximum number of LUNS received (should be"
                 " between 1 and 16384)");
 
-static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
+static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18;
 
-module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR);
+module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(inq_timeout, 
                 "Timeout (in seconds) waiting for devices to answer INQUIRY."
-                " Default is 5. Some non-compliant devices need more.");
+                " Default is 20. Some devices may need more; most need less.");
 
+/* This lock protects only this list */
 static DEFINE_SPINLOCK(async_scan_lock);
 static LIST_HEAD(scanning_hosts);
 
@@ -133,12 +135,10 @@ struct async_scan_data {
 /**
  * scsi_complete_async_scans - Wait for asynchronous scans to complete
  *
- * Asynchronous scans add themselves to the scanning_hosts list.  Once
- * that list is empty, we know that the scans are complete.  Rather than
- * waking up periodically to check the state of the list, we pretend to be
- * a scanning task by adding ourselves at the end of the list and going to
- * sleep.  When the task before us wakes us up, we take ourselves off the
- * list and return.
+ * When this function returns, any host which started scanning before
+ * this function was called will have finished its scan.  Hosts which
+ * started scanning after this function was called may or may not have
+ * finished.
  */
 int scsi_complete_async_scans(void)
 {
@@ -171,6 +171,11 @@ int scsi_complete_async_scans(void)
 
        spin_lock(&async_scan_lock);
        list_del(&data->list);
+       if (!list_empty(&scanning_hosts)) {
+               struct async_scan_data *next = list_entry(scanning_hosts.next,
+                               struct async_scan_data, list);
+               complete(&next->prev_finished);
+       }
  done:
        spin_unlock(&async_scan_lock);
 
@@ -178,9 +183,16 @@ int scsi_complete_async_scans(void)
        return 0;
 }
 
-#ifdef MODULE
 /* Only exported for the benefit of scsi_wait_scan */
 EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
+
+#ifndef MODULE
+/*
+ * For async scanning we need to wait for all the scans to complete before
+ * trying to mount the root fs.  Otherwise non-modular drivers may not be ready
+ * yet.
+ */
+late_initcall(scsi_complete_async_scans);
 #endif
 
 /**
@@ -205,11 +217,14 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
        scsi_cmd[4] = 0x2a;     /* size */
        scsi_cmd[5] = 0;
        scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,
-                        SCSI_TIMEOUT, 3);
+                        SCSI_TIMEOUT, 3, NULL);
 }
 
 /**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
+ * @starget: which target to allocate a &scsi_device for
+ * @lun: which lun
+ * @hostdata: usually NULL and set by ->slave_alloc instead
  *
  * Description:
  *     Allocate, initialize for io, and return a pointer to a scsi_Device.
@@ -225,6 +240,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        struct scsi_device *sdev;
        int display_failure_msg = 1, ret;
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+       extern void scsi_evt_thread(struct work_struct *work);
 
        sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
                       GFP_ATOMIC);
@@ -243,7 +259,9 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        INIT_LIST_HEAD(&sdev->same_target_siblings);
        INIT_LIST_HEAD(&sdev->cmd_list);
        INIT_LIST_HEAD(&sdev->starved_entry);
+       INIT_LIST_HEAD(&sdev->event_list);
        spin_lock_init(&sdev->list_lock);
+       INIT_WORK(&sdev->event_work, scsi_evt_thread);
 
        sdev->sdev_gendev.parent = get_device(&starget->dev);
        sdev->sdev_target = starget;
@@ -297,14 +315,31 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        return sdev;
 
 out_device_destroy:
+       scsi_device_set_state(sdev, SDEV_DEL);
        transport_destroy_device(&sdev->sdev_gendev);
+       put_device(&sdev->sdev_dev);
        put_device(&sdev->sdev_gendev);
 out:
        if (display_failure_msg)
-               printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+               printk(ALLOC_FAILURE_MSG, __func__);
        return NULL;
 }
 
+static void scsi_target_destroy(struct scsi_target *starget)
+{
+       struct device *dev = &starget->dev;
+       struct Scsi_Host *shost = dev_to_shost(dev->parent);
+       unsigned long flags;
+
+       transport_destroy_device(dev);
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (shost->hostt->target_destroy)
+               shost->hostt->target_destroy(starget);
+       list_del_init(&starget->siblings);
+       spin_unlock_irqrestore(shost->host_lock, flags);
+       put_device(dev);
+}
+
 static void scsi_target_dev_release(struct device *dev)
 {
        struct device *parent = dev->parent;
@@ -314,9 +349,14 @@ static void scsi_target_dev_release(struct device *dev)
        put_device(parent);
 }
 
+static struct device_type scsi_target_type = {
+       .name =         "scsi_target",
+       .release =      scsi_target_dev_release,
+};
+
 int scsi_is_target_device(const struct device *dev)
 {
-       return dev->release == scsi_target_dev_release;
+       return dev->type == &scsi_target_type;
 }
 EXPORT_SYMBOL(scsi_is_target_device);
 
@@ -367,21 +407,26 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
 
        starget = kzalloc(size, GFP_KERNEL);
        if (!starget) {
-               printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+               printk(KERN_ERR "%s: allocation failure\n", __func__);
                return NULL;
        }
        dev = &starget->dev;
        device_initialize(dev);
        starget->reap_ref = 1;
        dev->parent = get_device(parent);
-       dev->release = scsi_target_dev_release;
-       sprintf(dev->bus_id, "target%d:%d:%d",
-               shost->host_no, channel, id);
+       dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id);
+#ifndef CONFIG_SYSFS_DEPRECATED
+       dev->bus = &scsi_bus_type;
+#endif
+       dev->type = &scsi_target_type;
        starget->id = id;
        starget->channel = channel;
+       starget->can_queue = 0;
        INIT_LIST_HEAD(&starget->siblings);
        INIT_LIST_HEAD(&starget->devices);
-       starget->state = STARGET_RUNNING;
+       starget->state = STARGET_CREATED;
+       starget->scsi_level = SCSI_2;
+       starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED;
  retry:
        spin_lock_irqsave(shost->host_lock, flags);
 
@@ -393,18 +438,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        spin_unlock_irqrestore(shost->host_lock, flags);
        /* allocate and add */
        transport_setup_device(dev);
-       error = device_add(dev);
-       if (error) {
-               dev_err(dev, "target device_add failed, error %d\n", error);
-               spin_lock_irqsave(shost->host_lock, flags);
-               list_del_init(&starget->siblings);
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               transport_destroy_device(dev);
-               put_device(parent);
-               kfree(starget);
-               return NULL;
-       }
-       transport_add_device(dev);
        if (shost->hostt->target_alloc) {
                error = shost->hostt->target_alloc(starget);
 
@@ -412,9 +445,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
                        dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);
                        /* don't want scsi_target_reap to do the final
                         * put because it will be under the host lock */
-                       get_device(dev);
-                       scsi_target_reap(starget);
-                       put_device(dev);
+                       scsi_target_destroy(starget);
                        return NULL;
                }
        }
@@ -441,23 +472,14 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
 {
        struct scsi_target *starget =
                container_of(work, struct scsi_target, ew.work);
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       unsigned long flags;
 
        transport_remove_device(&starget->dev);
        device_del(&starget->dev);
-       transport_destroy_device(&starget->dev);
-       spin_lock_irqsave(shost->host_lock, flags);
-       if (shost->hostt->target_destroy)
-               shost->hostt->target_destroy(starget);
-       list_del_init(&starget->siblings);
-       spin_unlock_irqrestore(shost->host_lock, flags);
-       put_device(&starget->dev);
+       scsi_target_destroy(starget);
 }
 
 /**
  * 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
@@ -468,21 +490,25 @@ void scsi_target_reap(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        unsigned long flags;
+       enum scsi_target_state state;
+       int empty;
 
        spin_lock_irqsave(shost->host_lock, flags);
+       state = starget->state;
+       empty = --starget->reap_ref == 0 &&
+               list_empty(&starget->devices) ? 1 : 0;
+       spin_unlock_irqrestore(shost->host_lock, flags);
 
-       if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
-               BUG_ON(starget->state == STARGET_DEL);
-               starget->state = STARGET_DEL;
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               execute_in_process_context(scsi_target_reap_usercontext,
-                                          &starget->ew);
+       if (!empty)
                return;
 
-       }
-       spin_unlock_irqrestore(shost->host_lock, flags);
-
-       return;
+       BUG_ON(state == STARGET_DEL);
+       starget->state = STARGET_DEL;
+       if (state == STARGET_CREATED)
+               scsi_target_destroy(starget);
+       else
+               execute_in_process_context(scsi_target_reap_usercontext,
+                                          &starget->ew);
 }
 
 /**
@@ -550,6 +576,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
 
        /* Each pass gets up to three chances to ignore Unit Attention */
        for (count = 0; count < 3; ++count) {
+               int resid;
+
                memset(scsi_cmd, 0, 6);
                scsi_cmd[0] = INQUIRY;
                scsi_cmd[4] = (unsigned char) try_inquiry_len;
@@ -558,7 +586,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
 
                result = scsi_execute_req(sdev,  scsi_cmd, DMA_FROM_DEVICE,
                                          inq_result, try_inquiry_len, &sshdr,
-                                         HZ / 2 + HZ * scsi_inq_timeout, 3);
+                                         HZ / 2 + HZ * scsi_inq_timeout, 3,
+                                         &resid);
 
                SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s "
                                "with code 0x%x\n",
@@ -579,6 +608,14 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
                                    (sshdr.ascq == 0))
                                        continue;
                        }
+               } else {
+                       /*
+                        * if nothing was transferred, we try
+                        * again. It's a workaround for some USB
+                        * devices.
+                        */
+                       if (resid == try_inquiry_len)
+                               continue;
                }
                break;
        }
@@ -651,6 +688,19 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
         * short INQUIRY), an abort here prevents any further use of the
         * device, including spin up.
         *
+        * On the whole, the best approach seems to be to assume the first
+        * 36 bytes are valid no matter what the device says.  That's
+        * better than copying < 36 bytes to the inquiry-result buffer
+        * and displaying garbage for the Vendor, Product, or Revision
+        * strings.
+        */
+       if (sdev->inquiry_len < 36) {
+               printk(KERN_INFO "scsi scan: INQUIRY result too short (%d),"
+                               " using 36\n", sdev->inquiry_len);
+               sdev->inquiry_len = 36;
+       }
+
+       /*
         * Related to the above issue:
         *
         * XXX Devices (disk or all?) should be sent a TEST UNIT READY,
@@ -679,16 +729,14 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
 
 /**
  * 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
+ * @sdev:      holds information to be stored in the new scsi_device
  * @inq_result:        holds the result of a previous INQUIRY to the LUN
  * @bflags:    black/white list flag
+ * @async:     1 if this device is being scanned asynchronously
  *
  * Description:
- *     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
- *     when scanning a particular LUN).
+ *     Initialize the scsi_device @sdev.  Optionally set fields based
+ *     on values in *@bflags.
  *
  * Return:
  *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
@@ -697,6 +745,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
 static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                int *bflags, int async)
 {
+       int ret;
+
        /*
         * XXX do not save the inquiry, since it can change underneath us,
         * save just vendor/model/rev.
@@ -728,17 +778,15 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        sdev->rev = (char *) (sdev->inquiry + 32);
 
        if (*bflags & BLIST_ISROM) {
-               /*
-                * It would be better to modify sdev->type, and set
-                * sdev->removable; this can now be done since
-                * print_inquiry has gone away.
-                */
-               inq_result[0] = TYPE_ROM;
-               inq_result[1] |= 0x80;  /* removable */
-       } else if (*bflags & BLIST_NO_ULD_ATTACH)
-               sdev->no_uld_attach = 1;
+               sdev->type = TYPE_ROM;
+               sdev->removable = 1;
+       } else {
+               sdev->type = (inq_result[0] & 0x1f);
+               sdev->removable = (inq_result[1] & 0x80) >> 7;
+       }
 
-       switch (sdev->type = (inq_result[0] & 0x1f)) {
+       switch (sdev->type) {
+       case TYPE_RBC:
        case TYPE_TAPE:
        case TYPE_DISK:
        case TYPE_PRINTER:
@@ -749,17 +797,26 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        case TYPE_ENCLOSURE:
        case TYPE_COMM:
        case TYPE_RAID:
-       case TYPE_RBC:
+       case TYPE_OSD:
                sdev->writeable = 1;
                break;
-       case TYPE_WORM:
        case TYPE_ROM:
+       case TYPE_WORM:
                sdev->writeable = 0;
                break;
        default:
                printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
        }
 
+       if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) {
+               /* RBC and MMC devices can return SCSI-3 compliance and yet
+                * still not support REPORT LUNS, so make them act as
+                * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
+                * specifically set */
+               if ((*bflags & BLIST_REPORTLUN2) == 0)
+                       *bflags |= BLIST_NOREPORTLUN;
+       }
+
        /*
         * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
         * spec says: The device server is capable of supporting the
@@ -777,12 +834,11 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
         */ 
 
        sdev->inq_periph_qual = (inq_result[0] >> 5) & 7;
-       sdev->removable = (0x80 & inq_result[1]) >> 7;
        sdev->lockable = sdev->removable;
        sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
 
-       if (sdev->scsi_level >= SCSI_3 || (sdev->inquiry_len > 56 &&
-               inq_result[56] & 0x04))
+       if (sdev->scsi_level >= SCSI_3 ||
+                       (sdev->inquiry_len > 56 && inq_result[56] & 0x04))
                sdev->ppr = 1;
        if (inq_result[7] & 0x60)
                sdev->wdtr = 1;
@@ -795,13 +851,10 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                        sdev->inq_periph_qual, inq_result[2] & 0x07,
                        (inq_result[3] & 0x0f) == 1 ? " CCS" : "");
 
-       /*
-        * End sysfs code.
-        */
-
        if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
            !(*bflags & BLIST_NOTQ))
                sdev->tagged_supported = 1;
+
        /*
         * Some devices (Texel CD ROM drives) have handshaking problems
         * when used with the Seagate controllers. borken is initialized
@@ -810,6 +863,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        if ((*bflags & BLIST_BORKEN) == 0)
                sdev->borken = 0;
 
+       if (*bflags & BLIST_NO_ULD_ATTACH)
+               sdev->no_uld_attach = 1;
+
        /*
         * Apparently some really broken devices (contrary to the SCSI
         * standards) need to be selected without asserting ATN
@@ -832,8 +888,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                sdev->no_start_on_add = 1;
 
        if (*bflags & BLIST_SINGLELUN)
-               sdev->single_lun = 1;
-
+               scsi_target(sdev)->single_lun = 1;
 
        sdev->use_10_for_rw = 1;
 
@@ -848,7 +903,17 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
 
        /* set the device running here so that slave configure
         * may do I/O */
-       scsi_device_set_state(sdev, SDEV_RUNNING);
+       ret = scsi_device_set_state(sdev, SDEV_RUNNING);
+       if (ret) {
+               ret = scsi_device_set_state(sdev, SDEV_BLOCK);
+
+               if (ret) {
+                       sdev_printk(KERN_ERR, sdev,
+                                   "in wrong state %s to complete scan\n",
+                                   scsi_device_state_name(sdev->sdev_state));
+                       return SCSI_SCAN_NO_RESPONSE;
+               }
+       }
 
        if (*bflags & BLIST_MS_192_BYTES_FOR_3F)
                sdev->use_192_bytes_for_3f = 1;
@@ -862,7 +927,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        transport_configure_device(&sdev->sdev_gendev);
 
        if (sdev->host->hostt->slave_configure) {
-               int ret = sdev->host->hostt->slave_configure(sdev);
+               ret = sdev->host->hostt->slave_configure(sdev);
                if (ret) {
                        /*
                         * if LLDD reports slave not present, don't clutter
@@ -893,13 +958,13 @@ 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_dev);
        put_device(&sdev->sdev_gendev);
 }
 
 #ifdef CONFIG_SCSI_LOGGING
 /** 
- * scsi_inq_str - print INQUIRY data from min to max index,
- * strip trailing whitespace
+ * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
  * @buf:   Output buffer with at least end-first+1 bytes of space
  * @inq:   Inquiry buffer (input)
  * @first: Offset of string into inq
@@ -927,9 +992,10 @@ static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq,
  * 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
  * @bflagsp:   store bflags here if not NULL
+ * @sdevp:     probe the LUN corresponding to this scsi_device
+ * @rescan:     if nonzero skip some code only needed on first scan
+ * @hostdata:  passed to scsi_alloc_sdev()
  *
  * Description:
  *     Call scsi_probe_lun, if a LUN with an attached device is found,
@@ -957,10 +1023,10 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
         */
        sdev = scsi_device_lookup_by_target(starget, lun);
        if (sdev) {
-               if (rescan || sdev->sdev_state != SDEV_CREATED) {
+               if (rescan || !scsi_device_created(sdev)) {
                        SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
                                "scsi scan: device exists on %s\n",
-                               sdev->sdev_gendev.bus_id));
+                               dev_name(&sdev->sdev_gendev)));
                        if (sdevp)
                                *sdevp = sdev;
                        else
@@ -1012,12 +1078,13 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
 
                                sdev_printk(KERN_INFO, sdev,
                                        "scsi scan: consider passing scsi_mod."
-                                       "dev_flags=%s:%s:0x240 or 0x800240\n",
+                                       "dev_flags=%s:%s:0x240 or 0x1000240\n",
                                        scsi_inq_str(vend, result, 8, 16),
                                        scsi_inq_str(mod, result, 16, 32));
                        });
+
                }
-               
+
                res = SCSI_SCAN_TARGET_PRESENT;
                goto out_free_result;
        }
@@ -1042,7 +1109,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
         * PDT=1Fh none (no FDD connected to the requested logical unit)
         */
        if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
-            (result[0] & 0x1f) == 0x1f) {
+           (result[0] & 0x1f) == 0x1f &&
+           !scsi_is_wlun(lun)) {
                SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
                                        "scsi scan: peripheral device type"
                                        " of 31, no device added\n"));
@@ -1080,6 +1148,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
  * scsi_sequential_lun_scan - sequentially scan a SCSI target
  * @starget:   pointer to target structure to scan
  * @bflags:    black/white list flag for LUN 0
+ * @scsi_level: Which version of the standard does this device adhere to
+ * @rescan:     passed to scsi_probe_add_lun()
  *
  * Description:
  *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
@@ -1095,7 +1165,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
        SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of"
-                                   "%s\n", starget->dev.bus_id));
+                                   "%s\n", dev_name(&starget->dev)));
 
        max_dev_lun = min(max_scsi_luns, shost->max_lun);
        /*
@@ -1175,7 +1245,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
  *     Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns
  *     the integer: 0x0b030a04
  **/
-static int scsilun_to_int(struct scsi_lun *scsilun)
+int scsilun_to_int(struct scsi_lun *scsilun)
 {
        int i;
        unsigned int lun;
@@ -1186,10 +1256,11 @@ static int scsilun_to_int(struct scsi_lun *scsilun)
                              scsilun->scsi_lun[i + 1]) << (i * 8));
        return lun;
 }
+EXPORT_SYMBOL(scsilun_to_int);
 
 /**
  * int_to_scsilun: reverts an int into a scsi_lun
- * @int:        integer to be reverted
+ * @lun:        integer to be reverted
  * @scsilun:   struct scsi_lun to be set.
  *
  * Description:
@@ -1221,18 +1292,22 @@ 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
+ * @starget: which target
+ * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN
+ * @rescan: nonzero if we can skip code only needed on first scan
  *
  * Description:
- *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
- *     command, and scan the resulting list of LUNs by calling
- *     scsi_probe_and_add_lun.
+ *   Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command.
+ *   Scan the resulting list of LUNs by calling scsi_probe_and_add_lun.
  *
- *     Modifies sdevscan->lun.
+ *   If BLINK_REPORTLUN2 is set, scan a target that supports more than 8
+ *   LUNs even if it's older than SCSI-3.
+ *   If BLIST_NOREPORTLUN is set, return 1 always.
+ *   If BLIST_NOLUN is set, return 0 always.
  *
  * Return:
  *     0: scan completed (or no memory, so further scanning is futile)
- *     1: no report lun scan, or not configured
+ *     1: could not scan with REPORT LUN
  **/
 static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
                                int rescan)
@@ -1292,7 +1367,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
        lun_data = kmalloc(length, GFP_ATOMIC |
                           (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
        if (!lun_data) {
-               printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+               printk(ALLOC_FAILURE_MSG, __func__);
                goto out;
        }
 
@@ -1331,7 +1406,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
 
                result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
                                          lun_data, length, &sshdr,
-                                         SCSI_TIMEOUT + 4 * HZ, 3);
+                                         SCSI_TIMEOUT + 4 * HZ, 3, NULL);
 
                SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS"
                                " %s (try %d) result 0x%x\n", result
@@ -1421,7 +1496,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
        kfree(lun_data);
  out:
        scsi_device_put(sdev);
-       if (sdev->sdev_state == SDEV_CREATED)
+       if (scsi_device_created(sdev))
                /*
                 * the sdev we used didn't appear in the report luns scan
                 */
@@ -1436,11 +1511,17 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
        struct device *parent = &shost->shost_gendev;
        struct scsi_target *starget;
 
+       if (strncmp(scsi_scan_type, "none", 4) == 0)
+               return ERR_PTR(-ENODEV);
+
        starget = scsi_alloc_target(parent, channel, id);
        if (!starget)
                return ERR_PTR(-ENOMEM);
 
        mutex_lock(&shost->scan_mutex);
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
+
        if (scsi_host_scan_allowed(shost))
                scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
        mutex_unlock(&shost->scan_mutex);
@@ -1530,8 +1611,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
 }
 
 /**
- * scsi_scan_target - scan a target id, possibly including all LUNs on the
- *     target.
+ * scsi_scan_target - scan a target id, possibly including all LUNs on the target.
  * @parent:    host to scan
  * @channel:   channel to scan
  * @id:                target id to scan
@@ -1553,10 +1633,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
        if (strncmp(scsi_scan_type, "none", 4) == 0)
                return;
 
+       mutex_lock(&shost->scan_mutex);
        if (!shost->async_scan)
                scsi_complete_async_scans();
 
-       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost))
                __scsi_scan_target(parent, channel, id, lun, rescan);
        mutex_unlock(&shost->scan_mutex);
@@ -1599,10 +1679,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
 {
        SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
                "%s: <%u:%u:%u>\n",
-               __FUNCTION__, channel, id, lun));
-
-       if (!shost->async_scan)
-               scsi_complete_async_scans();
+               __func__, channel, id, lun));
 
        if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
            ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
@@ -1610,6 +1687,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
                return -EINVAL;
 
        mutex_lock(&shost->scan_mutex);
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
+
        if (scsi_host_scan_allowed(shost)) {
                if (channel == SCAN_WILD_CARD)
                        for (channel = 0; channel <= shost->max_channel;
@@ -1628,7 +1708,8 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
 {
        struct scsi_device *sdev;
        shost_for_each_device(sdev, shost) {
-               if (scsi_sysfs_add_sdev(sdev) != 0)
+               if (!scsi_host_scan_allowed(shost) ||
+                   scsi_sysfs_add_sdev(sdev) != 0)
                        scsi_destroy_sdev(sdev);
        }
 }
@@ -1646,12 +1727,13 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
 static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
 {
        struct async_scan_data *data;
+       unsigned long flags;
 
        if (strncmp(scsi_scan_type, "sync", 4) == 0)
                return NULL;
 
        if (shost->async_scan) {
-               printk("%s called twice for host %d", __FUNCTION__,
+               printk("%s called twice for host %d", __func__,
                                shost->host_no);
                dump_stack();
                return NULL;
@@ -1665,8 +1747,13 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
                goto err;
        init_completion(&data->prev_finished);
 
-       spin_lock(&async_scan_lock);
+       mutex_lock(&shost->scan_mutex);
+       spin_lock_irqsave(shost->host_lock, flags);
        shost->async_scan = 1;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+       mutex_unlock(&shost->scan_mutex);
+
+       spin_lock(&async_scan_lock);
        if (list_empty(&scanning_hosts))
                complete(&data->prev_finished);
        list_add_tail(&data->list, &scanning_hosts);
@@ -1690,15 +1777,20 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
 static void scsi_finish_async_scan(struct async_scan_data *data)
 {
        struct Scsi_Host *shost;
+       unsigned long flags;
 
        if (!data)
                return;
 
        shost = data->shost;
+
+       mutex_lock(&shost->scan_mutex);
+
        if (!shost->async_scan) {
-               printk("%s called twice for host %d", __FUNCTION__,
+               printk("%s called twice for host %d", __func__,
                                shost->host_no);
                dump_stack();
+               mutex_unlock(&shost->scan_mutex);
                return;
        }
 
@@ -1706,8 +1798,13 @@ static void scsi_finish_async_scan(struct async_scan_data *data)
 
        scsi_sysfs_add_devices(shost);
 
-       spin_lock(&async_scan_lock);
+       spin_lock_irqsave(shost->host_lock, flags);
        shost->async_scan = 0;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       mutex_unlock(&shost->scan_mutex);
+
+       spin_lock(&async_scan_lock);
        list_del(&data->list);
        if (!list_empty(&scanning_hosts)) {
                struct async_scan_data *next = list_entry(scanning_hosts.next,
@@ -1749,6 +1846,7 @@ static int do_scan_async(void *_data)
  **/
 void scsi_scan_host(struct Scsi_Host *shost)
 {
+       struct task_struct *p;
        struct async_scan_data *data;
 
        if (strncmp(scsi_scan_type, "none", 4) == 0)
@@ -1760,7 +1858,9 @@ void scsi_scan_host(struct Scsi_Host *shost)
                return;
        }
 
-       kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+       p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+       if (IS_ERR(p))
+               do_scan_async(data);
 }
 EXPORT_SYMBOL(scsi_scan_host);