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>
This commit is contained in:
Tejun Heo 2007-09-23 13:19:54 +09:00 committed by Jeff Garzik
parent 3af9a77af9
commit 633273a3ed
3 changed files with 96 additions and 35 deletions

View file

@ -670,29 +670,49 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
* None. * None.
* *
* RETURNS: * RETURNS:
* Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
* the event of failure. * %ATA_DEV_UNKNOWN the event of failure.
*/ */
unsigned int ata_dev_classify(const struct ata_taskfile *tf) unsigned int ata_dev_classify(const struct ata_taskfile *tf)
{ {
/* Apple's open source Darwin code hints that some devices only /* Apple's open source Darwin code hints that some devices only
* put a proper signature into the LBA mid/high registers, * put a proper signature into the LBA mid/high registers,
* So, we only check those. It's sufficient for uniqueness. * 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)) {
if (((tf->lbam == 0) && (tf->lbah == 0)) ||
((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
DPRINTK("found ATA device by sig\n"); DPRINTK("found ATA device by sig\n");
return ATA_DEV_ATA; return ATA_DEV_ATA;
} }
if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) || if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
DPRINTK("found ATAPI device by sig\n"); DPRINTK("found ATAPI device by sig\n");
return ATA_DEV_ATAPI; 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"); DPRINTK("unknown device\n");
return ATA_DEV_UNKNOWN; 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)) (link->flags & ATA_LFLAG_HRST_TO_RESUME))
ehc->i.action |= ATA_EH_HARDRESET; 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 we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET) if (ehc->i.action & ATA_EH_HARDRESET)
return 0; 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 */ /* wait a while before checking status, see SRST for more info */
msleep(150); 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); rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */ /* link occupied, -ENODEV too is an error */
if (rc) { if (rc) {
@ -5966,22 +6002,26 @@ int sata_scr_valid(struct ata_link *link)
* @val: Place to store read value * @val: Place to store read value
* *
* Read SCR register @reg of @link into *@val. This function is * Read SCR register @reg of @link into *@val. This function is
* guaranteed to succeed if the cable type of the port is SATA * guaranteed to succeed if @link is ap->link, the cable type of
* and the port implements ->scr_read. * the port is SATA and the port implements ->scr_read.
* *
* LOCKING: * LOCKING:
* None. * None if @link is ap->link. Kernel thread context otherwise.
* *
* RETURNS: * RETURNS:
* 0 on success, negative errno on failure. * 0 on success, negative errno on failure.
*/ */
int sata_scr_read(struct ata_link *link, int reg, u32 *val) 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)) if (sata_scr_valid(link))
return ap->ops->scr_read(ap, reg, val); return ap->ops->scr_read(ap, reg, val);
return -EOPNOTSUPP; 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 * @val: value to write
* *
* Write @val to SCR register @reg of @link. This function is * Write @val to SCR register @reg of @link. This function is
* guaranteed to succeed if the cable type of the port is SATA * guaranteed to succeed if @link is ap->link, the cable type of
* and the port implements ->scr_read. * the port is SATA and the port implements ->scr_read.
* *
* LOCKING: * LOCKING:
* None. * None if @link is ap->link. Kernel thread context otherwise.
* *
* RETURNS: * RETURNS:
* 0 on success, negative errno on failure. * 0 on success, negative errno on failure.
*/ */
int sata_scr_write(struct ata_link *link, int reg, u32 val) 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)) if (sata_scr_valid(link))
return ap->ops->scr_write(ap, reg, val); return ap->ops->scr_write(ap, reg, val);
return -EOPNOTSUPP; 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. * function performs flush after writing to the register.
* *
* LOCKING: * LOCKING:
* None. * None if @link is ap->link. Kernel thread context otherwise.
* *
* RETURNS: * RETURNS:
* 0 on success, negative errno on failure. * 0 on success, negative errno on failure.
*/ */
int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{ {
struct ata_port *ap = link->ap; if (ata_is_host_link(link)) {
int rc; struct ata_port *ap = link->ap;
int rc;
if (sata_scr_valid(link)) { if (sata_scr_valid(link)) {
rc = ap->ops->scr_write(ap, reg, val); rc = ap->ops->scr_write(ap, reg, val);
if (rc == 0) if (rc == 0)
rc = ap->ops->scr_read(ap, reg, &val); rc = ap->ops->scr_read(ap, reg, &val);
return rc; 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) if (ap->scsi_host)
scsi_host_put(ap->scsi_host); scsi_host_put(ap->scsi_host);
kfree(ap->pmp_link);
kfree(ap); kfree(ap);
host->ports[i] = NULL; host->ports[i] = NULL;
} }

View file

@ -2209,6 +2209,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
readid_flags |= ATA_READID_POSTRESET; readid_flags |= ATA_READID_POSTRESET;
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
WARN_ON(dev->class == ATA_DEV_PMP);
if (ata_link_offline(link)) { if (ata_link_offline(link)) {
rc = -EIO; rc = -EIO;
goto err; goto err;
@ -2234,8 +2236,11 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
ata_class_enabled(ehc->classes[dev->devno])) { ata_class_enabled(ehc->classes[dev->devno])) {
dev->class = ehc->classes[dev->devno]; dev->class = ehc->classes[dev->devno];
rc = ata_dev_read_id(dev, &dev->class, readid_flags, if (dev->class == ATA_DEV_PMP)
dev->id); rc = sata_pmp_attach(dev);
else
rc = ata_dev_read_id(dev, &dev->class,
readid_flags, dev->id);
switch (rc) { switch (rc) {
case 0: case 0:
new_mask |= 1 << dev->devno; new_mask |= 1 << dev->devno;
@ -2264,7 +2269,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
* device detection messages backwards. * device detection messages backwards.
*/ */
ata_link_for_each_dev(dev, link) { 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; continue;
ehc->i.flags |= ATA_EHI_PRINTINFO; 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) if (rc)
goto dev_fail; 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 */ /* configure transfer mode if necessary */
if (ehc->i.flags & ATA_EHI_SETMODE) { if (ehc->i.flags & ATA_EHI_SETMODE) {
rc = ata_set_mode(link, &dev); rc = ata_set_mode(link, &dev);

View file

@ -29,7 +29,7 @@
#define __LIBATA_H__ #define __LIBATA_H__
#define DRV_NAME "libata" #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_scsi_args {
struct ata_device *dev; struct ata_device *dev;