diff options
| author | Tejun Heo <htejun@gmail.com> | 2006-05-31 05:28:07 -0400 |
|---|---|---|
| committer | Tejun Heo <htejun@gmail.com> | 2006-05-31 05:28:07 -0400 |
| commit | 83c47bcb3c533180a6dda78152334de50065358a (patch) | |
| tree | 4bc9ac04f8c3797e49284e0b96e2d654769254ff | |
| parent | 580b2102327ab8444af5bde4e70b50d268a1d558 (diff) | |
[PATCH] libata-hp: implement warmplug
Implement warmplug. User-initiated unplug can be detected by
hostt->slave_destroy() and plug by transportt->user_scan(). This
patch only implements the two callbacks. The next function will hook
them.
Signed-off-by: Tejun Heo <htejun@gmail.com>
| -rw-r--r-- | drivers/scsi/libata-core.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/libata-scsi.c | 89 | ||||
| -rw-r--r-- | include/linux/libata.h | 1 |
3 files changed, 91 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 8df8ecc51a78..c61cfc742388 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
| @@ -5942,6 +5942,7 @@ EXPORT_SYMBOL_GPL(ata_port_queue_task); | |||
| 5942 | EXPORT_SYMBOL_GPL(ata_scsi_ioctl); | 5942 | EXPORT_SYMBOL_GPL(ata_scsi_ioctl); |
| 5943 | EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); | 5943 | EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); |
| 5944 | EXPORT_SYMBOL_GPL(ata_scsi_slave_config); | 5944 | EXPORT_SYMBOL_GPL(ata_scsi_slave_config); |
| 5945 | EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); | ||
| 5945 | EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); | 5946 | EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); |
| 5946 | EXPORT_SYMBOL_GPL(ata_scsi_release); | 5947 | EXPORT_SYMBOL_GPL(ata_scsi_release); |
| 5947 | EXPORT_SYMBOL_GPL(ata_host_intr); | 5948 | EXPORT_SYMBOL_GPL(ata_host_intr); |
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 12563998d97c..7c1ac58c430a 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
| @@ -57,6 +57,8 @@ static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, | |||
| 57 | const struct scsi_device *scsidev); | 57 | const struct scsi_device *scsidev); |
| 58 | static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, | 58 | static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, |
| 59 | const struct scsi_device *scsidev); | 59 | const struct scsi_device *scsidev); |
| 60 | static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, | ||
| 61 | unsigned int id, unsigned int lun); | ||
| 60 | 62 | ||
| 61 | 63 | ||
| 62 | #define RW_RECOVERY_MPAGE 0x1 | 64 | #define RW_RECOVERY_MPAGE 0x1 |
| @@ -727,6 +729,40 @@ int ata_scsi_slave_config(struct scsi_device *sdev) | |||
| 727 | } | 729 | } |
| 728 | 730 | ||
| 729 | /** | 731 | /** |
| 732 | * ata_scsi_slave_destroy - SCSI device is about to be destroyed | ||
| 733 | * @sdev: SCSI device to be destroyed | ||
| 734 | * | ||
| 735 | * @sdev is about to be destroyed for hot/warm unplugging. If | ||
| 736 | * this unplugging was initiated by libata as indicated by NULL | ||
| 737 | * dev->sdev, this function doesn't have to do anything. | ||
| 738 | * Otherwise, SCSI layer initiated warm-unplug is in progress. | ||
| 739 | * Clear dev->sdev, schedule the device for ATA detach and invoke | ||
| 740 | * EH. | ||
| 741 | * | ||
| 742 | * LOCKING: | ||
| 743 | * Defined by SCSI layer. We don't really care. | ||
| 744 | */ | ||
| 745 | void ata_scsi_slave_destroy(struct scsi_device *sdev) | ||
| 746 | { | ||
| 747 | struct ata_port *ap = ata_shost_to_port(sdev->host); | ||
| 748 | unsigned long flags; | ||
| 749 | struct ata_device *dev; | ||
| 750 | |||
| 751 | if (!ap->ops->error_handler) | ||
| 752 | return; | ||
| 753 | |||
| 754 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
| 755 | dev = __ata_scsi_find_dev(ap, sdev); | ||
| 756 | if (dev && dev->sdev) { | ||
| 757 | /* SCSI device already in CANCEL state, no need to offline it */ | ||
| 758 | dev->sdev = NULL; | ||
| 759 | dev->flags |= ATA_DFLAG_DETACH; | ||
| 760 | ata_port_schedule_eh(ap); | ||
| 761 | } | ||
| 762 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
| 763 | } | ||
| 764 | |||
| 765 | /** | ||
| 730 | * ata_scsi_change_queue_depth - SCSI callback for queue depth config | 766 | * ata_scsi_change_queue_depth - SCSI callback for queue depth config |
| 731 | * @sdev: SCSI device to configure queue depth for | 767 | * @sdev: SCSI device to configure queue depth for |
| 732 | * @queue_depth: new queue depth | 768 | * @queue_depth: new queue depth |
| @@ -2902,3 +2938,56 @@ void ata_scsi_hotplug(void *data) | |||
| 2902 | 2938 | ||
| 2903 | DPRINTK("EXIT\n"); | 2939 | DPRINTK("EXIT\n"); |
| 2904 | } | 2940 | } |
| 2941 | |||
| 2942 | /** | ||
| 2943 | * ata_scsi_user_scan - indication for user-initiated bus scan | ||
| 2944 | * @shost: SCSI host to scan | ||
| 2945 | * @channel: Channel to scan | ||
| 2946 | * @id: ID to scan | ||
| 2947 | * @lun: LUN to scan | ||
| 2948 | * | ||
| 2949 | * This function is called when user explicitly requests bus | ||
| 2950 | * scan. Set probe pending flag and invoke EH. | ||
| 2951 | * | ||
| 2952 | * LOCKING: | ||
| 2953 | * SCSI layer (we don't care) | ||
| 2954 | * | ||
| 2955 | * RETURNS: | ||
| 2956 | * Zero. | ||
| 2957 | */ | ||
| 2958 | static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, | ||
| 2959 | unsigned int id, unsigned int lun) | ||
| 2960 | { | ||
| 2961 | struct ata_port *ap = ata_shost_to_port(shost); | ||
| 2962 | unsigned long flags; | ||
| 2963 | int rc = 0; | ||
| 2964 | |||
| 2965 | if (!ap->ops->error_handler) | ||
| 2966 | return -EOPNOTSUPP; | ||
| 2967 | |||
| 2968 | if ((channel != SCAN_WILD_CARD && channel != 0) || | ||
| 2969 | (lun != SCAN_WILD_CARD && lun != 0)) | ||
| 2970 | return -EINVAL; | ||
| 2971 | |||
| 2972 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
| 2973 | |||
| 2974 | if (id == SCAN_WILD_CARD) { | ||
| 2975 | ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; | ||
| 2976 | ap->eh_info.action |= ATA_EH_SOFTRESET; | ||
| 2977 | } else { | ||
| 2978 | struct ata_device *dev = ata_find_dev(ap, id); | ||
| 2979 | |||
| 2980 | if (dev) { | ||
| 2981 | ap->eh_info.probe_mask |= 1 << dev->devno; | ||
| 2982 | ap->eh_info.action |= ATA_EH_SOFTRESET; | ||
| 2983 | } else | ||
| 2984 | rc = -EINVAL; | ||
| 2985 | } | ||
| 2986 | |||
| 2987 | if (rc == 0) | ||
| 2988 | ata_port_schedule_eh(ap); | ||
| 2989 | |||
| 2990 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
| 2991 | |||
| 2992 | return rc; | ||
| 2993 | } | ||
diff --git a/include/linux/libata.h b/include/linux/libata.h index 407115624d9f..74786c33c526 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -734,6 +734,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev, | |||
| 734 | struct block_device *bdev, | 734 | struct block_device *bdev, |
| 735 | sector_t capacity, int geom[]); | 735 | sector_t capacity, int geom[]); |
| 736 | extern int ata_scsi_slave_config(struct scsi_device *sdev); | 736 | extern int ata_scsi_slave_config(struct scsi_device *sdev); |
| 737 | extern void ata_scsi_slave_destroy(struct scsi_device *sdev); | ||
| 737 | extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, | 738 | extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, |
| 738 | int queue_depth); | 739 | int queue_depth); |
| 739 | extern struct ata_device *ata_dev_pair(struct ata_device *adev); | 740 | extern struct ata_device *ata_dev_pair(struct ata_device *adev); |
