diff options
author | Tejun Heo <htejun@gmail.com> | 2007-09-23 13:19:54 +0900 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:44 -0400 |
commit | 633273a3ed1cf37ced90475b0f95cf81deab04f1 (patch) | |
tree | 5cd42191d1ea8d5ee84fb2f7c7660f124787d9e8 | |
parent | 3af9a77af9e2b72366363864bfcd3d51465ff98a (diff) |
libata-pmp: hook PMP support and enable it
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>
-rw-r--r-- | drivers/ata/libata-core.c | 111 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 18 | ||||
-rw-r--r-- | drivers/ata/libata.h | 2 |
3 files changed, 96 insertions, 35 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9e7f55b7104..d3e78d97529 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -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; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 687419b6670..5f2c0f376f7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -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); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a9b9c9e1e10..a44172fd1f5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -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; |