libata-pmp-prep: implement sata_async_notification()
[deliverable/linux.git] / drivers / ata / libata-eh.c
index 3c31e10caf21e16bee5ee942fe5a1b5725c8bc38..60186f8ac3a133ca6f3bdd38f317538295247b5b 100644 (file)
@@ -904,6 +904,79 @@ int ata_port_freeze(struct ata_port *ap)
        return nr_aborted;
 }
 
+/**
+ *     sata_async_notification - SATA async notification handler
+ *     @ap: ATA port where async notification is received
+ *
+ *     Handler to be called when async notification via SDB FIS is
+ *     received.  This function schedules EH if necessary.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+       u32 sntf;
+       int rc;
+
+       if (!(ap->flags & ATA_FLAG_AN))
+               return 0;
+
+       rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+       if (rc == 0)
+               sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+       if (!ap->nr_pmp_links || rc) {
+               /* PMP is not attached or SNTF is not available */
+               if (!ap->nr_pmp_links) {
+                       /* PMP is not attached.  Check whether ATAPI
+                        * AN is configured.  If so, notify media
+                        * change.
+                        */
+                       struct ata_device *dev = ap->link.device;
+
+                       if ((dev->class == ATA_DEV_ATAPI) &&
+                           (dev->flags & ATA_DFLAG_AN))
+                               ata_scsi_media_change_notify(dev);
+                       return 0;
+               } else {
+                       /* PMP is attached but SNTF is not available.
+                        * ATAPI async media change notification is
+                        * not used.  The PMP must be reporting PHY
+                        * status change, schedule EH.
+                        */
+                       ata_port_schedule_eh(ap);
+                       return 1;
+               }
+       } else {
+               /* PMP is attached and SNTF is available */
+               struct ata_link *link;
+
+               /* check and notify ATAPI AN */
+               ata_port_for_each_link(link, ap) {
+                       if (!(sntf & (1 << link->pmp)))
+                               continue;
+
+                       if ((link->device->class == ATA_DEV_ATAPI) &&
+                           (link->device->flags & ATA_DFLAG_AN))
+                               ata_scsi_media_change_notify(link->device);
+               }
+
+               /* If PMP is reporting that PHY status of some
+                * downstream ports has changed, schedule EH.
+                */
+               if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+                       ata_port_schedule_eh(ap);
+                       return 1;
+               }
+
+               return 0;
+       }
+}
+
 /**
  *     ata_eh_freeze_port - EH helper to freeze port
  *     @ap: ATA port to freeze
This page took 0.029001 seconds and 5 git commands to generate.