aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-09-23 00:14:13 -0400
committerJeff Garzik <jeff@garzik.org>2007-10-12 14:55:42 -0400
commit7d77b247088fb360aa74bfdd9e19bce1e1987668 (patch)
treeadd1b03309dd6fa82eb0f47e1a88766695f38f28
parente31e8531d668c9c4dc7883054788f89805188003 (diff)
libata-pmp-prep: implement sata_async_notification()
AN serves multiple purposes. For ATAPI, it's used for media change notification. For PMP, for downstream PHY status change notification. Implement sata_async_notification() which demultiplexes AN. To avoid unnecessary port events, ATAPI AN is not enabled if PMP is attached but SNTF is not available. Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Kriten Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/ahci.c24
-rw-r--r--drivers/ata/libata-core.c13
-rw-r--r--drivers/ata/libata-eh.c73
-rw-r--r--drivers/ata/libata-scsi.c1
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/ata/sata_sil24.c5
-rw-r--r--include/linux/libata.h4
7 files changed, 93 insertions, 28 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index cf3404467ceb..9f3c591c7214 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1356,27 +1356,17 @@ static void ahci_port_intr(struct ata_port *ap)
1356 } 1356 }
1357 1357
1358 if (status & PORT_IRQ_SDB_FIS) { 1358 if (status & PORT_IRQ_SDB_FIS) {
1359 /* 1359 /* If the 'N' bit in word 0 of the FIS is set, we just
1360 * if this is an ATAPI device with AN turned on, 1360 * received asynchronous notification. Tell libata
1361 * then we should interrogate the device to 1361 * about it. Note that as the SDB FIS itself is
1362 * determine the cause of the interrupt 1362 * accessible, SNotification can be emulated by the
1363 * 1363 * driver but don't bother for the time being.
1364 * for AN - this we should check the SDB FIS
1365 * and find the I and N bits set
1366 */ 1364 */
1367 const __le32 *f = pp->rx_fis + RX_FIS_SDB; 1365 const __le32 *f = pp->rx_fis + RX_FIS_SDB;
1368 u32 f0 = le32_to_cpu(f[0]); 1366 u32 f0 = le32_to_cpu(f[0]);
1369 1367
1370 /* check the 'N' bit in word 0 of the FIS */ 1368 if (f0 & (1 << 15))
1371 if (f0 & (1 << 15)) { 1369 sata_async_notification(ap);
1372 int port_addr = ((f0 & 0x00000f00) >> 8);
1373 struct ata_device *adev;
1374 if (port_addr < ATA_MAX_DEVICES) {
1375 adev = &ap->link.device[port_addr];
1376 if (adev->flags & ATA_DFLAG_AN)
1377 ata_scsi_media_change_notify(adev);
1378 }
1379 }
1380 } 1370 }
1381 1371
1382 if (ap->link.sactive) 1372 if (ap->link.sactive)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 376dbd80cc93..8b08e7bdd24d 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2016,6 +2016,7 @@ int ata_dev_configure(struct ata_device *dev)
2016 else if (dev->class == ATA_DEV_ATAPI) { 2016 else if (dev->class == ATA_DEV_ATAPI) {
2017 const char *cdb_intr_string = ""; 2017 const char *cdb_intr_string = "";
2018 const char *atapi_an_string = ""; 2018 const char *atapi_an_string = "";
2019 u32 sntf;
2019 2020
2020 rc = atapi_cdb_len(id); 2021 rc = atapi_cdb_len(id);
2021 if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { 2022 if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -2027,11 +2028,14 @@ int ata_dev_configure(struct ata_device *dev)
2027 } 2028 }
2028 dev->cdb_len = (unsigned int) rc; 2029 dev->cdb_len = (unsigned int) rc;
2029 2030
2030 /* 2031 /* Enable ATAPI AN if both the host and device have
2031 * check to see if this ATAPI device supports 2032 * the support. If PMP is attached, SNTF is required
2032 * Asynchronous Notification 2033 * to enable ATAPI AN to discern between PHY status
2034 * changed notifications and ATAPI ANs.
2033 */ 2035 */
2034 if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) { 2036 if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
2037 (!ap->nr_pmp_links ||
2038 sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
2035 unsigned int err_mask; 2039 unsigned int err_mask;
2036 2040
2037 /* issue SET feature command to turn this on */ 2041 /* issue SET feature command to turn this on */
@@ -7248,6 +7252,7 @@ EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
7248EXPORT_SYMBOL_GPL(ata_link_abort); 7252EXPORT_SYMBOL_GPL(ata_link_abort);
7249EXPORT_SYMBOL_GPL(ata_port_abort); 7253EXPORT_SYMBOL_GPL(ata_port_abort);
7250EXPORT_SYMBOL_GPL(ata_port_freeze); 7254EXPORT_SYMBOL_GPL(ata_port_freeze);
7255EXPORT_SYMBOL_GPL(sata_async_notification);
7251EXPORT_SYMBOL_GPL(ata_eh_freeze_port); 7256EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
7252EXPORT_SYMBOL_GPL(ata_eh_thaw_port); 7257EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
7253EXPORT_SYMBOL_GPL(ata_eh_qc_complete); 7258EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 3c31e10caf21..60186f8ac3a1 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -905,6 +905,79 @@ int ata_port_freeze(struct ata_port *ap)
905} 905}
906 906
907/** 907/**
908 * sata_async_notification - SATA async notification handler
909 * @ap: ATA port where async notification is received
910 *
911 * Handler to be called when async notification via SDB FIS is
912 * received. This function schedules EH if necessary.
913 *
914 * LOCKING:
915 * spin_lock_irqsave(host lock)
916 *
917 * RETURNS:
918 * 1 if EH is scheduled, 0 otherwise.
919 */
920int sata_async_notification(struct ata_port *ap)
921{
922 u32 sntf;
923 int rc;
924
925 if (!(ap->flags & ATA_FLAG_AN))
926 return 0;
927
928 rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
929 if (rc == 0)
930 sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
931
932 if (!ap->nr_pmp_links || rc) {
933 /* PMP is not attached or SNTF is not available */
934 if (!ap->nr_pmp_links) {
935 /* PMP is not attached. Check whether ATAPI
936 * AN is configured. If so, notify media
937 * change.
938 */
939 struct ata_device *dev = ap->link.device;
940
941 if ((dev->class == ATA_DEV_ATAPI) &&
942 (dev->flags & ATA_DFLAG_AN))
943 ata_scsi_media_change_notify(dev);
944 return 0;
945 } else {
946 /* PMP is attached but SNTF is not available.
947 * ATAPI async media change notification is
948 * not used. The PMP must be reporting PHY
949 * status change, schedule EH.
950 */
951 ata_port_schedule_eh(ap);
952 return 1;
953 }
954 } else {
955 /* PMP is attached and SNTF is available */
956 struct ata_link *link;
957
958 /* check and notify ATAPI AN */
959 ata_port_for_each_link(link, ap) {
960 if (!(sntf & (1 << link->pmp)))
961 continue;
962
963 if ((link->device->class == ATA_DEV_ATAPI) &&
964 (link->device->flags & ATA_DFLAG_AN))
965 ata_scsi_media_change_notify(link->device);
966 }
967
968 /* If PMP is reporting that PHY status of some
969 * downstream ports has changed, schedule EH.
970 */
971 if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
972 ata_port_schedule_eh(ap);
973 return 1;
974 }
975
976 return 0;
977 }
978}
979
980/**
908 * ata_eh_freeze_port - EH helper to freeze port 981 * ata_eh_freeze_port - EH helper to freeze port
909 * @ap: ATA port to freeze 982 * @ap: ATA port to freeze
910 * 983 *
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 451f79c6fbac..df2e05738f3b 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3244,7 +3244,6 @@ void ata_scsi_media_change_notify(struct ata_device *dev)
3244 scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); 3244 scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
3245#endif 3245#endif
3246} 3246}
3247EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify);
3248 3247
3249/** 3248/**
3250 * ata_scsi_hotplug - SCSI part of hotplug 3249 * ata_scsi_hotplug - SCSI part of hotplug
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 0f3e355fdfd7..ebe22982e80c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -119,6 +119,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
119 struct scsi_host_template *sht); 119 struct scsi_host_template *sht);
120extern void ata_scsi_scan_host(struct ata_port *ap, int sync); 120extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
121extern int ata_scsi_offline_dev(struct ata_device *dev); 121extern int ata_scsi_offline_dev(struct ata_device *dev);
122extern void ata_scsi_media_change_notify(struct ata_device *dev);
122extern void ata_scsi_hotplug(struct work_struct *work); 123extern void ata_scsi_hotplug(struct work_struct *work);
123extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, 124extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
124 unsigned int buflen); 125 unsigned int buflen);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 9acfce43bde4..b4f81eb8bbbe 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -821,11 +821,8 @@ static void sil24_error_intr(struct ata_port *ap)
821 ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); 821 ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
822 822
823 if (irq_stat & PORT_IRQ_SDB_NOTIFY) { 823 if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
824 struct ata_device *dev = ap->link.device;
825
826 ata_ehi_push_desc(ehi, "SDB notify"); 824 ata_ehi_push_desc(ehi, "SDB notify");
827 if (dev->flags & ATA_DFLAG_AN) 825 sata_async_notification(ap);
828 ata_scsi_media_change_notify(dev);
829 } 826 }
830 827
831 if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { 828 if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 56b218771114..cd9c2a28136a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -139,7 +139,7 @@ enum {
139 ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ 139 ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
140 ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ 140 ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
141 ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ 141 ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
142 ATA_DFLAG_AN = (1 << 7), /* device supports AN */ 142 ATA_DFLAG_AN = (1 << 7), /* AN configured */
143 ATA_DFLAG_CFG_MASK = (1 << 12) - 1, 143 ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
144 144
145 ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ 145 ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */
@@ -787,7 +787,6 @@ extern void ata_host_init(struct ata_host *, struct device *,
787extern int ata_scsi_detect(struct scsi_host_template *sht); 787extern int ata_scsi_detect(struct scsi_host_template *sht);
788extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); 788extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
789extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); 789extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
790extern void ata_scsi_media_change_notify(struct ata_device *atadev);
791extern void ata_sas_port_destroy(struct ata_port *); 790extern void ata_sas_port_destroy(struct ata_port *);
792extern struct ata_port *ata_sas_port_alloc(struct ata_host *, 791extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
793 struct ata_port_info *, struct Scsi_Host *); 792 struct ata_port_info *, struct Scsi_Host *);
@@ -953,6 +952,7 @@ extern void ata_port_schedule_eh(struct ata_port *ap);
953extern int ata_link_abort(struct ata_link *link); 952extern int ata_link_abort(struct ata_link *link);
954extern int ata_port_abort(struct ata_port *ap); 953extern int ata_port_abort(struct ata_port *ap);
955extern int ata_port_freeze(struct ata_port *ap); 954extern int ata_port_freeze(struct ata_port *ap);
955extern int sata_async_notification(struct ata_port *ap);
956 956
957extern void ata_eh_freeze_port(struct ata_port *ap); 957extern void ata_eh_freeze_port(struct ata_port *ap);
958extern void ata_eh_thaw_port(struct ata_port *ap); 958extern void ata_eh_thaw_port(struct ata_port *ap);