MODULE_PARM_DESC(max_luns,
"last scsi LUN (should be between 1 and 2^32-1)");
-static char scsi_scan_type[6] = "sync";
+#ifdef CONFIG_SCSI_SCAN_ASYNC
+#define SCSI_SCAN_TYPE_DEFAULT "async"
+#else
+#define SCSI_SCAN_TYPE_DEFAULT "sync"
+#endif
+
+static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT;
module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
MODULE_PARM_DESC(scan, "sync, async or none");
/**
* 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)
{
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);
goto retry;
}
-static void scsi_target_reap_usercontext(void *data)
+static void scsi_target_reap_usercontext(struct work_struct *work)
{
- struct scsi_target *starget = data;
+ 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;
starget->state = STARGET_DEL;
spin_unlock_irqrestore(shost->host_lock, flags);
execute_in_process_context(scsi_target_reap_usercontext,
- starget, &starget->ew);
+ &starget->ew);
return;
}
sdev->no_uld_attach = 1;
switch (sdev->type = (inq_result[0] & 0x1f)) {
+ 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:
case TYPE_ENCLOSURE:
case TYPE_COMM:
case TYPE_RAID:
- case TYPE_RBC:
sdev->writeable = 1;
break;
- case TYPE_WORM:
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;
default:
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));
});
struct device *parent = &shost->shost_gendev;
struct scsi_target *starget;
+ 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);
{
struct Scsi_Host *shost = dev_to_shost(parent);
+ if (strncmp(scsi_scan_type, "none", 4) == 0)
+ return;
+
if (!shost->async_scan)
scsi_complete_async_scans();
* 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)
+static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
{
struct async_scan_data *data;
* 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)
+static void scsi_finish_async_scan(struct async_scan_data *data)
{
struct Scsi_Host *shost;
kfree(data);
}
-static int do_scan_async(void *_data)
+static void do_scsi_scan_host(struct Scsi_Host *shost)
{
- struct async_scan_data *data = _data;
- scsi_scan_host_selected(data->shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+ if (shost->hostt->scan_finished) {
+ unsigned long start = jiffies;
+ if (shost->hostt->scan_start)
+ shost->hostt->scan_start(shost);
+
+ while (!shost->hostt->scan_finished(shost, jiffies - start))
+ msleep(10);
+ } else {
+ scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
SCAN_WILD_CARD, 0);
+ }
+}
+static int do_scan_async(void *_data)
+{
+ struct async_scan_data *data = _data;
+ do_scsi_scan_host(data->shost);
scsi_finish_async_scan(data);
return 0;
}
data = scsi_prep_async_scan(shost);
if (!data) {
- scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
- SCAN_WILD_CARD, 0);
+ do_scsi_scan_host(shost);
return;
}
+
kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
}
EXPORT_SYMBOL(scsi_scan_host);