]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_scan.c
Pull cpuidle into release branch
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_scan.c
index 662577fbe7a87ddd93a66e37e66bbedbeb64e73d..b53c5f67e372684cc23c81a9f0ce19a41109e1ac 100644 (file)
@@ -85,7 +85,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 +109,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;
 
-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.");
 
+/* This lock protects only this list */
 static DEFINE_SPINLOCK(async_scan_lock);
 static LIST_HEAD(scanning_hosts);
 
@@ -703,16 +704,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
@@ -752,25 +751,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:
-               /* RBC 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;
-               /* fall through */
        case TYPE_TAPE:
        case TYPE_DISK:
        case TYPE_PRINTER:
@@ -784,13 +773,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                sdev->writeable = 1;
                break;
        case TYPE_ROM:
-               /* 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;
-               /* fall through */
        case TYPE_WORM:
                sdev->writeable = 0;
                break;
@@ -798,6 +780,15 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                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
@@ -815,12 +806,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;
@@ -833,13 +823,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
@@ -848,6 +835,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
@@ -872,7 +862,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        if (*bflags & BLIST_SINGLELUN)
                sdev->single_lun = 1;
 
-
        sdev->use_10_for_rw = 1;
 
        if (*bflags & BLIST_MS_SKIP_PAGE_08)
@@ -1213,7 +1202,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;
@@ -1224,6 +1213,7 @@ 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
@@ -1477,14 +1467,14 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
        if (strncmp(scsi_scan_type, "none", 4) == 0)
                return ERR_PTR(-ENODEV);
 
-       if (!shost->async_scan)
-               scsi_complete_async_scans();
-
        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);
@@ -1597,10 +1587,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);
@@ -1645,15 +1635,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
                "%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 -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;
@@ -1672,7 +1662,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);
        }
 }
@@ -1690,6 +1681,7 @@ 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;
@@ -1709,8 +1701,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);
@@ -1734,11 +1731,15 @@ 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__,
                                shost->host_no);
@@ -1750,8 +1751,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,
@@ -1793,6 +1799,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)
@@ -1804,7 +1811,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 (unlikely(IS_ERR(p)))
+               do_scan_async(data);
 }
 EXPORT_SYMBOL(scsi_scan_host);