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;
/* release fn is set up in scsi_sysfs_device_initialise, so
* have to free and put manually here */
put_device(&starget->dev);
+ kfree(sdev);
goto out;
}
{
struct device *parent = dev->parent;
struct scsi_target *starget = to_scsi_target(dev);
- struct Scsi_Host *shost = dev_to_shost(parent);
- if (shost->hostt->target_destroy)
- shost->hostt->target_destroy(starget);
kfree(starget);
put_device(parent);
}
+ shost->transportt->target_size;
struct scsi_target *starget;
struct scsi_target *found_target;
+ int error;
- /*
- * 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;
starget->channel = channel;
INIT_LIST_HEAD(&starget->siblings);
INIT_LIST_HEAD(&starget->devices);
+ starget->state = STARGET_RUNNING;
+ retry:
spin_lock_irqsave(shost->host_lock, flags);
found_target = __scsi_find_target(parent, channel, id);
spin_unlock_irqrestore(shost->host_lock, flags);
/* allocate and add */
transport_setup_device(dev);
- device_add(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) {
- int error = shost->hostt->target_alloc(starget);
+ error = shost->hostt->target_alloc(starget);
if(error) {
dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);
found_target->reap_ref++;
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(parent);
- kfree(starget);
- return found_target;
+ if (found_target->state != STARGET_DEL) {
+ kfree(starget);
+ return found_target;
+ }
+ /* Unfortunately, we found a dying target; need to
+ * wait until it's dead before we can get a new one */
+ put_device(&found_target->dev);
+ flush_scheduled_work();
+ goto retry;
}
-struct work_queue_wrapper {
- struct work_struct work;
- struct scsi_target *starget;
-};
-
-static void scsi_target_reap_work(void *data) {
- struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
- struct scsi_target *starget = wqw->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;
- kfree(wqw);
-
+ transport_remove_device(&starget->dev);
+ device_del(&starget->dev);
+ transport_destroy_device(&starget->dev);
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_destroy_device(&starget->dev);
- put_device(&starget->dev);
- return;
-
- }
+ if (shost->hostt->target_destroy)
+ shost->hostt->target_destroy(starget);
+ list_del_init(&starget->siblings);
spin_unlock_irqrestore(shost->host_lock, flags);
-
- return;
+ put_device(&starget->dev);
}
/**
*/
void scsi_target_reap(struct scsi_target *starget)
{
- struct work_queue_wrapper *wqw =
- kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC);
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ unsigned long flags;
- if (!wqw) {
- starget_printk(KERN_ERR, starget,
- "Failed to allocate memory in scsi_reap_target()\n");
+ spin_lock_irqsave(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, &starget->ew);
return;
+
}
+ spin_unlock_irqrestore(shost->host_lock, flags);
- INIT_WORK(&wqw->work, scsi_target_reap_work, wqw);
- wqw->starget = starget;
- schedule_work(&wqw->work);
+ return;
}
/**
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) &&
transport_configure_device(&sdev->sdev_gendev);
- if (sdev->host->hostt->slave_configure)
- sdev->host->hostt->slave_configure(sdev);
+ if (sdev->host->hostt->slave_configure) {
+ int ret = sdev->host->hostt->slave_configure(sdev);
+ if (ret) {
+ /*
+ * if LLDD reports slave not present, don't clutter
+ * console with alloc failure messages
+ */
+ if (ret != -ENXIO) {
+ sdev_printk(KERN_ERR, sdev,
+ "failed to configure device\n");
+ }
+ return SCSI_SCAN_NO_RESPONSE;
+ }
+ }
/*
* Ok, the device is now all set up, we can
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) {
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);
mutex_lock(&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);
- }
+ 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);