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); |