aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-31 05:28:07 -0400
committerTejun Heo <htejun@gmail.com>2006-05-31 05:28:07 -0400
commit83c47bcb3c533180a6dda78152334de50065358a (patch)
tree4bc9ac04f8c3797e49284e0b96e2d654769254ff /drivers
parent580b2102327ab8444af5bde4e70b50d268a1d558 (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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/libata-core.c1
-rw-r--r--drivers/scsi/libata-scsi.c89
2 files changed, 90 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);
5942EXPORT_SYMBOL_GPL(ata_scsi_ioctl); 5942EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
5943EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); 5943EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
5944EXPORT_SYMBOL_GPL(ata_scsi_slave_config); 5944EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
5945EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
5945EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); 5946EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
5946EXPORT_SYMBOL_GPL(ata_scsi_release); 5947EXPORT_SYMBOL_GPL(ata_scsi_release);
5947EXPORT_SYMBOL_GPL(ata_host_intr); 5948EXPORT_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);
58static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, 58static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
59 const struct scsi_device *scsidev); 59 const struct scsi_device *scsidev);
60static 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 */
745void 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 */
2958static 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}