#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/spinlock.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 MODULE_PARM_DESC(max_luns,
                 "last scsi LUN (should be between 1 and 2^32-1)");
 
+static char scsi_scan_type[6] = "sync";
+
+module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
+MODULE_PARM_DESC(scan, "sync, async or none");
+
 /*
  * max_scsi_report_luns: the maximum number of LUNS that will be
  * returned from the REPORT LUNS command. 8 times this value must
                 "Timeout (in seconds) waiting for devices to answer INQUIRY."
                 " Default is 5. Some non-compliant devices need more.");
 
+static DEFINE_SPINLOCK(async_scan_lock);
+static LIST_HEAD(scanning_hosts);
+
+struct async_scan_data {
+       struct list_head list;
+       struct Scsi_Host *shost;
+       struct completion prev_finished;
+};
+
+/**
+ * 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.
+ */
+int scsi_complete_async_scans(void)
+{
+       struct async_scan_data *data;
+
+       do {
+               if (list_empty(&scanning_hosts))
+                       return 0;
+               /* If we can't get memory immediately, that's OK.  Just
+                * sleep a little.  Even if we never get memory, the async
+                * scans will finish eventually.
+                */
+               data = kmalloc(sizeof(*data), GFP_KERNEL);
+               if (!data)
+                       msleep(1);
+       } while (!data);
+
+       data->shost = NULL;
+       init_completion(&data->prev_finished);
+
+       spin_lock(&async_scan_lock);
+       /* Check that there's still somebody else on the list */
+       if (list_empty(&scanning_hosts))
+               goto done;
+       list_add_tail(&data->list, &scanning_hosts);
+       spin_unlock(&async_scan_lock);
+
+       printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n");
+       wait_for_completion(&data->prev_finished);
+
+       spin_lock(&async_scan_lock);
+       list_del(&data->list);
+ done:
+       spin_unlock(&async_scan_lock);
+
+       kfree(data);
+       return 0;
+}
+
+#ifdef MODULE
+/* Only exported for the benefit of scsi_wait_scan */
+EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
+#endif
+
 /**
  * scsi_unlock_floptical - unlock device via a special MODE SENSE command
  * @sdev:      scsi device to send command to
  *     SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
  **/
 static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
-               int *bflags)
+               int *bflags, int async)
 {
        /*
         * XXX do not save the inquiry, since it can change underneath us,
         * register it and tell the rest of the kernel
         * about it.
         */
-       if (scsi_sysfs_add_sdev(sdev) != 0)
+       if (!async && scsi_sysfs_add_sdev(sdev) != 0)
                return SCSI_SCAN_NO_RESPONSE;
 
        return SCSI_SCAN_LUN_PRESENT;
                goto out_free_result;
        }
 
-       res = scsi_add_lun(sdev, result, &bflags);
+       res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);
        if (res == SCSI_SCAN_LUN_PRESENT) {
                if (bflags & BLIST_KEY) {
                        sdev->lockable = 0;
 {
        struct Scsi_Host *shost = dev_to_shost(parent);
 
+       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);
                "%s: <%u:%u:%u>\n",
                __FUNCTION__, channel, id, lun));
 
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
+
        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 0;
 }
 
+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)
+                       scsi_destroy_sdev(sdev);
+       }
+}
+
+/**
+ * scsi_prep_async_scan - prepare for an async scan
+ * @shost: the host which will be scanned
+ * Returns: a cookie to be passed to scsi_finish_async_scan()
+ *
+ * Tells the midlayer this host is going to do an asynchronous scan.
+ * It reserves the host's position in the scanning list and ensures
+ * that other asynchronous scans started after this one won't affect the
+ * ordering of the discovered devices.
+ */
+struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
+{
+       struct async_scan_data *data;
+
+       if (strncmp(scsi_scan_type, "sync", 4) == 0)
+               return NULL;
+
+       if (shost->async_scan) {
+               printk("%s called twice for host %d", __FUNCTION__,
+                               shost->host_no);
+               dump_stack();
+               return NULL;
+       }
+
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               goto err;
+       data->shost = scsi_host_get(shost);
+       if (!data->shost)
+               goto err;
+       init_completion(&data->prev_finished);
+
+       spin_lock(&async_scan_lock);
+       shost->async_scan = 1;
+       if (list_empty(&scanning_hosts))
+               complete(&data->prev_finished);
+       list_add_tail(&data->list, &scanning_hosts);
+       spin_unlock(&async_scan_lock);
+
+       return data;
+
+ err:
+       kfree(data);
+       return NULL;
+}
+
+/**
+ * scsi_finish_async_scan - asynchronous scan has finished
+ * @data: cookie returned from earlier call to scsi_prep_async_scan()
+ *
+ * All the devices currently attached to this host have been found.
+ * This function announces all the devices it has found to the rest
+ * of the system.
+ */
+void scsi_finish_async_scan(struct async_scan_data *data)
+{
+       struct Scsi_Host *shost;
+
+       if (!data)
+               return;
+
+       shost = data->shost;
+       if (!shost->async_scan) {
+               printk("%s called twice for host %d", __FUNCTION__,
+                               shost->host_no);
+               dump_stack();
+               return;
+       }
+
+       wait_for_completion(&data->prev_finished);
+
+       scsi_sysfs_add_devices(shost);
+
+       spin_lock(&async_scan_lock);
+       shost->async_scan = 0;
+       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);
+       }
+       spin_unlock(&async_scan_lock);
+
+       scsi_host_put(shost);
+       kfree(data);
+}
+
+static int do_scan_async(void *_data)
+{
+       struct async_scan_data *data = _data;
+       scsi_scan_host_selected(data->shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+                               SCAN_WILD_CARD, 0);
+
+       scsi_finish_async_scan(data);
+       return 0;
+}
+
 /**
  * scsi_scan_host - scan the given adapter
  * @shost:     adapter to scan
  **/
 void scsi_scan_host(struct Scsi_Host *shost)
 {
-       scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
-                               SCAN_WILD_CARD, 0);
+       struct async_scan_data *data;
+
+       if (strncmp(scsi_scan_type, "none", 4) == 0)
+               return;
+
+       data = scsi_prep_async_scan(shost);
+       if (!data) {
+               scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+                                       SCAN_WILD_CARD, 0);
+               return;
+       }
+       kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
 }
 EXPORT_SYMBOL(scsi_scan_host);
 
 
                                                  struct scsi_device *);
 
 /**
- * shost_for_each_device  -  iterate over all devices of a host
- * @sdev:      iterator
- * @host:      host whiches devices we want to iterate over
+ * shost_for_each_device - iterate over all devices of a host
+ * @sdev: the &struct scsi_device to use as a cursor
+ * @shost: the &struct scsi_host to iterate over
  *
- * This traverses over each devices of @shost.  The devices have
- * a reference that must be released by scsi_host_put when breaking
- * out of the loop.
+ * Iterator that returns each device attached to @shost.  This loop
+ * takes a reference on each device and releases it at the end.  If
+ * you break out of the loop, you must call scsi_device_put(sdev).
  */
 #define shost_for_each_device(sdev, shost) \
        for ((sdev) = __scsi_iterate_devices((shost), NULL); \
             (sdev) = __scsi_iterate_devices((shost), (sdev)))
 
 /**
- * __shost_for_each_device  -  iterate over all devices of a host (UNLOCKED)
- * @sdev:      iterator
- * @host:      host whiches devices we want to iterate over
+ * __shost_for_each_device - iterate over all devices of a host (UNLOCKED)
+ * @sdev: the &struct scsi_device to use as a cursor
+ * @shost: the &struct scsi_host to iterate over
  *
- * This traverses over each devices of @shost.  It does _not_ take a
- * reference on the scsi_device, thus it the whole loop must be protected
- * by shost->host_lock.
+ * Iterator that returns each device attached to @shost.  It does _not_
+ * take a reference on the scsi_device, so the whole loop must be
+ * protected by shost->host_lock.
  *
- * Note:  The only reason why drivers would want to use this is because
- * they're need to access the device list in irq context.  Otherwise you
- * really want to use shost_for_each_device instead.
+ * Note: The only reason to use this is because you need to access the
+ * device list in interrupt context.  Otherwise you really want to use
+ * shost_for_each_device instead.
  */
 #define __shost_for_each_device(sdev, shost) \
        list_for_each_entry((sdev), &((shost)->__devices), siblings)