* global variable (boot or module load time) settings.
*
* A specific LUN is scanned via an INQUIRY command; if the LUN has a
- * device attached, a Scsi_Device is allocated and setup for it.
+ * device attached, a scsi_device is allocated and setup for it.
*
* For every id of every channel on the given host:
*
* device or storage attached to LUN 0):
*
* If LUN 0 has a device attached, allocate and setup a
- * Scsi_Device for it.
+ * scsi_device for it.
*
* If target is SCSI-3 or up, issue a REPORT LUN, and scan
* all of the LUNs returned by the REPORT LUN; else,
#define SCSI_SCAN_TARGET_PRESENT 1
#define SCSI_SCAN_LUN_PRESENT 2
-static char *scsi_null_device_strs = "nullnullnullnull";
+static const char *scsi_null_device_strs = "nullnullnullnull";
#define MAX_SCSI_LUNS 512
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;
}
/*
* if LLDD reports slave not present, don't clutter
* console with alloc failure messages
-
-
*/
if (ret == -ENXIO)
display_failure_msg = 0;
out_device_destroy:
transport_destroy_device(&sdev->sdev_gendev);
- scsi_free_queue(sdev->request_queue);
put_device(&sdev->sdev_gendev);
out:
if (display_failure_msg)
{
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;
+}
+
+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;
+
+ 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);
}
/**
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
+
spin_lock_irqsave(shost->host_lock, flags);
if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
- list_del_init(&starget->siblings);
+ BUG_ON(starget->state == STARGET_DEL);
+ starget->state = STARGET_DEL;
spin_unlock_irqrestore(shost->host_lock, flags);
- device_del(&starget->dev);
- transport_unregister_device(&starget->dev);
- put_device(&starget->dev);
+ execute_in_process_context(scsi_target_reap_usercontext,
+ starget, &starget->ew);
return;
+
}
spin_unlock_irqrestore(shost->host_lock, flags);
+
+ return;
}
/**
*
* If the INQUIRY is successful, zero is returned and the
* INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
- * are copied to the Scsi_Device any flags value is stored in *@bflags.
+ * are copied to the scsi_device any flags value is stored in *@bflags.
**/
static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
int result_len, int *bflags)
pass = 1;
next_pass:
- SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY pass %d "
- "to host %d channel %d id %d lun %d, length %d\n",
- pass, sdev->host->host_no, sdev->channel,
- sdev->id, sdev->lun, try_inquiry_len));
+ SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev,
+ "scsi scan: INQUIRY pass %d length %d\n",
+ pass, try_inquiry_len));
/* Each pass gets up to three chances to ignore Unit Attention */
for (count = 0; count < 3; ++count) {
/*
* Get any flags for this device.
*
- * XXX add a bflags to Scsi_Device, and replace the
- * corresponding bit fields in Scsi_Device, so bflags
+ * XXX add a bflags to scsi_device, and replace the
+ * corresponding bit fields in scsi_device, so bflags
* need not be passed as an argument.
*/
*bflags = scsi_get_device_flags(sdev, &inq_result[8],
if (sdev->scsi_level >= 2 ||
(sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
sdev->scsi_level++;
+ sdev->sdev_target->scsi_level = sdev->scsi_level;
return 0;
}
/**
- * 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
+ * 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
* @inq_result: holds the result of a previous INQUIRY to the LUN
* @bflags: black/white list flag
*
* Description:
- * Allocate and initialize a Scsi_Device matching sdevscan. Optionally
+ * 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
+ * NULL, store the address of the new scsi_device in *@sdevnew (needed
* when scanning a particular LUN).
*
* Return:
- * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
- * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
+ * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
**/
static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
{
*
* The above is vague, as it implies that we could treat 001 and
* 011 the same. Stay compatible with previous code, and create a
- * Scsi_Device for a PQ of 1
+ * scsi_device for a PQ of 1
*
* Don't set the device offline here; rather let the upper
* level drivers eval the PQ to decide whether they should
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
return SCSI_SCAN_LUN_PRESENT;
}
+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_gendev);
+}
+
+
/**
* 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
+ * @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
*
* Description:
* allocate and set it up by calling scsi_add_lun.
*
* Return:
- * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
* SCSI_SCAN_TARGET_PRESENT: target responded, but no device is
* attached at the LUN
- * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
**/
static int scsi_probe_and_add_lun(struct scsi_target *starget,
uint lun, int *bflagsp,
* The rescan flag is used as an optimization, the first scan of a
* host adapter calls into here with rescan == 0.
*/
- if (rescan) {
- sdev = scsi_device_lookup_by_target(starget, lun);
- if (sdev) {
+ sdev = scsi_device_lookup_by_target(starget, lun);
+ if (sdev) {
+ if (rescan || sdev->sdev_state != SDEV_CREATED) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: device exists on %s\n",
sdev->sdev_gendev.bus_id));
sdev->model);
return SCSI_SCAN_LUN_PRESENT;
}
- }
-
- sdev = scsi_alloc_sdev(starget, lun, hostdata);
+ scsi_device_put(sdev);
+ } else
+ sdev = scsi_alloc_sdev(starget, lun, hostdata);
if (!sdev)
goto out;
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) {
res = SCSI_SCAN_NO_RESPONSE;
}
}
- } else {
- if (sdev->host->hostt->slave_destroy)
- sdev->host->hostt->slave_destroy(sdev);
- transport_destroy_device(&sdev->sdev_gendev);
- put_device(&sdev->sdev_gendev);
- }
+ } else
+ scsi_destroy_sdev(sdev);
out:
return res;
}
/**
* scsi_report_lun_scan - Scan using SCSI REPORT LUN results
- * @sdevscan: scan the host, channel, and id of this Scsi_Device
+ * @sdevscan: scan the host, channel, and id of this scsi_device
*
* Description:
* If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
* 0: scan completed (or no memory, so further scanning is futile)
* 1: no report lun scan, or not configured
**/
-static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
+static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
int rescan)
{
char devname[64];
struct scsi_lun *lunp, *lun_data;
u8 *data;
struct scsi_sense_hdr sshdr;
- struct scsi_target *starget = scsi_target(sdev);
+ struct scsi_device *sdev;
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ int ret = 0;
/*
* Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
* support more than 8 LUNs.
*/
if ((bflags & BLIST_NOREPORTLUN) ||
- sdev->scsi_level < SCSI_2 ||
- (sdev->scsi_level < SCSI_3 &&
- (!(bflags & BLIST_REPORTLUN2) || sdev->host->max_lun <= 8)) )
+ starget->scsi_level < SCSI_2 ||
+ (starget->scsi_level < SCSI_3 &&
+ (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) )
return 1;
if (bflags & BLIST_NOLUN)
return 0;
+ if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
+ sdev = scsi_alloc_sdev(starget, 0, NULL);
+ if (!sdev)
+ return 0;
+ if (scsi_device_get(sdev))
+ return 0;
+ }
+
sprintf(devname, "host %d channel %d id %d",
- sdev->host->host_no, sdev->channel, sdev->id);
+ shost->host_no, sdev->channel, sdev->id);
/*
* Allocate enough to hold the header (the same size as one scsi_lun)
length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun);
lun_data = kmalloc(length, GFP_ATOMIC |
(sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
- if (!lun_data)
+ if (!lun_data) {
+ printk(ALLOC_FAILURE_MSG, __FUNCTION__);
goto out;
+ }
scsi_cmd[0] = REPORT_LUNS;
/*
* The device probably does not support a REPORT LUN command
*/
- kfree(lun_data);
- return 1;
+ ret = 1;
+ goto out_err;
}
/*
num_luns = max_scsi_report_luns;
}
- SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUN scan of"
- " host %d channel %d id %d\n", sdev->host->host_no,
- sdev->channel, sdev->id));
+ SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
+ "scsi scan: REPORT LUN scan\n"));
/*
* Scan the luns in lun_data. The entry at offset 0 is really
for (i = 0; i < sizeof(struct scsi_lun); i++)
printk("%02x", data[i]);
printk(" has a LUN larger than currently supported.\n");
- } else if (lun == 0) {
- /*
- * LUN 0 has already been scanned.
- */
} else if (lun > sdev->host->max_lun) {
printk(KERN_WARNING "scsi: %s lun%d has a LUN larger"
" than allowed by the host adapter\n",
/*
* Got some results, but now none, abort.
*/
- printk(KERN_ERR "scsi: Unexpected response"
- " from %s lun %d while scanning, scan"
- " aborted\n", devname, lun);
+ sdev_printk(KERN_ERR, sdev,
+ "Unexpected response"
+ " from lun %d while scanning, scan"
+ " aborted\n", lun);
break;
}
}
}
+ out_err:
kfree(lun_data);
- return 0;
-
out:
- /*
- * We are out of memory, don't try scanning any further.
- */
- printk(ALLOC_FAILURE_MSG, __FUNCTION__);
- return 0;
+ scsi_device_put(sdev);
+ if (sdev->sdev_state == SDEV_CREATED)
+ /*
+ * the sdev we used didn't appear in the report luns scan
+ */
+ scsi_destroy_sdev(sdev);
+ return ret;
}
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);
- down(&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);
- }
- up(&shost->scan_mutex);
+ mutex_lock(&shost->scan_mutex);
+ 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);
struct Scsi_Host *shost = dev_to_shost(parent);
int bflags = 0;
int res;
- struct scsi_device *sdev = NULL;
struct scsi_target *starget;
if (shost->this_id == id)
* Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned.
*/
- res = scsi_probe_and_add_lun(starget, 0, &bflags, &sdev, rescan, NULL);
- if (res == SCSI_SCAN_LUN_PRESENT) {
- if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
+ res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL);
+ if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) {
+ if (scsi_report_lun_scan(starget, bflags, rescan) != 0)
/*
* The REPORT LUN did not scan the target,
* do a sequential scan.
*/
scsi_sequential_lun_scan(starget, bflags,
- res, sdev->scsi_level, rescan);
- } else if (res == SCSI_SCAN_TARGET_PRESENT) {
- /*
- * There's a target here, but lun 0 is offline so we
- * can't use the report_lun scan. Fall back to a
- * sequential lun scan with a bflags of SPARSELUN and
- * a default scsi level of SCSI_2
- */
- scsi_sequential_lun_scan(starget, BLIST_SPARSELUN,
- SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
+ res, starget->scsi_level, rescan);
}
- if (sdev)
- scsi_device_put(sdev);
out_reap:
/* now determine if the target has any children at all
{
struct Scsi_Host *shost = dev_to_shost(parent);
- down(&shost->scan_mutex);
+ mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost))
__scsi_scan_target(parent, channel, id, lun, rescan);
- up(&shost->scan_mutex);
+ mutex_unlock(&shost->scan_mutex);
}
EXPORT_SYMBOL(scsi_scan_target);
int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
- SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
- __FUNCTION__, shost->host_no, channel, id, lun));
+ SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
+ "%s: <%u:%u:%u>\n",
+ __FUNCTION__, channel, id, lun));
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;
- down(&shost->scan_mutex);
+ mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost)) {
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel;
else
scsi_scan_channel(shost, channel, id, lun, rescan);
}
- up(&shost->scan_mutex);
+ mutex_unlock(&shost->scan_mutex);
return 0;
}
}
EXPORT_SYMBOL(scsi_scan_host);
-/**
- * scsi_scan_single_target - scan the given SCSI target
- * @shost: adapter to scan
- * @chan: channel to scan
- * @id: target id to scan
- **/
-void scsi_scan_single_target(struct Scsi_Host *shost,
- unsigned int chan, unsigned int id)
-{
- scsi_scan_host_selected(shost, chan, id, SCAN_WILD_CARD, 1);
-}
-EXPORT_SYMBOL(scsi_scan_single_target);
-
void scsi_forget_host(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
/*
* Function: scsi_get_host_dev()
*
- * Purpose: Create a Scsi_Device that points to the host adapter itself.
+ * Purpose: Create a scsi_device that points to the host adapter itself.
*
- * Arguments: SHpnt - Host that needs a Scsi_Device
+ * Arguments: SHpnt - Host that needs a scsi_device
*
* Lock status: None assumed.
*
- * Returns: The Scsi_Device or NULL
+ * Returns: The scsi_device or NULL
*
* Notes:
- * Attach a single Scsi_Device to the Scsi_Host - this should
+ * Attach a single scsi_device to the Scsi_Host - this should
* be made to look like a "pseudo-device" that points to the
* HA itself.
*
struct scsi_device *sdev = NULL;
struct scsi_target *starget;
- down(&shost->scan_mutex);
+ mutex_lock(&shost->scan_mutex);
if (!scsi_host_scan_allowed(shost))
goto out;
starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
}
put_device(&starget->dev);
out:
- up(&shost->scan_mutex);
+ mutex_unlock(&shost->scan_mutex);
return sdev;
}
EXPORT_SYMBOL(scsi_get_host_dev);
*
* Purpose: Free a scsi_device that points to the host adapter itself.
*
- * Arguments: SHpnt - Host that needs a Scsi_Device
+ * Arguments: SHpnt - Host that needs a scsi_device
*
* Lock status: None assumed.
*
{
BUG_ON(sdev->id != sdev->host->this_id);
- if (sdev->host->hostt->slave_destroy)
- sdev->host->hostt->slave_destroy(sdev);
- transport_destroy_device(&sdev->sdev_gendev);
- put_device(&sdev->sdev_gendev);
+ scsi_destroy_sdev(sdev);
}
EXPORT_SYMBOL(scsi_free_host_dev);