diff options
author | Tejun Heo <htejun@gmail.com> | 2007-09-23 00:14:13 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:42 -0400 |
commit | 7d77b247088fb360aa74bfdd9e19bce1e1987668 (patch) | |
tree | add1b03309dd6fa82eb0f47e1a88766695f38f28 /drivers/ata/libata-eh.c | |
parent | e31e8531d668c9c4dc7883054788f89805188003 (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>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 73 |
1 files changed, 73 insertions, 0 deletions
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 | */ | ||
920 | int 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 | * |