From f4629ba1d341b599fec0e72d97f966a43773b756 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:28:07 +0900 Subject: [PATCH] --- yaml --- r: 29495 b: refs/heads/master c: 83c47bcb3c533180a6dda78152334de50065358a h: refs/heads/master i: 29493: 1ca413c18f058ae6d683d227be9f2f90079e5a32 29491: d9fded3a4fbf1175596b295b348fef9e3e75ef67 29487: 4a7565278e172a5faa317fc3a9ad216690b1f075 v: v3 --- [refs] | 2 +- trunk/drivers/scsi/libata-core.c | 1 + trunk/drivers/scsi/libata-scsi.c | 89 ++++++++++++++++++++++++++++++++ trunk/include/linux/libata.h | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 05fd3c13f020..1663dace0e98 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 580b2102327ab8444af5bde4e70b50d268a1d558 +refs/heads/master: 83c47bcb3c533180a6dda78152334de50065358a diff --git a/trunk/drivers/scsi/libata-core.c b/trunk/drivers/scsi/libata-core.c index 8df8ecc51a78..c61cfc742388 100644 --- a/trunk/drivers/scsi/libata-core.c +++ b/trunk/drivers/scsi/libata-core.c @@ -5942,6 +5942,7 @@ EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); +EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); diff --git a/trunk/drivers/scsi/libata-scsi.c b/trunk/drivers/scsi/libata-scsi.c index 12563998d97c..7c1ac58c430a 100644 --- a/trunk/drivers/scsi/libata-scsi.c +++ b/trunk/drivers/scsi/libata-scsi.c @@ -57,6 +57,8 @@ static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); +static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun); #define RW_RECOVERY_MPAGE 0x1 @@ -726,6 +728,40 @@ int ata_scsi_slave_config(struct scsi_device *sdev) return 0; /* scsi layer doesn't check return value, sigh */ } +/** + * ata_scsi_slave_destroy - SCSI device is about to be destroyed + * @sdev: SCSI device to be destroyed + * + * @sdev is about to be destroyed for hot/warm unplugging. If + * this unplugging was initiated by libata as indicated by NULL + * dev->sdev, this function doesn't have to do anything. + * Otherwise, SCSI layer initiated warm-unplug is in progress. + * Clear dev->sdev, schedule the device for ATA detach and invoke + * EH. + * + * LOCKING: + * Defined by SCSI layer. We don't really care. + */ +void ata_scsi_slave_destroy(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + unsigned long flags; + struct ata_device *dev; + + if (!ap->ops->error_handler) + return; + + spin_lock_irqsave(&ap->host_set->lock, flags); + dev = __ata_scsi_find_dev(ap, sdev); + if (dev && dev->sdev) { + /* SCSI device already in CANCEL state, no need to offline it */ + dev->sdev = NULL; + dev->flags |= ATA_DFLAG_DETACH; + ata_port_schedule_eh(ap); + } + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + /** * ata_scsi_change_queue_depth - SCSI callback for queue depth config * @sdev: SCSI device to configure queue depth for @@ -2902,3 +2938,56 @@ void ata_scsi_hotplug(void *data) DPRINTK("EXIT\n"); } + +/** + * ata_scsi_user_scan - indication for user-initiated bus scan + * @shost: SCSI host to scan + * @channel: Channel to scan + * @id: ID to scan + * @lun: LUN to scan + * + * This function is called when user explicitly requests bus + * scan. Set probe pending flag and invoke EH. + * + * LOCKING: + * SCSI layer (we don't care) + * + * RETURNS: + * Zero. + */ +static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun) +{ + struct ata_port *ap = ata_shost_to_port(shost); + unsigned long flags; + int rc = 0; + + if (!ap->ops->error_handler) + return -EOPNOTSUPP; + + if ((channel != SCAN_WILD_CARD && channel != 0) || + (lun != SCAN_WILD_CARD && lun != 0)) + return -EINVAL; + + spin_lock_irqsave(&ap->host_set->lock, flags); + + if (id == SCAN_WILD_CARD) { + ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; + ap->eh_info.action |= ATA_EH_SOFTRESET; + } else { + struct ata_device *dev = ata_find_dev(ap, id); + + if (dev) { + ap->eh_info.probe_mask |= 1 << dev->devno; + ap->eh_info.action |= ATA_EH_SOFTRESET; + } else + rc = -EINVAL; + } + + if (rc == 0) + ata_port_schedule_eh(ap); + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + return rc; +} diff --git a/trunk/include/linux/libata.h b/trunk/include/linux/libata.h index 407115624d9f..74786c33c526 100644 --- a/trunk/include/linux/libata.h +++ b/trunk/include/linux/libata.h @@ -734,6 +734,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); extern int ata_scsi_slave_config(struct scsi_device *sdev); +extern void ata_scsi_slave_destroy(struct scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev);