libata-pmp: hook PMP support and enable it
authorTejun Heo <htejun@gmail.com>
Sun, 23 Sep 2007 04:19:54 +0000 (13:19 +0900)
committerJeff Garzik <jeff@garzik.org>
Fri, 12 Oct 2007 18:55:44 +0000 (14:55 -0400)
Hook PMP support into libata and enable it.  Connect SCR and probing
functions, and update ata_dev_classify() to detect PMP.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata.h

index 9e7f55b..d3e78d9 100644 (file)
@@ -670,29 +670,49 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
  *     None.
  *
  *     RETURNS:
- *     Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- *     the event of failure.
+ *     Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
+ *     %ATA_DEV_UNKNOWN the event of failure.
  */
-
 unsigned int ata_dev_classify(const struct ata_taskfile *tf)
 {
        /* Apple's open source Darwin code hints that some devices only
         * put a proper signature into the LBA mid/high registers,
         * So, we only check those.  It's sufficient for uniqueness.
+        *
+        * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate
+        * signatures for ATA and ATAPI devices attached on SerialATA,
+        * 0x3c/0xc3 and 0x69/0x96 respectively.  However, SerialATA
+        * spec has never mentioned about using different signatures
+        * for ATA/ATAPI devices.  Then, Serial ATA II: Port
+        * Multiplier specification began to use 0x69/0x96 to identify
+        * port multpliers and 0x3c/0xc3 to identify SEMB device.
+        * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and
+        * 0x69/0x96 shortly and described them as reserved for
+        * SerialATA.
+        *
+        * We follow the current spec and consider that 0x69/0x96
+        * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
         */
-
-       if (((tf->lbam == 0) && (tf->lbah == 0)) ||
-           ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+       if ((tf->lbam == 0) && (tf->lbah == 0)) {
                DPRINTK("found ATA device by sig\n");
                return ATA_DEV_ATA;
        }
 
-       if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
-           ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+       if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
                DPRINTK("found ATAPI device by sig\n");
                return ATA_DEV_ATAPI;
        }
 
+       if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {
+               DPRINTK("found PMP device by sig\n");
+               return ATA_DEV_PMP;
+       }
+
+       if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
+               printk("ata: SEMB device ignored\n");
+               return ATA_DEV_SEMB_UNSUP; /* not yet */
+       }
+
        DPRINTK("unknown device\n");
        return ATA_DEV_UNKNOWN;
 }
@@ -3426,6 +3446,12 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
            (link->flags & ATA_LFLAG_HRST_TO_RESUME))
                ehc->i.action |= ATA_EH_HARDRESET;
 
+       /* Some PMPs don't work with only SRST, force hardreset if PMP
+        * is supported.
+        */
+       if (ap->flags & ATA_FLAG_PMP)
+               ehc->i.action |= ATA_EH_HARDRESET;
+
        /* if we're about to do hardreset, nothing more to do */
        if (ehc->i.action & ATA_EH_HARDRESET)
                return 0;
@@ -3616,6 +3642,16 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class,
        /* wait a while before checking status, see SRST for more info */
        msleep(150);
 
+       /* If PMP is supported, we have to do follow-up SRST.  Note
+        * that some PMPs don't send D2H Reg FIS after hardreset at
+        * all if the first port is empty.  Wait for it just for a
+        * second and request follow-up SRST.
+        */
+       if (ap->flags & ATA_FLAG_PMP) {
+               ata_wait_ready(ap, jiffies + HZ);
+               return -EAGAIN;
+       }
+
        rc = ata_wait_ready(ap, deadline);
        /* link occupied, -ENODEV too is an error */
        if (rc) {
@@ -5966,22 +6002,26 @@ int sata_scr_valid(struct ata_link *link)
  *     @val: Place to store read value
  *
  *     Read SCR register @reg of @link into *@val.  This function is
- *     guaranteed to succeed if the cable type of the port is SATA
- *     and the port implements ->scr_read.
+ *     guaranteed to succeed if @link is ap->link, the cable type of
+ *     the port is SATA and the port implements ->scr_read.
  *
  *     LOCKING:
- *     None.
+ *     None if @link is ap->link.  Kernel thread context otherwise.
  *
  *     RETURNS:
  *     0 on success, negative errno on failure.
  */
 int sata_scr_read(struct ata_link *link, int reg, u32 *val)
 {
-       struct ata_port *ap = link->ap;
+       if (ata_is_host_link(link)) {
+               struct ata_port *ap = link->ap;
 
-       if (sata_scr_valid(link))
-               return ap->ops->scr_read(ap, reg, val);
-       return -EOPNOTSUPP;
+               if (sata_scr_valid(link))
+                       return ap->ops->scr_read(ap, reg, val);
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_read(link, reg, val);
 }
 
 /**
@@ -5991,22 +6031,26 @@ int sata_scr_read(struct ata_link *link, int reg, u32 *val)
  *     @val: value to write
  *
  *     Write @val to SCR register @reg of @link.  This function is
- *     guaranteed to succeed if the cable type of the port is SATA
- *     and the port implements ->scr_read.
+ *     guaranteed to succeed if @link is ap->link, the cable type of
+ *     the port is SATA and the port implements ->scr_read.
  *
  *     LOCKING:
- *     None.
+ *     None if @link is ap->link.  Kernel thread context otherwise.
  *
  *     RETURNS:
  *     0 on success, negative errno on failure.
  */
 int sata_scr_write(struct ata_link *link, int reg, u32 val)
 {
-       struct ata_port *ap = link->ap;
+       if (ata_is_host_link(link)) {
+               struct ata_port *ap = link->ap;
 
-       if (sata_scr_valid(link))
-               return ap->ops->scr_write(ap, reg, val);
-       return -EOPNOTSUPP;
+               if (sata_scr_valid(link))
+                       return ap->ops->scr_write(ap, reg, val);
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_write(link, reg, val);
 }
 
 /**
@@ -6019,23 +6063,27 @@ int sata_scr_write(struct ata_link *link, int reg, u32 val)
  *     function performs flush after writing to the register.
  *
  *     LOCKING:
- *     None.
+ *     None if @link is ap->link.  Kernel thread context otherwise.
  *
  *     RETURNS:
  *     0 on success, negative errno on failure.
  */
 int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
 {
-       struct ata_port *ap = link->ap;
-       int rc;
+       if (ata_is_host_link(link)) {
+               struct ata_port *ap = link->ap;
+               int rc;
 
-       if (sata_scr_valid(link)) {
-               rc = ap->ops->scr_write(ap, reg, val);
-               if (rc == 0)
-                       rc = ap->ops->scr_read(ap, reg, &val);
-               return rc;
+               if (sata_scr_valid(link)) {
+                       rc = ap->ops->scr_write(ap, reg, val);
+                       if (rc == 0)
+                               rc = ap->ops->scr_read(ap, reg, &val);
+                       return rc;
+               }
+               return -EOPNOTSUPP;
        }
-       return -EOPNOTSUPP;
+
+       return sata_pmp_scr_write(link, reg, val);
 }
 
 /**
@@ -6424,6 +6472,7 @@ static void ata_host_release(struct device *gendev, void *res)
                if (ap->scsi_host)
                        scsi_host_put(ap->scsi_host);
 
+               kfree(ap->pmp_link);
                kfree(ap);
                host->ports[i] = NULL;
        }
index 687419b..5f2c0f3 100644 (file)
@@ -2209,6 +2209,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
                        readid_flags |= ATA_READID_POSTRESET;
 
                if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
+                       WARN_ON(dev->class == ATA_DEV_PMP);
+
                        if (ata_link_offline(link)) {
                                rc = -EIO;
                                goto err;
@@ -2234,8 +2236,11 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
                           ata_class_enabled(ehc->classes[dev->devno])) {
                        dev->class = ehc->classes[dev->devno];
 
-                       rc = ata_dev_read_id(dev, &dev->class, readid_flags,
-                                            dev->id);
+                       if (dev->class == ATA_DEV_PMP)
+                               rc = sata_pmp_attach(dev);
+                       else
+                               rc = ata_dev_read_id(dev, &dev->class,
+                                                    readid_flags, dev->id);
                        switch (rc) {
                        case 0:
                                new_mask |= 1 << dev->devno;
@@ -2264,7 +2269,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
         * device detection messages backwards.
         */
        ata_link_for_each_dev(dev, link) {
-               if (!(new_mask & (1 << dev->devno)))
+               if (!(new_mask & (1 << dev->devno)) ||
+                   dev->class == ATA_DEV_PMP)
                        continue;
 
                ehc->i.flags |= ATA_EHI_PRINTINFO;
@@ -2521,6 +2527,12 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                if (rc)
                        goto dev_fail;
 
+               /* if PMP got attached, return, pmp EH will take care of it */
+               if (link->device->class == ATA_DEV_PMP) {
+                       ehc->i.action = 0;
+                       return 0;
+               }
+
                /* configure transfer mode if necessary */
                if (ehc->i.flags & ATA_EHI_SETMODE) {
                        rc = ata_set_mode(link, &dev);
index a9b9c9e..a44172f 100644 (file)
@@ -29,7 +29,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME       "libata"
-#define DRV_VERSION    "2.21"  /* must be exactly four chars */
+#define DRV_VERSION    "3.00"  /* must be exactly four chars */
 
 struct ata_scsi_args {
        struct ata_device       *dev;