linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHSET 4/4] implement PMP support, take 4
@ 2007-07-01 10:54 Tejun Heo
  2007-07-01 10:54 ` [PATCH 01/15] libata-pmp: update ata_eh_reset() for PMP Tejun Heo
                   ` (16 more replies)
  0 siblings, 17 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao, htejun

Hello, all.

his is the fourth take of libata-pmp patchset.  This patchset contains
15 patches and implements PMP support.

#01-04: implement libata PMP support
#05-09: implement sata_sil24 PMP support
#10-15: implement ahci PMP support

Changes from the last take[L] are.

* updated to fit new #upstream
* ACPI support for PMP fan-out ports added
* improved general PMP EH behavior
* various PMP chip specific quirks for smooth handling of first gen
  products which at times are pretty quirky
* AHCI PMP support added

Tested extensively with sil3214/32, ICH9R, JMB360/3 combined with
sil3726, 4726 and 5744 port multipliers.  Disks from all major vendors
and an SATAPI device is used as downstream devices.  sil5744 and 3726
behave very nicely on all controllers.  Hotplugging and suspend/resume
work well too.  There are some remaining issues.

* When attached to AHCI controller (ICH9R, JMB360/3), NCQ doesn't
  work.  Things look okay as long as only one command is in flight but
  as soon as the second command is issued (to the same device), hell
  breaks loose and all sorts of errors occur including device abort,
  bad PMP number and interface fatal error.  This behavior is common
  across all PMP chips.  I've disabled NCQ if PMP is attached to an
  ahci controller for now.

* Sil4726 is a bit too quirky.  Without the first fan-out port
  occupied, the thing acts really weirdly.  As long as the first port
  is occupied, it works okay.  This is reportedly fixed by new
  firmware.  I tried to update the firmware but installing 3124 driver
  on Windows was just too difficult for me and I gave up after thirty
  painful minutes.  Anyone up for testing?

* Again, Sil4726 doesn't like ahci driver initialization sequence.
  During driver initialization, the whole controller is reset and the
  PHY seems to go offline and back online.  Sil4726 doesn't like it
  and goes out for lunch for several secs after that which makes
  initial probing think that the port is empty.  After probing is
  complete, Sil4726 comes back and gets detected but at that point
  detection is asynchronous and if boot device is on one of fan-out
  ports, it can be a problem.  Again, this might have been fixed by
  new firmware.  Anyone up for testing?

* The long boot delay on ASUS boards with on-board PMP chips should be
  fixed by this patchset but I don't have such a board or Sil4723
  which is used on those baords, so I'm not sure.  Anyone up for
  testing?

This patchset is against

  libata-dev#upstream (4e1ae96828f6cee7b89ab8ca474c150fe211afd8)
  + [1] misc-updates patchset
  + [2] libata-link patchset, take 4
  + [3] libata-pmp-prep patchset, take 4

Thanks.

--
tejun

[L] http://thread.gmane.org/gmane.linux.ide/13503
[1] http://thread.gmane.org/gmane.linux.ide/20081
[2] http://thread.gmane.org/gmane.linux.ide/20099
[3] http://thread.gmane.org/gmane.linux.ide/20115



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 01/15] libata-pmp: update ata_eh_reset() for PMP
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 02/15] libata-pmp: implement Port Multiplier support Tejun Heo
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

PMP always requires SRST to be enabled.  Also, hardreset reports
classification code from the first device when PMP is attached, not
from the PMP.  Update ata_eh_reset() such that followup softreset is
performed if the controller is PMP capable and the host link is being
reset.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/libata-eh.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 03b1665..01cd3be 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1841,6 +1841,8 @@ static int ata_eh_followup_srst_needed(struct ata_link *link,
 		return 1;
 	if (rc != 0)
 		return 0;
+	if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
+		return 1;
 	if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
 	    classes[0] == ATA_DEV_UNKNOWN)
 		return 1;
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (2 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 03/15] libata-pmp: hook PMP support and enable it Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-12 20:24   ` Jeff Garzik
  2007-07-01 10:54 ` [PATCH 09/15] sata_sil24: implement PORT_RST Tejun Heo
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Extend ata_acpi_associate_sata_port() such that it can handle PMP and
call it when PMP is attached and detached.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/libata-acpi.c |   36 ++++++++++++++++++++++++++++++++----
 drivers/ata/libata-pmp.c  |    4 ++++
 drivers/ata/libata.h      |    1 +
 3 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 43af2e0..153388c 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -40,12 +40,40 @@ static int is_pci_dev(struct device *dev)
 	return (dev->bus == &pci_bus_type);
 }
 
-static void ata_acpi_associate_sata_port(struct ata_port *ap)
+/**
+ * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
+ * @ap: target SATA port
+ *
+ * Look up ACPI objects associated with @ap and initialize acpi_handle
+ * fields of @ap, the port and devices accordingly.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+void ata_acpi_associate_sata_port(struct ata_port *ap)
 {
-	acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+	WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
+
+	if (!ap->nr_pmp_links) {
+		acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+
+		ap->link.device->acpi_handle =
+			acpi_get_child(ap->host->acpi_handle, adr);
+	} else {
+		struct ata_link *link;
+
+		ap->link.device->acpi_handle = NULL;
 
-	ap->link.device->acpi_handle =
-		acpi_get_child(ap->host->acpi_handle, adr);
+		ata_port_for_each_link(link, ap) {
+			acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+
+			link->device->acpi_handle =
+				acpi_get_child(ap->host->acpi_handle, adr);
+		}
+	}
 }
 
 static void ata_acpi_associate_ide_port(struct ata_port *ap)
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 7c298e7..d6d05b2 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -595,6 +595,8 @@ int sata_pmp_attach(struct ata_device *dev)
 	ata_port_for_each_link(tlink, ap)
 		sata_link_init_spd_limit(tlink);
 
+	ata_acpi_associate_sata_port(ap);
+
 	return 0;
 
  fail:
@@ -634,6 +636,8 @@ static void sata_pmp_detach(struct ata_device *dev)
 	ap->nr_pmp_links = 0;
 	link->pmp = 0;
 	spin_unlock_irqrestore(ap->lock, flags);
+
+	ata_acpi_associate_sata_port(ap);
 }
 
 /**
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index f774d9c..9577db0 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -101,6 +101,7 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
+extern void ata_acpi_associate_sata_port(struct ata_port *ap);
 extern void ata_acpi_associate(struct ata_host *host);
 extern int ata_acpi_on_suspend(struct ata_port *ap);
 extern void ata_acpi_on_resume(struct ata_port *ap);
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 03/15] libata-pmp: hook PMP support and enable it
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
  2007-07-01 10:54 ` [PATCH 01/15] libata-pmp: update ata_eh_reset() for PMP Tejun Heo
  2007-07-01 10:54 ` [PATCH 02/15] libata-pmp: implement Port Multiplier support Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP Tejun Heo
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

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>
---
 drivers/ata/libata-core.c |  113 ++++++++++++++++++++++++++++++++-------------
 drivers/ata/libata-eh.c   |   18 ++++++-
 2 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 4e86164..151b585 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,7 +59,7 @@
 
 #include "libata.h"
 
-#define DRV_VERSION	"2.21"	/* must be exactly four chars */
+#define DRV_VERSION	"3.00"	/* must be exactly four chars */
 
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
@@ -666,29 +666,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;
 }
@@ -3367,6 +3387,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;
@@ -3555,6 +3581,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) {
@@ -5750,22 +5786,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);
 }
 
 /**
@@ -5775,22 +5815,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);
 }
 
 /**
@@ -5803,23 +5847,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);
 }
 
 /**
@@ -6203,6 +6251,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 01cd3be..13b6092 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2047,6 +2047,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;
@@ -2072,8 +2074,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;
@@ -2102,7 +2107,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;
@@ -2359,6 +2365,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);
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 02/15] libata-pmp: implement Port Multiplier support
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
  2007-07-01 10:54 ` [PATCH 01/15] libata-pmp: update ata_eh_reset() for PMP Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 03/15] libata-pmp: hook PMP support and enable it Tejun Heo
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Implement Port Multiplier support.  To support PMP, a LLDD has to
supply ops->pmp_read() and pmp_write().  If non-null, ->pmp_attach and
->pmp_detach are called on PMP attach and detach, respectively.

->pmp_read/write() can be called while the port is frozen, so they
must be implemented by polling.  This patch supplies several helpers
to ease ->pmp_read/write() implementation.

Also, irq_handler and error_handler must be PMP aware.  Most of PMP
aware EH can be done by calling ata_pmp_do_eh() with appropriate
methods.  PMP EH uses separate set of reset methods and this patch
implements standard prereset, hardreset and postreset methods.

This patch only implements PMP support.  The next patch will integrate
PMP into the reset of libata and thus enable PMP support.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/Makefile      |    3 +-
 drivers/ata/libata-core.c |   11 +
 drivers/ata/libata-pmp.c  | 1157 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/ata/libata.h      |    5 +
 include/linux/libata.h    |   19 +
 5 files changed, 1194 insertions(+), 1 deletions(-)
 create mode 100644 drivers/ata/libata-pmp.c

diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 8149c68..19512c3 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -68,5 +68,6 @@ obj-$(CONFIG_ATA_GENERIC)	+= ata_generic.o
 # Should be last libata driver
 obj-$(CONFIG_PATA_LEGACY)	+= pata_legacy.o
 
-libata-objs	:= libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+libata-objs	:= libata-core.o libata-scsi.o libata-sff.o libata-eh.o \
+		   libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)	+= libata-acpi.o
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 2d960da..4e86164 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3801,6 +3801,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 	{ "SAMSUNG CD-ROM SN-124","N001",	ATA_HORKAGE_NODMA },
 	{ "Seagate STT20000A", NULL,		ATA_HORKAGE_NODMA },
 	{ "IOMEGA  ZIP 250       ATAPI", NULL,	ATA_HORKAGE_NODMA }, /* temporary fix */
+	/* Odd clown on sil3726/4726 PMPs */
+	{ "Config  Disk",	NULL,		ATA_HORKAGE_NODMA |
+						ATA_HORKAGE_SKIP_PM },
 
 	/* Weird ATAPI devices */
 	{ "TORiSAN DVD-ROM DRD-N216", NULL,	ATA_HORKAGE_MAX_SEC_128 },
@@ -7046,6 +7049,14 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf);
+EXPORT_SYMBOL_GPL(sata_pmp_read_val);
+EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf);
+EXPORT_SYMBOL_GPL(sata_pmp_std_prereset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_postreset);
+EXPORT_SYMBOL_GPL(sata_pmp_do_eh);
+
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 EXPORT_SYMBOL_GPL(ata_link_abort);
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
new file mode 100644
index 0000000..7c298e7
--- /dev/null
+++ b/drivers/ata/libata-pmp.c
@@ -0,0 +1,1157 @@
+/*
+ * libata-pmp.c - libata port multiplier support
+ *
+ * Copyright (c) 2007  SUSE Linux Products GmbH
+ * Copyright (c) 2007  Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include "libata.h"
+
+/**
+ *	sata_pmp_read - read PMP register
+ *	@link: link to read PMP register for
+ *	@reg: register to read
+ *	@r_val: resulting value
+ *
+ *	Wrapper around ap->ops->pmp_read to make it easier to call and
+ *	nomarlize error return value.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *pmp_dev = ap->link.device;
+	int rc;
+
+	might_sleep();
+
+	rc = ap->ops->pmp_read(pmp_dev, link->pmp, reg, r_val);
+	if (rc)
+		rc = -EIO;
+	return rc;
+}
+
+/**
+ *	sata_pmp_write - write PMP register
+ *	@link: link to write PMP register for
+ *	@reg: register to write
+ *	@r_val: value to write
+ *
+ *	Wrapper around ap->ops->pmp_write to make it easier to call
+ *	and nomarlize error return value.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_write(struct ata_link *link, int reg, u32 val)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *pmp_dev = ap->link.device;
+	int rc;
+
+	might_sleep();
+
+	rc = ap->ops->pmp_write(pmp_dev, link->pmp, reg, val);
+	if (rc)
+		rc = -EIO;
+	return rc;
+}
+
+/**
+ *	sata_pmp_read_init_tf - initialize TF for PMP read
+ *	@tf: taskfile to initialize
+ *	@dev: PMP dev
+ *	@pmp: port multiplier port number
+ *	@reg: register to read
+ *
+ *	Initialize @tf for PMP read command.
+ *
+ *	LOCKING:
+ *	None.
+ */
+void sata_pmp_read_init_tf(struct ata_taskfile *tf,
+			   struct ata_device *dev, int pmp, int reg)
+{
+	ata_tf_init(dev, tf);
+	tf->command = ATA_CMD_PMP_READ;
+	tf->protocol = ATA_PROT_NODATA;
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->feature = reg;
+	tf->device = pmp;
+}
+
+/**
+ *	sata_pmp_read_val - extract PMP read result from TF
+ *	@tf: target TF
+ *
+ *	Determine PMP read result from @tf.
+ *
+ *	LOCKING:
+ *	None.
+ */
+u32 sata_pmp_read_val(const struct ata_taskfile *tf)
+{
+	return tf->nsect | tf->lbal << 8 | tf->lbam << 16 | tf->lbah << 24;
+}
+
+/**
+ *	sata_pmp_read_init_tf - initialize TF for PMP write
+ *	@tf: taskfile to initialize
+ *	@dev: PMP dev
+ *	@pmp: port multiplier port number
+ *	@reg: register to read
+ *	@val: value to write
+ *
+ *	Initialize @tf for PMP write command.
+ *
+ *	LOCKING:
+ *	None.
+ */
+void sata_pmp_write_init_tf(struct ata_taskfile *tf,
+			    struct ata_device *dev, int pmp, int reg, u32 val)
+{
+	ata_tf_init(dev, tf);
+	tf->command = ATA_CMD_PMP_WRITE;
+	tf->protocol = ATA_PROT_NODATA;
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->feature = reg;
+	tf->device = pmp;
+	tf->nsect = val & 0xff;
+	tf->lbal = (val >> 8) & 0xff;
+	tf->lbam = (val >> 16) & 0xff;
+	tf->lbah = (val >> 24) & 0xff;
+}
+
+/**
+ *	sata_pmp_scr_read - read PSCR
+ *	@link: ATA link to read PSCR for
+ *	@reg: PSCR to read
+ *	@r_val: resulting value
+ *
+ *	Read PSCR @reg into @r_val for @link, to be called from
+ *	ata_scr_read().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
+{
+	if (reg > SATA_PMP_PSCR_CONTROL)
+		return -EINVAL;
+
+	return sata_pmp_read(link, reg, r_val);
+}
+
+/**
+ *	sata_pmp_scr_write - write PSCR
+ *	@link: ATA link to write PSCR for
+ *	@reg: PSCR to write
+ *	@val: value to be written
+ *
+ *	Write @val to PSCR @reg for @link, to be called from
+ *	ata_scr_write() and ata_scr_write_flush().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
+{
+	if (reg > SATA_PMP_PSCR_CONTROL)
+		return -EINVAL;
+
+	return sata_pmp_write(link, reg, val);
+}
+
+/**
+ *	sata_pmp_std_prereset - prepare PMP link for reset
+ *	@link: link to be reset
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	@link is about to be reset.  Initialize it.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline)
+{
+	struct ata_eh_context *ehc = &link->eh_context;
+	const unsigned long *timing = sata_ehc_deb_timing(ehc);
+	int rc;
+
+	/* force HRST? */
+	if (link->flags & ATA_LFLAG_NO_SRST)
+		ehc->i.action |= ATA_EH_HARDRESET;
+
+	/* handle link resume */
+	if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+	    (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+		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;
+
+	/* resume link */
+	rc = sata_link_resume(link, timing, deadline);
+	if (rc) {
+		/* phy resume failed */
+		ata_link_printk(link, KERN_WARNING, "failed to resume link "
+				"for reset (errno=%d)\n", rc);
+		return rc;
+	}
+
+	/* clear SError bits including .X which blocks the port when set */
+	rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"failed to clear SError (errno=%d)\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ *	sata_pmp_std_hardreset - standard hardreset method for PMP link
+ *	@link: link to be reset
+ *	@class: resulting class of attached device
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	Hardreset PMP port @link.  Note that this function doesn't
+ *	wait for BSY clearance.  There simply isn't a generic way to
+ *	wait the event.  Instead, this function return -EAGAIN thus
+ *	telling libata-EH to followup with softreset.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+			   unsigned long deadline)
+{
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+	u32 tmp;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	/* do hardreset */
+	rc = sata_link_hardreset(link, timing, deadline);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"COMRESET failed (errno=%d)\n", rc);
+		goto out;
+	}
+
+	/* clear SError bits including .X which blocks the port when set */
+	rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR, "failed to clear SError "
+				"during hardreset (errno=%d)\n", rc);
+		goto out;
+	}
+
+	/* if device is present, follow up with srst to wait for !BSY */
+	if (ata_link_online(link))
+		rc = -EAGAIN;
+ out:
+	/* if SCR isn't accessible, we need to reset the PMP */
+	if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp))
+		rc = -ERESTART;
+
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+/**
+ *	ata_std_postreset - standard postreset method for PMP link
+ *	@link: the target ata_link
+ *	@classes: classes of attached devices
+ *
+ *	This function is invoked after a successful reset.  Note that
+ *	the device might have been reset more than once using
+ *	different reset methods before postreset is invoked.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class)
+{
+	u32 serror;
+
+	DPRINTK("ENTER\n");
+
+	/* clear SError */
+	if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+		sata_scr_write(link, SCR_ERROR, serror);
+
+	/* print link status */
+	sata_print_link_status(link);
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	sata_pmp_read_gscr - read GSCR block of SATA PMP
+ *	@dev: PMP device
+ *	@gscr: buffer to read GSCR block into
+ *
+ *	Read selected PMP GSCRs from the PMP at @dev.  This will serve
+ *	as configuration and identification info for the PMP.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
+{
+	static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
+		int reg = gscr_to_read[i];
+
+		rc = sata_pmp_read(dev->link, reg, &gscr[reg]);
+		if (rc) {
+			ata_dev_printk(dev, KERN_ERR, "failed to read "
+				       "PMP GSCR[%d] (errno=%d)\n", reg, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static const char *sata_pmp_spec_rev_str(const u32 *gscr)
+{
+	u32 rev = gscr[SATA_PMP_GSCR_REV];
+
+	if (rev & (1 << 2))
+		return "1.1";
+	if (rev & (1 << 1))
+		return "1.0";
+	return "<unknown>";
+}
+
+static int sata_pmp_configure(struct ata_device *dev, int print_info)
+{
+	struct ata_port *ap = dev->link->ap;
+	u32 *gscr = dev->gscr;
+	const char *reason;
+	int nr_ports, rc;
+
+	nr_ports = sata_pmp_gscr_ports(gscr);
+
+	if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
+		rc = -EINVAL;
+		reason = "invalid nr_ports";
+		goto fail;
+	}
+
+	rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, SERR_PHYRDY_CHG);
+	if (rc) {
+		reason = "failed to write GSCR_ERROR_EN";
+		goto fail;
+	}
+
+	if (ap->flags & ATA_FLAG_SDB_NOTIFY &&
+	    gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY) {
+		gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+
+		rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
+				    gscr[SATA_PMP_GSCR_FEAT_EN]);
+		if (rc) {
+			reason = "failed to write GSCR_FEAT_EN";
+			goto fail;
+		}
+	}
+
+	if (print_info) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
+			       "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+			       sata_pmp_spec_rev_str(gscr),
+			       sata_pmp_gscr_vendor(gscr),
+			       sata_pmp_gscr_devid(gscr),
+			       sata_pmp_gscr_rev(gscr),
+			       nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+			       gscr[SATA_PMP_GSCR_FEAT]);
+
+		if (!(ap->flags & ATA_FLAG_SDB_NOTIFY))
+			ata_dev_printk(dev, KERN_INFO,
+				"SDB_NOTIFY not supported on host port, "
+				"hotplug won't work on\n         fan-out "
+				"ports. Use warm-plug instead.\n");
+	}
+
+	return 0;
+
+ fail:
+	ata_dev_printk(dev, KERN_ERR,
+		       "failed to configure Port Multiplier (%s)\n", reason);
+	return rc;
+}
+
+static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+{
+	struct ata_link *pmp_link = ap->pmp_link;
+	int i;
+
+	if (!pmp_link) {
+		pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
+				   GFP_NOIO);
+		if (!pmp_link)
+			return -ENOMEM;
+
+		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+			ata_link_init(ap, &pmp_link[i], i);
+
+		ap->pmp_link = pmp_link;
+	}
+
+	for (i = 0; i < nr_ports; i++) {
+		struct ata_link *link = &pmp_link[i];
+		struct ata_eh_context *ehc = &link->eh_context;
+
+		link->flags = 0;
+		ehc->i.probe_mask |= 1;
+		ehc->i.action |= ATA_EH_SOFTRESET;
+		ehc->i.flags |= ATA_EHI_RESUME_LINK;
+	}
+
+	return 0;
+}
+
+static void sata_pmp_quirks(struct ata_port *ap)
+{
+	u32 *gscr = ap->link.device->gscr;
+	u16 vendor = sata_pmp_gscr_vendor(gscr);
+	u16 devid = sata_pmp_gscr_devid(gscr);
+	struct ata_link *link;
+
+	if (vendor == 0x1095 && devid == 0x3726) {
+		/* sil3726 quirks */
+		ata_port_for_each_link(link, ap) {
+			/* SError.N need a kick in the ass to get working */
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+			/* class code report is unreliable */
+			if (link->pmp < 5)
+				link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+			/* port 5 is for SEMB device and it doesn't like SRST */
+			if (link->pmp == 5)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_SEMB;
+		}
+	} else if (vendor == 0x1095 && devid == 0x4723) {
+		/* sil4723 quirks */
+		ata_port_for_each_link(link, ap) {
+			/* SError.N need a kick in the ass to get working */
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+			/* class code report is unreliable */
+			if (link->pmp < 2)
+				link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+			/* the config device at port 2 locks up on SRST */
+			if (link->pmp == 2)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_ATA;
+		}
+	} else if (vendor == 0x1095 && devid == 0x4726) {
+		/* sil4726 quirks */
+		ata_port_for_each_link(link, ap) {
+			/* SError.N need a kick in the ass to get working */
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+			/* class code report is unreliable */
+			if (link->pmp < 5)
+				link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+			/* The config device, which can be either at
+			 * port 0 or 5, locks up on SRST.
+			 */
+			if (link->pmp == 0 || link->pmp == 5)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_ATA;
+
+			/* Port 6 is for SEMB device which doesn't
+			 * like SRST either.
+			 */
+			if (link->pmp == 6)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_SEMB;
+		}
+	} else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
+					devid == 0x5734 || devid == 0x5744)) {
+		/* sil5723/5744 quirks */
+
+		/* sil5723/5744 has either two or three downstream
+		 * ports depending on operation mode.  The last port
+		 * is empty if any actual IO device is available or
+		 * occupied by a pseudo configuration device
+		 * otherwise.  Don't try hard to recover it.
+		 */
+		ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+	}
+}
+
+/**
+ *	sata_pmp_attach - attach a SATA PMP device
+ *	@dev: SATA PMP device to attach
+ *
+ *	Configure and attach SATA PMP device @dev.  This function is
+ *	also responsible for allocating and initializing PMP links.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_attach(struct ata_device *dev)
+{
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
+	unsigned long flags;
+	struct ata_link *tlink;
+	int rc;
+
+	/* is it hanging off the right place? */
+	if (!(ap->flags & ATA_FLAG_PMP)) {
+		ata_dev_printk(dev, KERN_ERR,
+			       "host does not support Port Multiplier\n");
+		return -EINVAL;
+	}
+
+	if (!ata_is_host_link(link)) {
+		ata_dev_printk(dev, KERN_ERR,
+			       "Port Multipliers cannot be nested\n");
+		return -EINVAL;
+	}
+
+	if (dev->devno) {
+		ata_dev_printk(dev, KERN_ERR,
+			       "Port Multiplier must be the first device\n");
+		return -EINVAL;
+	}
+
+	WARN_ON(link->pmp != 0);
+	link->pmp = SATA_PMP_CTRL_PORT;
+
+	/* read GSCR block */
+	rc = sata_pmp_read_gscr(dev, dev->gscr);
+	if (rc)
+		goto fail;
+
+	/* config PMP */
+	rc = sata_pmp_configure(dev, 1);
+	if (rc)
+		goto fail;
+
+	rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
+	if (rc) {
+		ata_dev_printk(dev, KERN_INFO,
+			       "failed to initialize PMP links\n");
+		goto fail;
+	}
+
+	/* attach it */
+	spin_lock_irqsave(ap->lock, flags);
+	WARN_ON(ap->nr_pmp_links);
+	ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	sata_pmp_quirks(ap);
+
+	if (ap->ops->pmp_attach)
+		ap->ops->pmp_attach(ap);
+
+	ata_port_for_each_link(tlink, ap)
+		sata_link_init_spd_limit(tlink);
+
+	return 0;
+
+ fail:
+	link->pmp = 0;
+	return rc;
+}
+
+/**
+ *	sata_pmp_detach - detach a SATA PMP device
+ *	@dev: SATA PMP device to detach
+ *
+ *	Detach SATA PMP device @dev.  This function is also
+ *	responsible for deconfiguring PMP links.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+static void sata_pmp_detach(struct ata_device *dev)
+{
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
+	struct ata_link *tlink;
+	unsigned long flags;
+
+	ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+
+	WARN_ON(!ata_is_host_link(link) || dev->devno ||
+		link->pmp != SATA_PMP_CTRL_PORT);
+
+	if (ap->ops->pmp_detach)
+		ap->ops->pmp_detach(ap);
+
+	ata_port_for_each_link(tlink, ap)
+		ata_eh_detach_dev(tlink->device);
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->nr_pmp_links = 0;
+	link->pmp = 0;
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *	sata_pmp_same_pmp - does new GSCR matches the configured PMP?
+ *	@dev: PMP device to compare against
+ *	@new_gscr: GSCR block of the new device
+ *
+ *	Compare @new_gscr against @dev and determine whether @dev is
+ *	the PMP described by @new_gscr.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	1 if @dev matches @new_gscr, 0 otherwise.
+ */
+static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
+{
+	const u32 *old_gscr = dev->gscr;
+	u16 old_vendor, new_vendor, old_devid, new_devid;
+	int old_nr_ports, new_nr_ports;
+
+	old_vendor = sata_pmp_gscr_vendor(old_gscr);
+	new_vendor = sata_pmp_gscr_vendor(new_gscr);
+	old_devid = sata_pmp_gscr_devid(old_gscr);
+	new_devid = sata_pmp_gscr_devid(new_gscr);
+	old_nr_ports = sata_pmp_gscr_ports(old_gscr);
+	new_nr_ports = sata_pmp_gscr_ports(new_gscr);
+
+	if (old_vendor != new_vendor) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+			       "vendor mismatch '0x%x' != '0x%x'\n",
+			       old_vendor, new_vendor);
+		return 0;
+	}
+
+	if (old_devid != new_devid) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+			       "device ID mismatch '0x%x' != '0x%x'\n",
+			       old_devid, new_devid);
+		return 0;
+	}
+
+	if (old_nr_ports != new_nr_ports) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+			       "nr_ports mismatch '0x%x' != '0x%x'\n",
+			       old_nr_ports, new_nr_ports);
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ *	sata_pmp_revalidate - revalidate SATA PMP
+ *	@dev: PMP device to revalidate
+ *	@new_class: new class code
+ *
+ *	Re-read GSCR block and make sure @dev is still attached to the
+ *	port and properly configured.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
+{
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
+	u32 *gscr = (void *)ap->sector_buf;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
+
+	if (!ata_dev_enabled(dev)) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	/* wrong class? */
+	if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	/* read GSCR */
+	rc = sata_pmp_read_gscr(dev, gscr);
+	if (rc)
+		goto fail;
+
+	/* is the pmp still there? */
+	if (!sata_pmp_same_pmp(dev, gscr)) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
+
+	rc = sata_pmp_configure(dev, 0);
+	if (rc)
+		goto fail;
+
+	ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
+
+	DPRINTK("EXIT, rc=0\n");
+	return 0;
+
+ fail:
+	ata_dev_printk(dev, KERN_ERR,
+		       "PMP revalidation failed (errno=%d)\n", rc);
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+/**
+ *	sata_pmp_revalidate_quick - revalidate SATA PMP quickly
+ *	@dev: PMP device to revalidate
+ *
+ *	Make sure the attached PMP is accessible.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate_quick(struct ata_device *dev)
+{
+	u32 prod_id;
+	int rc;
+
+	rc = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
+	if (rc) {
+		ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID\n");
+		return rc;
+	}
+
+	if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
+		ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+		/* something weird is going on, request full PMP recovery */
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ *	sata_pmp_eh_recover_pmp - recover PMP
+ *	@ap: ATA port PMP is attached to
+ *	@prereset: prereset method (can be NULL)
+ *	@softreset: softreset method
+ *	@hardreset: hardreset method
+ *	@postreset: postreset method (can be NULL)
+ *
+ *	Recover PMP attached to @ap.  Recovery procedure is somewhat
+ *	similar to that of ata_eh_recover() except that reset should
+ *	always be performed in hard->soft sequence and recovery
+ *	failure results in PMP detachment.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+	struct ata_link *link = &ap->link;
+	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_device *dev = link->device;
+	int tries = ATA_EH_PMP_TRIES;
+	int detach = 0, rc = 0;
+	int reval_failed = 0;
+
+	DPRINTK("ENTER\n");
+
+	if (dev->flags & ATA_DFLAG_DETACH) {
+		detach = 1;
+		goto fail;
+	}
+
+ retry:
+	ehc->classes[0] = ATA_DEV_UNKNOWN;
+
+	if (ehc->i.action & ATA_EH_RESET_MASK) {
+		struct ata_link *tlink;
+
+		ata_eh_freeze_port(ap);
+
+		/* reset */
+		ehc->i.action = ATA_EH_HARDRESET;
+		rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
+				  postreset);
+		if (rc) {
+			ata_link_printk(link, KERN_ERR,
+					"failed to reset PMP, giving up\n");
+			goto fail;
+		}
+
+		ata_eh_thaw_port(ap);
+
+		/* PMP is reset, SErrors cannot be trusted, scan all */
+		ata_port_for_each_link(tlink, ap)
+			ata_ehi_schedule_probe(&tlink->eh_context.i);
+	}
+
+	/* If revalidation is requested, revalidate and reconfigure;
+	 * otherwise, do quick revalidation.
+	 */
+	if (ehc->i.action & ATA_EH_REVALIDATE)
+		rc = sata_pmp_revalidate(dev, ehc->classes[0]);
+	else
+		rc = sata_pmp_revalidate_quick(dev);
+
+	if (rc) {
+		tries--;
+
+		if (rc == -ENODEV) {
+			ehc->i.probe_mask |= 1;
+			detach = 1;
+			/* give it just two more chances */
+			tries = min(tries, 2);
+		}
+
+		if (tries) {
+			int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
+
+			/* consecutive revalidation failures? speed down */
+			if (reval_failed)
+				sata_down_spd_limit(link);
+			else
+				reval_failed = 1;
+
+			ata_dev_printk(dev, KERN_WARNING,
+				       "retrying hardreset%s\n",
+				       sleep ? " in 5 secs" : "");
+			if (sleep)
+				ssleep(5);
+			ehc->i.action |= ATA_EH_HARDRESET;
+			goto retry;
+		} else {
+			ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
+				       "after %d tries, giving up\n",
+				       ATA_EH_DEV_TRIES);
+			goto fail;
+		}
+	}
+
+	/* okay, PMP resurrected */
+	ehc->i.flags = 0;
+
+	DPRINTK("EXIT, rc=0\n");
+	return 0;
+
+ fail:
+	sata_pmp_detach(dev);
+	if (detach)
+		ata_eh_detach_dev(dev);
+	else
+		ata_dev_disable(dev);
+
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
+{
+	struct ata_link *link;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(ap->lock, flags);
+
+	ata_port_for_each_link(link, ap) {
+		if (!(link->flags & ATA_LFLAG_DISABLED))
+			continue;
+
+		spin_unlock_irqrestore(ap->lock, flags);
+
+		/* Some PMPs require hardreset sequence to get
+		 * SError.N working.
+		 */
+		if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) &&
+		    (link->eh_context.i.flags & ATA_EHI_RESUME_LINK))
+			sata_link_hardreset(link, sata_deb_timing_normal,
+					    jiffies + ATA_TMOUT_INTERNAL_QUICK);
+
+		/* unconditionally clear SError.N */
+		rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+		if (rc) {
+			ata_link_printk(link, KERN_ERR, "failed to clear "
+					"SError.N (errno=%d)\n", rc);
+			return rc;
+		}
+
+		spin_lock_irqsave(ap->lock, flags);
+	}
+
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	return 0;
+}
+
+static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
+{
+	struct ata_port *ap = link->ap;
+	unsigned long flags;
+
+	if (link_tries[link->pmp] && --link_tries[link->pmp])
+		return 1;
+
+	/* disable this link */
+	if (!(link->flags & ATA_LFLAG_DISABLED)) {
+		ata_link_printk(link, KERN_WARNING,
+			"failed to recover link after %d tries, disabling\n",
+			ATA_EH_PMP_LINK_TRIES);
+
+		spin_lock_irqsave(ap->lock, flags);
+		link->flags |= ATA_LFLAG_DISABLED;
+		spin_unlock_irqrestore(ap->lock, flags);
+	}
+
+	ata_dev_disable(link->device);
+	link->eh_context.i.action = 0;
+
+	return 0;
+}
+
+/**
+ *	sata_pmp_eh_recover - recover PMP-enabled port
+ *	@ap: ATA port to recover
+ *	@prereset: prereset method (can be NULL)
+ *	@softreset: softreset method
+ *	@hardreset: hardreset method
+ *	@postreset: postreset method (can be NULL)
+ *	@pmp_prereset: PMP prereset method (can be NULL)
+ *	@pmp_softreset: PMP softreset method (can be NULL)
+ *	@pmp_hardreset: PMP hardreset method (can be NULL)
+ *	@pmp_postreset: PMP postreset method (can be NULL)
+ *
+ *	Drive EH recovery operation for PMP enabled port @ap.  This
+ *	function recovers host and PMP ports with proper retrials and
+ *	fallbacks.  Actual recovery operations are performed using
+ *	ata_eh_recover() and sata_pmp_eh_recover_pmp().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+		ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+		ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+	int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
+	struct ata_link *pmp_link = &ap->link;
+	struct ata_device *pmp_dev = pmp_link->device;
+	struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+	struct ata_link *link;
+	struct ata_device *dev;
+	u32 gscr_error, sntf;
+	int cnt, rc;
+
+	pmp_tries = ATA_EH_PMP_TRIES;
+	ata_port_for_each_link(link, ap)
+		link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ retry:
+	/* PMP attached? */
+	if (!ap->nr_pmp_links) {
+		rc = ata_eh_recover(ap, prereset, softreset, hardreset,
+				    postreset, NULL);
+		if (rc) {
+			ata_link_for_each_dev(dev, &ap->link)
+				ata_dev_disable(dev);
+			return rc;
+		}
+
+		if (pmp_dev->class != ATA_DEV_PMP)
+			return 0;
+
+		/* new PMP online */
+		ata_port_for_each_link(link, ap)
+			link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+		/* fall through */
+	}
+
+	/* recover pmp */
+	rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset,
+				     postreset);
+	if (rc)
+		goto pmp_fail;
+
+	/* handle disabled links */
+	rc = sata_pmp_eh_handle_disabled_links(ap);
+	if (rc)
+		goto pmp_fail;
+
+	/* recover links */
+	rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset,
+			    pmp_postreset, &link);
+	if (rc)
+		goto link_fail;
+
+	/* Connection status might have changed while resetting other
+	 * links, check SATA_PMP_GSCR_ERROR before returning.
+	 */
+
+	/* clear SNotification */
+	rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+	if (rc == 0)
+		sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+	/* check GSCR_ERROR */
+	rc = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
+	if (rc) {
+		ata_dev_printk(pmp_dev, KERN_ERR,
+			       "failed to read PMP_GSCR_ERROR\n");
+		goto pmp_fail;
+	}
+
+	cnt = 0;
+	ata_port_for_each_link(link, ap) {
+		if (!(gscr_error & (1 << link->pmp)))
+			continue;
+
+		if (sata_pmp_handle_link_fail(link, link_tries)) {
+			ata_ehi_hotplugged(&link->eh_context.i);
+			cnt++;
+		} else {
+			ata_link_printk(link, KERN_WARNING,
+				"PHY status changed but maxed out on retries, "
+				"giving up\n");
+			ata_link_printk(link, KERN_WARNING,
+				"Manully issue scan to resume this link\n");
+		}
+	}
+
+	if (cnt) {
+		ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
+				"ports, repeating recovery\n");
+		goto retry;
+	}
+
+	return 0;
+
+ link_fail:
+	if (sata_pmp_handle_link_fail(link, link_tries)) {
+		pmp_ehc->i.action |= ATA_EH_HARDRESET;
+		goto retry;
+	}
+
+	/* fall through */
+ pmp_fail:
+	/* Control always ends up here after detaching PMP.  Shut up
+	 * and return if we're unloading.
+	 */
+	if (ap->pflags & ATA_PFLAG_UNLOADING)
+		return rc;
+
+	if (!ap->nr_pmp_links)
+		goto retry;
+
+	if (--pmp_tries) {
+		ata_port_printk(ap, KERN_WARNING,
+				"failed to recover PMP, retrying in 5 secs\n");
+		pmp_ehc->i.action |= ATA_EH_HARDRESET;
+		ssleep(5);
+		goto retry;
+	}
+
+	ata_port_printk(ap, KERN_ERR,
+			"failed to recover PMP after %d tries, giving up\n",
+			ATA_EH_PMP_TRIES);
+	sata_pmp_detach(pmp_dev);
+	ata_dev_disable(pmp_dev);
+
+	return rc;
+}
+
+/**
+ *	sata_pmp_do_eh - do standard error handling for PMP-enabled host
+ *	@ap: host port to handle error for
+ *	@prereset: prereset method (can be NULL)
+ *	@softreset: softreset method
+ *	@hardreset: hardreset method
+ *	@postreset: postreset method (can be NULL)
+ *	@pmp_prereset: PMP prereset method (can be NULL)
+ *	@pmp_softreset: PMP softreset method (can be NULL)
+ *	@pmp_hardreset: PMP hardreset method (can be NULL)
+ *	@pmp_postreset: PMP postreset method (can be NULL)
+ *
+ *	Perform standard error handling sequence for PMP-enabled host
+ *	@ap.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void sata_pmp_do_eh(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+		ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+		ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+	ata_eh_autopsy(ap);
+	ata_eh_report(ap);
+	sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset,
+			    pmp_prereset, pmp_softreset, pmp_hardreset,
+			    pmp_postreset);
+	ata_eh_finish(ap);
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 114b988..f774d9c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -150,6 +150,11 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
 extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
 
+/* libata-pmp.c */
+extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_attach(struct ata_device *dev);
+
 /* libata-eh.c */
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 09959a7..c12312f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -939,6 +939,25 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
 #endif /* CONFIG_PCI */
 
 /*
+ * PMP
+ */
+extern void sata_pmp_read_init_tf(struct ata_taskfile *tf,
+				  struct ata_device *dev, int pmp, int reg);
+extern u32 sata_pmp_read_val(const struct ata_taskfile *tf);
+extern void sata_pmp_write_init_tf(struct ata_taskfile *tf,
+				   struct ata_device *dev,
+				   int pmp, int reg, u32 val);
+extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline);
+extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+				  unsigned long deadline);
+extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class);
+extern void sata_pmp_do_eh(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+		ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+		ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset);
+
+/*
  * EH
  */
 extern void ata_eng_timeout(struct ata_port *ap);
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 07/15] sata_sil24: separate out sil24_do_softreset()
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (4 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 09/15] sata_sil24: implement PORT_RST Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-12 20:26   ` Jeff Garzik
  2007-07-01 10:54 ` [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Separate out sil24_do_softreset() which takes @pmp as its last
argument.  This will be used to implement sil24_pmp_softreset().

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/sata_sil24.c |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 8273b8e..24d3d6b 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -587,8 +587,8 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
 	return rc;
 }
 
-static int sil24_softreset(struct ata_link *link, unsigned int *class,
-			   unsigned long deadline)
+static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
+			      int pmp, unsigned long deadline)
 {
 	struct ata_port *ap = link->ap;
 	unsigned long timeout_msec = 0;
@@ -615,7 +615,8 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
 		timeout_msec = jiffies_to_msecs(deadline - jiffies);
 
 	ata_tf_init(link->device, &tf);	/* doesn't really matter */
-	rc = sil24_exec_polled_cmd(ap, 0, &tf, 0, PRB_CTRL_SRST, timeout_msec);
+	rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+				   timeout_msec);
 	if (rc == -EBUSY) {
 		reason = "timeout";
 		goto err;
@@ -639,6 +640,12 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
 	return -EIO;
 }
 
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
+			   unsigned long deadline)
+{
+	return sil24_do_softreset(link, class, 0, deadline);
+}
+
 static int sil24_hardreset(struct ata_link *link, unsigned int *class,
 			   unsigned long deadline)
 {
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 08/15] sata_sil24: implement PMP support
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (6 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 05/15] sata_sil24: replace sil24_update_tf() with sil24_read_tf() Tejun Heo
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Implement PMP support.  sil24 supports full FIS-switching.  However,
it has a PMP DMA CS errata which requires port-wide resetting if
commands are outstanding to three or more devices when an error occurs
on one of them.

ATAPI commands often result in CHECK SENSE and it's crucial to not
reset them before fetching sense data.  Unfortunately, ATAPI CHECK
SENSE causes a lot of problem if command is outstanding to any other
device usually resulting in port-wide reset.  So, sata_sil24
implements sil24_qc_defer() which guarantees ATAPI command is run by
itself.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/sata_sil24.c |  233 +++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 212 insertions(+), 21 deletions(-)

diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 24d3d6b..5f07d7e 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -30,7 +30,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_sil24"
-#define DRV_VERSION	"0.9"
+#define DRV_VERSION	"1.0"
 
 /*
  * Port request block (PRB) 32 bytes
@@ -168,7 +168,7 @@ enum {
 
 	DEF_PORT_IRQ		= PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
 				  PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
-				  PORT_IRQ_UNK_FIS,
+				  PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
 
 	/* bits[27:16] are unmasked (raw) */
 	PORT_IRQ_RAW_SHIFT	= 16,
@@ -237,7 +237,8 @@ enum {
 	/* host flags */
 	SIL24_COMMON_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-				  ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA,
+				  ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+				  ATA_FLAG_PMP | ATA_FLAG_SDB_NOTIFY,
 	SIL24_COMMON_LFLAGS	= ATA_LFLAG_SKIP_D2H_BSY,
 	SIL24_FLAG_PCIX_IRQ_WOC	= (1 << 24), /* IRQ loss errata on PCI-X */
 
@@ -329,9 +330,14 @@ static u8 sil24_check_status(struct ata_port *ap);
 static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
 static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static int sil24_qc_defer(struct ata_queued_cmd *qc);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static void sil24_irq_clear(struct ata_port *ap);
+static void sil24_pmp_attach(struct ata_port *ap);
+static void sil24_pmp_detach(struct ata_port *ap);
+static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val);
+static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val);
 static void sil24_freeze(struct ata_port *ap);
 static void sil24_thaw(struct ata_port *ap);
 static void sil24_error_handler(struct ata_port *ap);
@@ -340,6 +346,7 @@ static int sil24_port_start(struct ata_port *ap);
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 #ifdef CONFIG_PM
 static int sil24_pci_device_resume(struct pci_dev *pdev);
+static int sil24_port_resume(struct ata_port *ap);
 #endif
 
 static const struct pci_device_id sil24_pci_tbl[] = {
@@ -394,7 +401,7 @@ static const struct ata_port_operations sil24_ops = {
 
 	.tf_read		= sil24_tf_read,
 
-	.qc_defer		= ata_std_qc_defer,
+	.qc_defer		= sil24_qc_defer,
 	.qc_prep		= sil24_qc_prep,
 	.qc_issue		= sil24_qc_issue,
 
@@ -405,12 +412,21 @@ static const struct ata_port_operations sil24_ops = {
 	.scr_read		= sil24_scr_read,
 	.scr_write		= sil24_scr_write,
 
+	.pmp_attach		= sil24_pmp_attach,
+	.pmp_detach		= sil24_pmp_detach,
+	.pmp_read		= sil24_pmp_read,
+	.pmp_write		= sil24_pmp_write,
+
 	.freeze			= sil24_freeze,
 	.thaw			= sil24_thaw,
 	.error_handler		= sil24_error_handler,
 	.post_internal_cmd	= sil24_post_internal_cmd,
 
 	.port_start		= sil24_port_start,
+
+#ifdef CONFIG_PM
+	.port_resume		= sil24_port_resume,
+#endif
 };
 
 /*
@@ -524,11 +540,40 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 	*tf = pp->tf;
 }
 
+static void sil24_config_pmp(struct ata_port *ap, int attached)
+{
+	void __iomem *port = ap->ioaddr.cmd_addr;
+
+	if (attached)
+		writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);
+	else
+		writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);
+}
+
+static void sil24_clear_pmp(struct ata_port *ap)
+{
+	void __iomem *port = ap->ioaddr.cmd_addr;
+	int i;
+
+	writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+
+	for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+		void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;
+
+		writel(0, pmp_base + PORT_PMP_STATUS);
+		writel(0, pmp_base + PORT_PMP_QACTIVE);
+	}
+}
+
 static int sil24_init_port(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	u32 tmp;
 
+	/* clear PMP error status */
+	if (ap->nr_pmp_links)
+		sil24_clear_pmp(ap);
+
 	writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
 	ata_wait_register(port + PORT_CTRL_STAT,
 			  PORT_CS_INIT, PORT_CS_INIT, 10, 100);
@@ -643,7 +688,7 @@ static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
 static int sil24_softreset(struct ata_link *link, unsigned int *class,
 			   unsigned long deadline)
 {
-	return sil24_do_softreset(link, class, 0, deadline);
+	return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
 }
 
 static int sil24_hardreset(struct ata_link *link, unsigned int *class,
@@ -711,6 +756,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
 	}
 }
 
+static int sil24_qc_defer(struct ata_queued_cmd *qc)
+{
+	struct ata_link *link = qc->dev->link;
+	struct ata_port *ap = link->ap;
+	u8 prot = qc->tf.protocol;
+	int is_atapi = (prot == ATA_PROT_ATAPI ||
+			prot == ATA_PROT_ATAPI_NODATA ||
+			prot == ATA_PROT_ATAPI_DMA);
+
+	/* ATAPI commands completing with CHECK_SENSE cause various
+	 * weird problems if other commands are active.  PMP DMA CS
+	 * errata doesn't cover all and HSM violation occurs even with
+	 * only one other device active.  Always run an ATAPI command
+	 * by itself.
+	 */
+	if (unlikely(ap->excl_link)) {
+		if (link == ap->excl_link) {
+			if (ap->nr_active_links)
+				return ATA_DEFER_PORT;
+			qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+		} else
+			return ATA_DEFER_PORT;
+	} else if (unlikely(is_atapi)) {
+		ap->excl_link = link;
+		if (ap->nr_active_links)
+			return ATA_DEFER_PORT;
+		qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+	}
+
+	return ata_std_qc_defer(qc);
+}
+
 static void sil24_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
@@ -783,6 +860,65 @@ static void sil24_irq_clear(struct ata_port *ap)
 	/* unused */
 }
 
+static void sil24_pmp_attach(struct ata_port *ap)
+{
+	sil24_config_pmp(ap, 1);
+	sil24_init_port(ap);
+}
+
+static void sil24_pmp_detach(struct ata_port *ap)
+{
+	sil24_init_port(ap);
+	sil24_config_pmp(ap, 0);
+}
+
+static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val)
+{
+	struct ata_port *ap = dev->link->ap;
+	struct ata_taskfile tf;
+	int rc;
+
+	sata_pmp_read_init_tf(&tf, dev, pmp, reg);
+	rc = sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0,
+				   SATA_PMP_SCR_TIMEOUT);
+	if (rc == 0) {
+		sil24_read_tf(ap, 0, &tf);
+		*r_val = sata_pmp_read_val(&tf);
+	}
+	return rc;
+}
+
+static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val)
+{
+	struct ata_port *ap = dev->link->ap;
+	struct ata_taskfile tf;
+
+	sata_pmp_write_init_tf(&tf, dev, pmp, reg, val);
+	return sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0,
+				     SATA_PMP_SCR_TIMEOUT);
+}
+
+static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
+			       unsigned long deadline)
+{
+	return sil24_do_softreset(link, class, link->pmp, deadline);
+}
+
+static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
+			       unsigned long deadline)
+{
+	int rc;
+
+	rc = sil24_init_port(link->ap);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"hardreset failed (port not ready)\n");
+		return rc;
+	}
+
+	return sata_pmp_std_hardreset(link, class, deadline);
+}
+
 static void sil24_freeze(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
@@ -810,8 +946,10 @@ static void sil24_error_intr(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
-	struct ata_eh_info *ehi = &ap->link.eh_info;
-	int freeze = 0;
+	struct ata_queued_cmd *qc = NULL;
+	struct ata_link *link;
+	struct ata_eh_info *ehi;
+	int abort = 0, freeze = 0;
 	u32 irq_stat;
 
 	/* on error, we need to clear IRQ explicitly */
@@ -819,10 +957,17 @@ static void sil24_error_intr(struct ata_port *ap)
 	writel(irq_stat, port + PORT_IRQ_STAT);
 
 	/* first, analyze and record host port events */
+	link = &ap->link;
+	ehi = &link->eh_info;
 	ata_ehi_clear_desc(ehi);
 
 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x ", irq_stat);
 
+	if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+		ata_ehi_push_desc(ehi, "<SDB notify> ");
+		sata_async_notification(ap);
+	}
+
 	if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
 		ata_ehi_hotplugged(ehi);
 		ata_ehi_push_desc(ehi, "<%s> ",
@@ -842,8 +987,43 @@ static void sil24_error_intr(struct ata_port *ap)
 	if (irq_stat & PORT_IRQ_ERROR) {
 		struct sil24_cerr_info *ci = NULL;
 		unsigned int err_mask = 0, action = 0;
-		struct ata_queued_cmd *qc;
-		u32 cerr;
+		u32 context, cerr;
+		int pmp;
+
+		abort = 1;
+
+		/* DMA Context Switch Failure in Port Multiplier Mode
+		 * errata.  If we have active commands to 3 or more
+		 * devices, any error condition on active devices can
+		 * corrupt DMA context switching.
+		 */
+		if (ap->nr_active_links >= 3) {
+			ehi->err_mask |= AC_ERR_OTHER;
+			ehi->action |= ATA_EH_HARDRESET;
+			ata_ehi_push_desc(ehi, "<PMP DMA CS errata> ");
+			freeze = 1;
+		}
+
+		/* find out the offending link and qc */
+		if (ap->nr_pmp_links) {
+			context = readl(port + PORT_CONTEXT);
+			pmp = (context >> 5) & 0xf;
+
+			if (pmp < ap->nr_pmp_links) {
+				link = &ap->pmp_link[pmp];
+				ehi = &link->eh_info;
+				qc = ata_qc_from_tag(ap, link->active_tag);
+
+				ata_ehi_clear_desc(ehi);
+				ata_ehi_push_desc(ehi, "irq_stat 0x%08x ",
+						  irq_stat);
+			} else {
+				err_mask |= AC_ERR_HSM;
+				action |= ATA_EH_HARDRESET;
+				freeze = 1;
+			}
+		} else
+			qc = ata_qc_from_tag(ap, link->active_tag);
 
 		/* analyze CMD_ERR */
 		cerr = readl(port + PORT_CMD_ERR);
@@ -862,7 +1042,6 @@ static void sil24_error_intr(struct ata_port *ap)
 		}
 
 		/* record error info */
-		qc = ata_qc_from_tag(ap, ap->link.active_tag);
 		if (qc) {
 			sil24_read_tf(ap, qc->tag, &pp->tf);
 			qc->err_mask |= err_mask;
@@ -870,13 +1049,21 @@ static void sil24_error_intr(struct ata_port *ap)
 			ehi->err_mask |= err_mask;
 
 		ehi->action |= action;
+
+		/* if PMP, resume */
+		if (ap->nr_pmp_links)
+			writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
 	}
 
 	/* freeze or abort */
 	if (freeze)
 		ata_port_freeze(ap);
-	else
-		ata_port_abort(ap);
+	else if (abort) {
+		if (qc)
+			ata_link_abort(qc->dev->link);
+		else
+			ata_port_abort(ap);
+	}
 }
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
@@ -961,16 +1148,14 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
 
 static void sil24_error_handler(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
-
-	if (sil24_init_port(ap)) {
+	if (sil24_init_port(ap))
 		ata_eh_freeze_port(ap);
-		ehc->i.action |= ATA_EH_HARDRESET;
-	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
-		  ata_std_postreset);
+	sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+		       ata_std_postreset, sata_pmp_std_prereset,
+		       sil24_pmp_softreset, sil24_pmp_hardreset,
+		       sata_pmp_std_postreset);
 }
 
 static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -978,8 +1163,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
 	struct ata_port *ap = qc->ap;
 
 	/* make DMA engine forget about the failed command */
-	if (qc->flags & ATA_QCFLAG_FAILED)
-		sil24_init_port(ap);
+	if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+		ata_eh_freeze_port(ap);
 }
 
 static int sil24_port_start(struct ata_port *ap)
@@ -1177,6 +1362,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
 
 	return 0;
 }
+
+static int sil24_port_resume(struct ata_port *ap)
+{
+	sil24_config_pmp(ap, ap->nr_pmp_links);
+	return 0;
+}
 #endif
 
 static int __init sil24_init(void)
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd()
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (5 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 07/15] sata_sil24: separate out sil24_do_softreset() Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-12 20:25   ` Jeff Garzik
  2007-07-01 10:54 ` [PATCH 08/15] sata_sil24: implement PMP support Tejun Heo
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Separate out sil24_exec_polled_cmd() from sil24_softreset().  This
will be used to implement sil24_pmp_read/write().

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/sata_sil24.c |   78 +++++++++++++++++++++++++++++++++------------
 1 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 65dbfd4..8273b8e 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -540,17 +540,61 @@ static int sil24_init_port(struct ata_port *ap)
 	return 0;
 }
 
-static int sil24_softreset(struct ata_link *link, unsigned int *class,
-			   unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+				 const struct ata_taskfile *tf,
+				 int is_cmd, u32 ctrl,
+				 unsigned long timeout_msec)
 {
-	struct ata_port *ap = link->ap;
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
 	dma_addr_t paddr = pp->cmd_block_dma;
+	u32 irq_enabled, irq_mask, irq_stat;
+	int rc;
+
+	prb->ctrl = cpu_to_le16(ctrl);
+	ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+	/* temporarily plug completion and error interrupts */
+	irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+	writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+	irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+				     10, timeout_msec);
+
+	writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+	irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+	if (irq_stat & PORT_IRQ_COMPLETE)
+		rc = 0;
+	else {
+		/* force port into known state */
+		sil24_init_port(ap);
+
+		if (irq_stat & PORT_IRQ_ERROR)
+			rc = -EIO;
+		else
+			rc = -EBUSY;
+	}
+
+	/* restore IRQ enabled */
+	writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+	return rc;
+}
+
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
+			   unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
+	unsigned long timeout_msec = 0;
 	struct ata_taskfile tf;
-	u32 mask, irq_stat;
 	const char *reason;
+	int rc;
 
 	DPRINTK("ENTER\n");
 
@@ -567,24 +611,16 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
 	}
 
 	/* do SRST */
-	prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
-	prb->fis[1] = 0; /* no PMP yet */
+	if (time_after(deadline, jiffies))
+		timeout_msec = jiffies_to_msecs(deadline - jiffies);
 
-	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
-	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
-	mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
-				     100, jiffies_to_msecs(deadline - jiffies));
-
-	writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
-	irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
-	if (!(irq_stat & PORT_IRQ_COMPLETE)) {
-		if (irq_stat & PORT_IRQ_ERROR)
-			reason = "SRST command error";
-		else
-			reason = "timeout";
+	ata_tf_init(link->device, &tf);	/* doesn't really matter */
+	rc = sil24_exec_polled_cmd(ap, 0, &tf, 0, PRB_CTRL_SRST, timeout_msec);
+	if (rc == -EBUSY) {
+		reason = "timeout";
+		goto err;
+	} else if (rc) {
+		reason = "SRST command error";
 		goto err;
 	}
 
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 05/15] sata_sil24: replace sil24_update_tf() with sil24_read_tf()
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (7 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 08/15] sata_sil24: implement PMP support Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 14/15] ahci: separate out ahci_do_softreset() Tejun Heo
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Replace sil24_update_tf() to sil24_read_tf() which reads TF into
passed int result TF argument and can read TFs of PMP links.  This
will be used by PMP support.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/sata_sil24.c |   23 ++++++++++++++---------
 1 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index e2a41ff..65dbfd4 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -468,15 +468,15 @@ static void sil24_dev_config(struct ata_device *dev)
 		writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
 }
 
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
 {
-	struct sil24_port_priv *pp = ap->private_data;
 	void __iomem *port = ap->ioaddr.cmd_addr;
-	struct sil24_prb __iomem *prb = port;
+	struct sil24_prb __iomem *prb;
 	u8 fis[6 * 4];
 
-	memcpy_fromio(fis, prb->fis, 6 * 4);
-	ata_tf_from_fis(fis, &pp->tf);
+	prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+	memcpy_fromio(fis, prb->fis, sizeof(fis));
+	ata_tf_from_fis(fis, tf);
 }
 
 static u8 sil24_check_status(struct ata_port *ap)
@@ -548,6 +548,7 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
 	dma_addr_t paddr = pp->cmd_block_dma;
+	struct ata_taskfile tf;
 	u32 mask, irq_stat;
 	const char *reason;
 
@@ -587,8 +588,8 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
 		goto err;
 	}
 
-	sil24_update_tf(ap);
-	*class = ata_dev_classify(&pp->tf);
+	sil24_read_tf(ap, 0, &tf);
+	*class = ata_dev_classify(&tf);
 
 	if (*class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
@@ -765,6 +766,7 @@ static void sil24_thaw(struct ata_port *ap)
 static void sil24_error_intr(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
 	struct ata_eh_info *ehi = &ap->link.eh_info;
 	int freeze = 0;
 	u32 irq_stat;
@@ -819,7 +821,7 @@ static void sil24_error_intr(struct ata_port *ap)
 		/* record error info */
 		qc = ata_qc_from_tag(ap, ap->link.active_tag);
 		if (qc) {
-			sil24_update_tf(ap);
+			sil24_read_tf(ap, qc->tag, &pp->tf);
 			qc->err_mask |= err_mask;
 		} else
 			ehi->err_mask |= err_mask;
@@ -836,8 +838,11 @@ static void sil24_error_intr(struct ata_port *ap)
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
 {
+	struct ata_port *ap = qc->ap;
+	struct sil24_port_priv *pp = ap->private_data;
+
 	if (qc->flags & ATA_QCFLAG_RESULT_TF)
-		sil24_update_tf(qc->ap);
+		sil24_read_tf(ap, qc->tag, &pp->tf);
 }
 
 static inline void sil24_host_intr(struct ata_port *ap)
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 09/15] sata_sil24: implement PORT_RST
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (3 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 07/15] sata_sil24: separate out sil24_do_softreset() Tejun Heo
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

As DEV_RST (hardreset) sometimes fail to recover the controller
(especially after PMP DMA CS errata).  In such cases, perform PORT_RST
prior to DEV_RST.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/sata_sil24.c |   93 ++++++++++++++++++++++++++++++++++-----------
 1 files changed, 70 insertions(+), 23 deletions(-)

diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5f07d7e..2574d87 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -323,6 +323,7 @@ struct sil24_port_priv {
 	union sil24_cmd_block *cmd_block;	/* 32 cmd blocks */
 	dma_addr_t cmd_block_dma;		/* DMA base addr for them */
 	struct ata_taskfile tf;			/* Cached taskfile registers */
+	int do_port_rst;
 };
 
 static void sil24_dev_config(struct ata_device *dev);
@@ -540,6 +541,31 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 	*tf = pp->tf;
 }
 
+static void sil24_config_port(struct ata_port *ap)
+{
+	void __iomem *port = ap->ioaddr.cmd_addr;
+
+	/* configure IRQ WoC */
+	if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+	else
+		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+	/* zero error counters. */
+	writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+	writel(0x8000, port + PORT_CRC_ERR_THRESH);
+	writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+	writel(0x0000, port + PORT_DECODE_ERR_CNT);
+	writel(0x0000, port + PORT_CRC_ERR_CNT);
+	writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+	/* always use 64bit activation */
+	writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+	/* clear port multiplier enable and resume bits */
+	writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+}
+
 static void sil24_config_pmp(struct ata_port *ap, int attached)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
@@ -568,6 +594,7 @@ static void sil24_clear_pmp(struct ata_port *ap)
 static int sil24_init_port(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
 	u32 tmp;
 
 	/* clear PMP error status */
@@ -580,8 +607,12 @@ static int sil24_init_port(struct ata_port *ap)
 	tmp = ata_wait_register(port + PORT_CTRL_STAT,
 				PORT_CS_RDY, 0, 10, 100);
 
-	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+		pp->do_port_rst = 1;
+		ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
 		return -EIO;
+	}
+
 	return 0;
 }
 
@@ -696,10 +727,34 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
 {
 	struct ata_port *ap = link->ap;
 	void __iomem *port = ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
+	int did_port_rst = 0;
 	const char *reason;
 	int tout_msec, rc;
 	u32 tmp;
 
+ retry:
+	/* Sometimes, DEV_RST is not enough to recover the controller.
+	 * This happens often after PM DMA CS errata.
+	 */
+	if (pp->do_port_rst) {
+		ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+				"state, performing PORT_RST\n");
+
+		writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+		msleep(10);
+		writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+		ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+				  10, 5000);
+
+		/* restore port configuration */
+		sil24_config_port(ap);
+		sil24_config_pmp(ap, ap->nr_pmp_links);
+
+		pp->do_port_rst = 0;
+		did_port_rst = 1;
+	}
+
 	/* sil24 does the right thing(tm) without any protection */
 	sata_set_spd(link);
 
@@ -736,6 +791,11 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
 	return -EAGAIN;
 
  err:
+	if (!did_port_rst) {
+		pp->do_port_rst = 1;
+		goto retry;
+	}
+
 	ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
 	return -EIO;
 }
@@ -1001,6 +1061,7 @@ static void sil24_error_intr(struct ata_port *ap)
 			ehi->err_mask |= AC_ERR_OTHER;
 			ehi->action |= ATA_EH_HARDRESET;
 			ata_ehi_push_desc(ehi, "<PMP DMA CS errata> ");
+			pp->do_port_rst = 1;
 			freeze = 1;
 		}
 
@@ -1148,6 +1209,8 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
 
 static void sil24_error_handler(struct ata_port *ap)
 {
+	struct sil24_port_priv *pp = ap->private_data;
+
 	if (sil24_init_port(ap))
 		ata_eh_freeze_port(ap);
 
@@ -1156,6 +1219,8 @@ static void sil24_error_handler(struct ata_port *ap)
 		       ata_std_postreset, sata_pmp_std_prereset,
 		       sil24_pmp_softreset, sil24_pmp_hardreset,
 		       sata_pmp_std_postreset);
+
+	pp->do_port_rst = 0;
 }
 
 static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -1202,7 +1267,6 @@ static int sil24_port_start(struct ata_port *ap)
 static void sil24_init_controller(struct ata_host *host)
 {
 	void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
-	void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
 	u32 tmp;
 	int i;
 
@@ -1214,7 +1278,8 @@ static void sil24_init_controller(struct ata_host *host)
 
 	/* init ports */
 	for (i = 0; i < host->n_ports; i++) {
-		void __iomem *port = port_base + i * PORT_REGS_SIZE;
+		struct ata_port *ap = host->ports[i];
+		void __iomem *port = ap->ioaddr.cmd_addr;
 
 		/* Initial PHY setting */
 		writel(0x20c, port + PORT_PHY_CFG);
@@ -1231,26 +1296,8 @@ static void sil24_init_controller(struct ata_host *host)
 				           "failed to clear port RST\n");
 		}
 
-		/* Configure IRQ WoC */
-		if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
-			writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
-		else
-			writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
-		/* Zero error counters. */
-		writel(0x8000, port + PORT_DECODE_ERR_THRESH);
-		writel(0x8000, port + PORT_CRC_ERR_THRESH);
-		writel(0x8000, port + PORT_HSHK_ERR_THRESH);
-		writel(0x0000, port + PORT_DECODE_ERR_CNT);
-		writel(0x0000, port + PORT_CRC_ERR_CNT);
-		writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
-		/* Always use 64bit activation */
-		writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
-		/* Clear port multiplier enable and resume bits */
-		writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
-		       port + PORT_CTRL_CLR);
+		/* configure port */
+		sil24_config_port(ap);
 	}
 
 	/* Turn on interrupts */
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 10/15] libata-pmp: implement qc_defer for command switching PMP support
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (9 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 14/15] ahci: separate out ahci_do_softreset() Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 11/15] ahci: use deadline instead of fixed timeout for 1st FIS for SRST Tejun Heo
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Implement sata_pmp_qc_defer_cmd_switch() - standard qc_defer for
command switching PMP support.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/libata-core.c |    1 +
 drivers/ata/libata-pmp.c  |   30 ++++++++++++++++++++++++++++++
 include/linux/libata.h    |    1 +
 3 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 151b585..568e750 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -7098,6 +7098,7 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
 EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf);
 EXPORT_SYMBOL_GPL(sata_pmp_read_val);
 EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf);
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index d6d05b2..7053abc 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -70,6 +70,36 @@ static int sata_pmp_write(struct ata_link *link, int reg, u32 val)
 }
 
 /**
+ *	sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
+ *	@qc: ATA command in question
+ *
+ *	A host which has command switching PMP support cannot issue
+ *	commands to multiple links simultaneously.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ *	RETURNS:
+ *	ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
+{
+	struct ata_link *link = qc->dev->link;
+	struct ata_port *ap = link->ap;
+
+	if (ap->excl_link == NULL || ap->excl_link == link) {
+		if (ap->nr_active_links == 0 || ata_link_active(link)) {
+			qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+			return ata_std_qc_defer(qc);
+		}
+
+		ap->excl_link = link;
+	}
+
+	return ATA_DEFER_PORT;
+}
+
+/**
  *	sata_pmp_read_init_tf - initialize TF for PMP read
  *	@tf: taskfile to initialize
  *	@dev: PMP dev
diff --git a/include/linux/libata.h b/include/linux/libata.h
index c12312f..6d9f17e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -941,6 +941,7 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
 /*
  * PMP
  */
+extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc);
 extern void sata_pmp_read_init_tf(struct ata_taskfile *tf,
 				  struct ata_device *dev, int pmp, int reg);
 extern u32 sata_pmp_read_val(const struct ata_taskfile *tf);
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 12/15] ahci: separate out ahci_kick_engine()
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (11 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 11/15] ahci: use deadline instead of fixed timeout for 1st FIS for SRST Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-12 20:26   ` Jeff Garzik
  2007-07-01 10:54 ` [PATCH 13/15] ahci: separate out ahci_exec_polled_cmd() Tejun Heo
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Separate out stop_engine - CLO - start_engine sequence from
ahci_softreset() and ahci_clo() into ahci_reset_engine() and use it in
ahci_softreset() and ahci_post_internal_cmd().  The function will also
be used to prepare for and clean up after PMP register access
commands.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/ahci.c |   69 +++++++++++++++++++++++++++-------------------------
 1 files changed, 36 insertions(+), 33 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 9af91ac..9d24dad 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -923,25 +923,49 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
 	struct ahci_host_priv *hpriv = ap->host->private_data;
 	u32 tmp;
+	int busy, rc;
 
-	if (!(hpriv->cap & HOST_CAP_CLO))
-		return -EOPNOTSUPP;
+	/* do we need to kick the port? */
+	busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+	if (!busy && !force_restart)
+		return 0;
+
+	/* stop engine */
+	rc = ahci_stop_engine(ap);
+	if (rc)
+		goto out_restart;
+
+	/* need to do CLO? */
+	if (!busy) {
+		rc = 0;
+		goto out_restart;
+	}
+
+	if (!(hpriv->cap & HOST_CAP_CLO)) {
+		rc = -EOPNOTSUPP;
+		goto out_restart;
+	}
 
+	/* perform CLO */
 	tmp = readl(port_mmio + PORT_CMD);
 	tmp |= PORT_CMD_CLO;
 	writel(tmp, port_mmio + PORT_CMD);
 
+	rc = 0;
 	tmp = ata_wait_register(port_mmio + PORT_CMD,
 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
 	if (tmp & PORT_CMD_CLO)
-		return -EIO;
+		rc = -EIO;
 
-	return 0;
+	/* restart engine */
+ out_restart:
+	ahci_start_engine(ap);
+	return rc;
 }
 
 static int ahci_softreset(struct ata_link *link, unsigned int *class,
@@ -967,27 +991,10 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	}
 
 	/* prepare for SRST (AHCI-1.1 10.4.1) */
-	rc = ahci_stop_engine(ap);
-	if (rc) {
-		reason = "failed to stop engine";
-		goto fail_restart;
-	}
-
-	/* check BUSY/DRQ, perform Command List Override if necessary */
-	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
-		rc = ahci_clo(ap);
-
-		if (rc == -EOPNOTSUPP) {
-			reason = "port busy but CLO unavailable";
-			goto fail_restart;
-		} else if (rc) {
-			reason = "port busy but CLO failed";
-			goto fail_restart;
-		}
-	}
-
-	/* restart engine */
-	ahci_start_engine(ap);
+	rc = ahci_kick_engine(ap, 1);
+	if (rc)
+		ata_link_printk(link, KERN_WARNING,
+				"failed to reset engine (errno=%d)", rc);
 
 	ata_tf_init(link->device, &tf);
 	fis = pp->cmd_tbl;
@@ -1046,8 +1053,6 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	DPRINTK("EXIT, class=%u\n", *class);
 	return 0;
 
- fail_restart:
-	ahci_start_engine(ap);
  fail:
 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
 	return rc;
@@ -1497,11 +1502,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 
-	if (qc->flags & ATA_QCFLAG_FAILED) {
-		/* make DMA engine forget about the failed command */
-		ahci_stop_engine(ap);
-		ahci_start_engine(ap);
-	}
+	/* make DMA engine forget about the failed command */
+	if (qc->flags & ATA_QCFLAG_FAILED)
+		ahci_kick_engine(ap, 1);
 }
 
 #ifdef CONFIG_PM
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 11/15] ahci: use deadline instead of fixed timeout for 1st FIS for SRST
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (10 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 10/15] libata-pmp: implement qc_defer for command switching PMP support Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-01 10:54 ` [PATCH 12/15] ahci: separate out ahci_kick_engine() Tejun Heo
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Use deadline instead of fixed timeout for 1st FIS for SRST to improve
robustness of SRST.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/ahci.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 88cfac0..9af91ac 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -952,6 +952,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	void __iomem *port_mmio = ahci_port_base(ap);
 	const u32 cmd_fis_len = 5; /* five dwords */
 	const char *reason = NULL;
+	unsigned long now, msecs;
 	struct ata_taskfile tf;
 	u32 tmp;
 	u8 *fis;
@@ -992,6 +993,11 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	fis = pp->cmd_tbl;
 
 	/* issue the first D2H Register FIS */
+	msecs = 0;
+	now = jiffies;
+	if (time_after(now, deadline))
+		msecs = jiffies_to_msecs(deadline - now);
+
 	ahci_fill_cmd_slot(pp, 0,
 			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
 
@@ -1000,7 +1006,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 
 	writel(1, port_mmio + PORT_CMD_ISSUE);
 
-	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
+	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs);
 	if (tmp & 0x1) {
 		rc = -EIO;
 		reason = "1st FIS failed";
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 14/15] ahci: separate out ahci_do_softreset()
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (8 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 05/15] sata_sil24: replace sil24_update_tf() with sil24_read_tf() Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-12 20:26   ` Jeff Garzik
  2007-07-01 10:54 ` [PATCH 10/15] libata-pmp: implement qc_defer for command switching PMP support Tejun Heo
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Separate out ahci_do_softreset() which takes @pmp as its last
argument.  This will be used to implement ahci_pmp_softreset().

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/ahci.c |   19 +++++++++++++++----
 1 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index d25cee8..94bb767 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -998,8 +998,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
 	return 0;
 }
 
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
-			  unsigned long deadline)
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+			     int pmp, unsigned long deadline)
 {
 	struct ata_port *ap = link->ap;
 	const char *reason = NULL;
@@ -1030,7 +1030,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 		msecs = jiffies_to_msecs(deadline - now);
 
 	tf.ctl |= ATA_SRST;
-	if (ahci_exec_polled_cmd(ap, 0, &tf, 0,
+	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
 		rc = -EIO;
 		reason = "1st FIS failed";
@@ -1042,7 +1042,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 
 	/* issue the second D2H Register FIS */
 	tf.ctl &= ~ATA_SRST;
-	ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0);
+	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
 
 	/* spec mandates ">= 2ms" before checking status.
 	 * We wait 150ms, because that was the magic delay used for
@@ -1070,6 +1070,17 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	return rc;
 }
 
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+			  unsigned long deadline)
+{
+	int pmp = 0;
+
+	if (link->ap->flags & ATA_FLAG_PMP)
+		pmp = SATA_PMP_CTRL_PORT;
+
+	return ahci_do_softreset(link, class, pmp, deadline);
+}
+
 static int ahci_hardreset(struct ata_link *link, unsigned int *class,
 			  unsigned long deadline)
 {
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 13/15] ahci: separate out ahci_exec_polled_cmd()
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (12 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 12/15] ahci: separate out ahci_kick_engine() Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-12 20:26   ` Jeff Garzik
  2007-07-01 10:54 ` [PATCH 15/15] ahci: implement PMP support Tejun Heo
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Separate out ahci_exec_polled_cmd() from ahci_softreset().  This will
be used to implement ahci_pmp_read/write().  ahci_exec_polled_cmd()
performs reset_engine before returning if the command fails (times
out).  This is to improve robustness.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/ahci.c |   54 +++++++++++++++++++++++++++++++--------------------
 1 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 9d24dad..d25cee8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -968,18 +968,43 @@ static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 	return rc;
 }
 
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+				struct ata_taskfile *tf, int is_cmd, u16 flags,
+				unsigned long timeout_msec)
+{
+	const u32 cmd_fis_len = 5; /* five dwords */
+	struct ahci_port_priv *pp = ap->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u8 *fis = pp->cmd_tbl;
+	u32 tmp;
+
+	/* prep the command */
+	ata_tf_to_fis(tf, pmp, is_cmd, fis);
+	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+	/* issue & wait */
+	writel(1, port_mmio + PORT_CMD_ISSUE);
+
+	if (timeout_msec) {
+		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+					1, timeout_msec);
+		if (tmp & 0x1) {
+			ahci_kick_engine(ap, 1);
+			return -EBUSY;
+		}
+	} else
+		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
+
+	return 0;
+}
+
 static int ahci_softreset(struct ata_link *link, unsigned int *class,
 			  unsigned long deadline)
 {
 	struct ata_port *ap = link->ap;
-	struct ahci_port_priv *pp = ap->private_data;
-	void __iomem *port_mmio = ahci_port_base(ap);
-	const u32 cmd_fis_len = 5; /* five dwords */
 	const char *reason = NULL;
 	unsigned long now, msecs;
 	struct ata_taskfile tf;
-	u32 tmp;
-	u8 *fis;
 	int rc;
 
 	DPRINTK("ENTER\n");
@@ -997,7 +1022,6 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 				"failed to reset engine (errno=%d)", rc);
 
 	ata_tf_init(link->device, &tf);
-	fis = pp->cmd_tbl;
 
 	/* issue the first D2H Register FIS */
 	msecs = 0;
@@ -1005,16 +1029,9 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	if (time_after(now, deadline))
 		msecs = jiffies_to_msecs(deadline - now);
 
-	ahci_fill_cmd_slot(pp, 0,
-			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
-
 	tf.ctl |= ATA_SRST;
-	ata_tf_to_fis(&tf, 0, 0, fis);
-
-	writel(1, port_mmio + PORT_CMD_ISSUE);
-
-	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs);
-	if (tmp & 0x1) {
+	if (ahci_exec_polled_cmd(ap, 0, &tf, 0,
+				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
 		rc = -EIO;
 		reason = "1st FIS failed";
 		goto fail;
@@ -1024,13 +1041,8 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
 	msleep(1);
 
 	/* issue the second D2H Register FIS */
-	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
 	tf.ctl &= ~ATA_SRST;
-	ata_tf_to_fis(&tf, 0, 0, fis);
-
-	writel(1, port_mmio + PORT_CMD_ISSUE);
-	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
+	ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0);
 
 	/* spec mandates ">= 2ms" before checking status.
 	 * We wait 150ms, because that was the magic delay used for
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 15/15] ahci: implement PMP support
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (13 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 13/15] ahci: separate out ahci_exec_polled_cmd() Tejun Heo
@ 2007-07-01 10:54 ` Tejun Heo
  2007-07-03  7:39 ` [PATCHSET 4/4] implement PMP support, take 4 Jim Paris
  2007-07-12 20:27 ` Jeff Garzik
  16 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-01 10:54 UTC (permalink / raw)
  To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo

Implement AHCI PMP support.  ahci only supports command based
switching.  Also, for some reason, NCQ over PMP doesn't work now.
Other than that, everything works.

Tested on ICH9R, JMB360/363 + SIMG3726, 4726 and 5744.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Forrest Zhao <forrest.zhao@gmail.com>
---
 drivers/ata/ahci.c |  230 +++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 185 insertions(+), 45 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 94bb767..bb55720 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"ahci"
-#define DRV_VERSION	"2.2"
+#define DRV_VERSION	"3.0"
 
 
 enum {
@@ -96,6 +96,7 @@ enum {
 
 	/* HOST_CAP bits */
 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
+	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
@@ -143,7 +144,8 @@ enum {
 				  PORT_IRQ_IF_ERR |
 				  PORT_IRQ_CONNECT |
 				  PORT_IRQ_PHYRDY |
-				  PORT_IRQ_UNK_FIS,
+				  PORT_IRQ_UNK_FIS |
+				  PORT_IRQ_BAD_PMP,
 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
 				  PORT_IRQ_TF_ERR |
 				  PORT_IRQ_HBUS_DATA_ERR,
@@ -153,6 +155,7 @@ enum {
 
 	/* PORT_CMD bits */
 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
+	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
@@ -226,6 +229,10 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static u8 ahci_check_status(struct ata_port *ap);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
+static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val);
+static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val);
 static void ahci_error_handler(struct ata_port *ap);
 static void ahci_vt8251_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -267,7 +274,7 @@ static const struct ata_port_operations ahci_ops = {
 
 	.tf_read		= ahci_tf_read,
 
-	.qc_defer		= ata_std_qc_defer,
+	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
@@ -284,6 +291,11 @@ static const struct ata_port_operations ahci_ops = {
 	.error_handler		= ahci_error_handler,
 	.post_internal_cmd	= ahci_post_internal_cmd,
 
+	.pmp_attach		= ahci_pmp_attach,
+	.pmp_detach		= ahci_pmp_detach,
+	.pmp_read		= ahci_pmp_read,
+	.pmp_write		= ahci_pmp_write,
+
 #ifdef CONFIG_PM
 	.port_suspend		= ahci_port_suspend,
 	.port_resume		= ahci_port_resume,
@@ -302,7 +314,7 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 
 	.tf_read		= ahci_tf_read,
 
-	.qc_defer		= ata_std_qc_defer,
+	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
@@ -319,6 +331,11 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 	.error_handler		= ahci_vt8251_error_handler,
 	.post_internal_cmd	= ahci_post_internal_cmd,
 
+	.pmp_attach		= ahci_pmp_attach,
+	.pmp_detach		= ahci_pmp_detach,
+	.pmp_read		= ahci_pmp_read,
+	.pmp_write		= ahci_pmp_write,
+
 #ifdef CONFIG_PM
 	.port_suspend		= ahci_port_suspend,
 	.port_resume		= ahci_port_resume,
@@ -1105,7 +1122,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
 
 	if (rc == 0 && ata_link_online(link))
 		*class = ahci_dev_classify(ap);
-	if (*class == ATA_DEV_UNKNOWN)
+	if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
 
 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -1160,6 +1177,12 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class)
 	}
 }
 
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+			      unsigned long deadline)
+{
+	return ahci_do_softreset(link, class, link->pmp, deadline);
+}
+
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = ap->ioaddr.cmd_addr;
@@ -1218,7 +1241,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 	 */
 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-	ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
+	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
 	if (is_atapi) {
 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1231,7 +1254,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 	/*
 	 * Fill in command slot information.
 	 */
-	opts = cmd_fis_len | n_elem << 16;
+	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
 	if (qc->tf.flags & ATA_TFLAG_WRITE)
 		opts |= AHCI_CMD_WRITE;
 	if (is_atapi)
@@ -1243,66 +1266,85 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 {
 	struct ahci_port_priv *pp = ap->private_data;
-	struct ata_eh_info *ehi = &ap->link.eh_info;
-	unsigned int err_mask = 0, action = 0;
-	struct ata_queued_cmd *qc;
+	struct ata_eh_info *host_ehi = &ap->link.eh_info;
+	struct ata_link *link = NULL;
+	struct ata_queued_cmd *active_qc;
+	struct ata_eh_info *active_ehi;
 	u32 serror;
 
-	ata_ehi_clear_desc(ehi);
+	/* determine active link */
+	ata_port_for_each_link(link, ap)
+		if (ata_link_active(link))
+			break;
+	if (!link)
+		link = &ap->link;
+
+	active_qc = ata_qc_from_tag(ap, link->active_tag);
+	active_ehi = &link->eh_info;
+
+	/* record irq stat */
+	ata_ehi_clear_desc(host_ehi);
+	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x ", irq_stat);
 
 	/* AHCI needs SError cleared; otherwise, it might lock up */
 	ahci_scr_read(ap, SCR_ERROR, &serror);
 	ahci_scr_write(ap, SCR_ERROR, serror);
-
-	/* analyze @irq_stat */
-	ata_ehi_push_desc(ehi, "irq_stat 0x%08x ", irq_stat);
+	host_ehi->serror |= serror;
 
 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
 	if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
 		irq_stat &= ~PORT_IRQ_IF_ERR;
 
 	if (irq_stat & PORT_IRQ_TF_ERR) {
-		err_mask |= AC_ERR_DEV;
+		/* If qc is active, charge it; otherwise, the active
+		 * link.  There's no active qc on NCQ errors.  It will
+		 * be determined by EH by reading log page 10h.
+		 */
+		if (active_qc)
+			active_qc->err_mask |= AC_ERR_DEV;
+		else
+			active_ehi->err_mask |= AC_ERR_DEV;
+
 		if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
-			serror &= ~SERR_INTERNAL;
+			host_ehi->serror &= ~SERR_INTERNAL;
+	}
+
+	if (irq_stat & PORT_IRQ_UNK_FIS) {
+		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+
+		active_ehi->err_mask |= AC_ERR_HSM;
+		active_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(active_ehi,
+				  "<unknown FIS %08x %08x %08x %08x> " ,
+				  unk[0], unk[1], unk[2], unk[3]);
+	}
+
+	if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+		active_ehi->err_mask |= AC_ERR_HSM;
+		active_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(active_ehi, "<incorrect PMP> ");
 	}
 
 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
-		err_mask |= AC_ERR_HOST_BUS;
-		action |= ATA_EH_SOFTRESET;
+		host_ehi->err_mask |= AC_ERR_HOST_BUS;
+		host_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(host_ehi, "<host bus error> ");
 	}
 
 	if (irq_stat & PORT_IRQ_IF_ERR) {
-		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi, "<interface fatal error> ");
+		host_ehi->err_mask |= AC_ERR_ATA_BUS;
+		host_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(host_ehi, "<interface fatal error> ");
 	}
 
 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
-		ata_ehi_hotplugged(ehi);
-		ata_ehi_push_desc(ehi, "<%s> ", irq_stat & PORT_IRQ_CONNECT ?
+		ata_ehi_hotplugged(host_ehi);
+		ata_ehi_push_desc(host_ehi, "<%s> ",
+			irq_stat & PORT_IRQ_CONNECT ?
 			"connection status changed" : "PHY RDY changed");
 	}
 
-	if (irq_stat & PORT_IRQ_UNK_FIS) {
-		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
-		err_mask |= AC_ERR_HSM;
-		action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi, "<unknown FIS %08x %08x %08x %08x> ",
-				  unk[0], unk[1], unk[2], unk[3]);
-	}
-
 	/* okay, let's hand over to EH */
-	ehi->serror |= serror;
-	ehi->action |= action;
-
-	qc = ata_qc_from_tag(ap, ap->link.active_tag);
-	if (qc)
-		qc->err_mask |= err_mask;
-	else
-		ehi->err_mask |= err_mask;
-
 	if (irq_stat & PORT_IRQ_FREEZE)
 		ata_port_freeze(ap);
 	else
@@ -1320,6 +1362,9 @@ static void ahci_port_intr(struct ata_port *ap)
 	status = readl(port_mmio + PORT_IRQ_STAT);
 	writel(status, port_mmio + PORT_IRQ_STAT);
 
+	if (status & PORT_IRQ_SDB_FIS)
+		sata_async_notification(ap);
+
 	if (unlikely(status & PORT_IRQ_ERROR)) {
 		ahci_error_intr(ap, status);
 		return;
@@ -1491,8 +1536,11 @@ static void ahci_thaw(struct ata_port *ap)
 	writel(tmp, port_mmio + PORT_IRQ_STAT);
 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
 
-	/* turn IRQ back on */
-	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+	/* turn IRQ back on, ignore BAD_PMP if PMP isn't attached */
+	tmp = DEF_PORT_IRQ;
+	if (!ap->nr_pmp_links)
+		tmp &= ~PORT_IRQ_BAD_PMP;
+	writel(tmp, port_mmio + PORT_IRQ_MASK);
 }
 
 static void ahci_error_handler(struct ata_port *ap)
@@ -1504,8 +1552,10 @@ static void ahci_error_handler(struct ata_port *ap)
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
-		  ahci_postreset);
+	sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
+		       ahci_hardreset, ahci_postreset,
+		       sata_pmp_std_prereset, ahci_pmp_softreset,
+		       sata_pmp_std_hardreset, sata_pmp_std_postreset);
 }
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
@@ -1530,6 +1580,85 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 		ahci_kick_engine(ap, 1);
 }
 
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	unsigned long flags;
+	u32 cmd;
+
+	cmd = readl(port_mmio + PORT_CMD);
+	cmd |= PORT_CMD_PMP;
+	writel(cmd, port_mmio + PORT_CMD);
+
+	/* FIXME: For some reason, NCQ on PMP doesn't work well on
+	 * ahci.  It works as long as only one command is in flight.
+	 * BAD_PMP, IF_ERR and device errors are reported the moment
+	 * another command grows the queue depth.
+	 *
+	 * It's not certain who's to blame yet.  The behavior is
+	 * consistent on any combination of ich9r, jmb36x + sil3726,
+	 * 4726 and 5744 + several different NCQ capable drives from
+	 * different vendors.  It could be a common flaw in those Port
+	 * Multipliers or a bug in this driver.
+	 */
+	if (hpriv->cap & HOST_CAP_NCQ) {
+		spin_lock_irqsave(ap->lock, flags);
+		ata_port_printk(ap, KERN_INFO,
+			"ahci: NCQ is currently not supported with PMP\n");
+		ap->flags &= ~ATA_FLAG_NCQ;
+		spin_unlock_irqrestore(ap->lock, flags);
+	}
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	unsigned long flags;
+	u32 cmd;
+
+	cmd = readl(port_mmio + PORT_CMD);
+	cmd &= ~PORT_CMD_PMP;
+	writel(cmd, port_mmio + PORT_CMD);
+
+	if (hpriv->cap & HOST_CAP_NCQ) {
+		spin_lock_irqsave(ap->lock, flags);
+		ap->flags |= ATA_FLAG_NCQ;
+		spin_unlock_irqrestore(ap->lock, flags);
+	}
+}
+
+static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val)
+{
+	struct ata_port *ap = dev->link->ap;
+	struct ata_taskfile tf;
+	int rc;
+
+	ahci_kick_engine(ap, 0);
+
+	sata_pmp_read_init_tf(&tf, dev, pmp, reg);
+	rc = ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0,
+				  SATA_PMP_SCR_TIMEOUT);
+	if (rc == 0) {
+		ahci_tf_read(ap, &tf);
+		*r_val = sata_pmp_read_val(&tf);
+	}
+	return rc;
+}
+
+static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val)
+{
+	struct ata_port *ap = dev->link->ap;
+	struct ata_taskfile tf;
+
+	ahci_kick_engine(ap, 0);
+
+	sata_pmp_write_init_tf(&tf, dev, pmp, reg, val);
+	return ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0,
+				    SATA_PMP_SCR_TIMEOUT);
+}
+
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
@@ -1552,6 +1681,11 @@ static int ahci_port_resume(struct ata_port *ap)
 	ahci_power_up(ap);
 	ahci_start_port(ap);
 
+	if (ap->nr_pmp_links)
+		ahci_pmp_attach(ap);
+	else
+		ahci_pmp_detach(ap);
+
 	return 0;
 }
 
@@ -1809,6 +1943,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (hpriv->cap & HOST_CAP_NCQ)
 		pi.flags |= ATA_FLAG_NCQ;
 
+	if (hpriv->cap & HOST_CAP_PMP)
+		pi.flags |= ATA_FLAG_PMP;
+
+	if (hpriv->cap & HOST_CAP_SNTF)
+		pi.flags |= ATA_FLAG_SDB_NOTIFY;
+
 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
 	if (!host)
 		return -ENOMEM;
-- 
1.5.0.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCHSET 4/4] implement PMP support, take 4
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (14 preceding siblings ...)
  2007-07-01 10:54 ` [PATCH 15/15] ahci: implement PMP support Tejun Heo
@ 2007-07-03  7:39 ` Jim Paris
  2007-07-03  9:34   ` Tejun Heo
  2007-07-12 20:27 ` Jeff Garzik
  16 siblings, 1 reply; 28+ messages in thread
From: Jim Paris @ 2007-07-03  7:39 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Hello, all.
> 
> his is the fourth take of libata-pmp patchset.  This patchset contains
> 15 patches and implements PMP support.

Hi Tejun,

Thanks once again.  2.6.22-rc6 + libata-tj-2.6.22-rc6-20070702 seems
to be working fine on my system (SiI3124 PCI-X + two SiI4726, plus
other non-PMP stuff).  The libata portions of the boot logs are
attached below.

There are errors with ata1.05 and ata2.05.  I guess those are the
SiI4726 management ports that were just ignored in the last take of
PMP.  The EH on those causes a boot delay, but it's pretty short.

> * Sil4726 is a bit too quirky.  Without the first fan-out port
>   occupied, the thing acts really weirdly.  As long as the first port
>   is occupied, it works okay.  This is reportedly fixed by new
>   firmware.  I tried to update the firmware but installing 3124 driver
>   on Windows was just too difficult for me and I gave up after thirty
>   painful minutes.  Anyone up for testing?

I'll test the 4726 behavior with pulling disks etc including the first
port.  I'll also search to see if I can find a Windows machine to
update the firmware and let you know how things change.

There's a 4726 firmware update utility for Linux available:
  http://www.siliconimage.com/support/downloadresults.aspx?pid=74
It's closed source, but I wonder how it is supposed to work.  It seems
to just probe /dev/sd* and read the first sector.  Maybe it wants that
management port to be exposed as a SCSI device?

-jim

[   50.891895] libata version 3.00 loaded.
[   50.984511] sata_sil24 0000:01:00.0: version 1.0
[   50.985526] scsi0 : sata_sil24
[   50.985631] scsi1 : sata_sil24
[   50.985722] ata1: SATA max UDMA/100 cmd 0xffffc20000328000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[   50.985786] ata2: SATA max UDMA/100 cmd 0xffffc2000032a000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[   53.187373] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 0)
[   53.331253] ata1.15: Port Multiplier 1.1, 0x1095:0x4726 r0, 6 ports, feat 0x9/0xb
[   53.443184] ata1.00: hard resetting link
[   54.006777] ata1.00: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   54.022765] ata1.01: hard resetting link
[   54.666304] ata1.01: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   54.682292] ata1.02: hard resetting link
[   55.293855] ata1.02: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   55.309843] ata1.03: hard resetting link
[   55.937393] ata1.03: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   55.953381] ata1.04: hard resetting link
[   56.580932] ata1.04: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   56.580980] ata1.05: hard resetting link
[   57.144528] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[   57.180320] ata1.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   57.180371] ata1.00: 586072368 sectors, multi 16: LBA48 NCQ (depth 31/32)
[   57.238586] ata1.00: configured for UDMA/100
[   57.323623] ata1.01: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   57.323670] ata1.01: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   57.381887] ata1.01: configured for UDMA/100
[   57.411186] ata1.02: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   57.411232] ata1.02: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   57.469450] ata1.02: configured for UDMA/100
[   57.499841] ata1.03: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   57.499888] ata1.03: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   57.558108] ata1.03: configured for UDMA/100
[   57.589327] ata1.04: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   57.589374] ata1.04: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   57.647596] ata1.04: configured for UDMA/100
[   57.647758] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[   57.647805] ata1: failed to recover some devices, retrying in 5 secs
[   62.649282] ata1.05: hard resetting link
[   63.212886] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[   63.314995] ata1.00: configured for UDMA/100
[   63.433306] ata1.01: configured for UDMA/100
[   63.537472] ata1.02: configured for UDMA/100
[   63.642810] ata1.03: configured for UDMA/100
[   63.748971] ata1.04: configured for UDMA/100
[   63.749131] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[   63.764490] ata1.05: limiting SATA link speed to 1.5 Gbps
[   63.764537] ata1.05: limiting speed to UDMA7:PIO5
[   63.764582] ata1: failed to recover some devices, retrying in 5 secs
[   68.764898] ata1.05: hard resetting link
[   69.392458] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[   69.392621] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[   69.392668] ata1: failed to recover some devices, retrying in 5 secs
[   74.392865] ata1.05: hard resetting link
[   74.956471] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[   74.972460] ata1: EH pending after completion, repeating EH (cnt=4)
[   75.100368] ata1: EH complete
[   77.298095] ata2: SATA link up 3.0 Gbps (SStatus 123 SControl 0)
[   77.441977] ata2.15: Port Multiplier 1.1, 0x1095:0x4726 r0, 6 ports, feat 0x9/0xb
[   77.553906] ata2.00: hard resetting link
[   78.117501] ata2.00: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   78.133489] ata2.01: hard resetting link
[   78.761040] ata2.01: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   78.785022] ata2.02: hard resetting link
[   79.412573] ata2.02: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   79.428561] ata2.03: hard resetting link
[   80.040123] ata2.03: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   80.056111] ata2.04: hard resetting link
[   80.667674] ata2.04: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[   80.667721] ata2.05: hard resetting link
[   81.231270] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[   81.262866] ata2.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   81.262913] ata2.00: 586072368 sectors, multi 16: LBA48 NCQ (depth 31/32)
[   81.321132] ata2.00: configured for UDMA/100
[   81.354521] ata2.01: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   81.354568] ata2.01: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   81.412788] ata2.01: configured for UDMA/100
[   81.445410] ata2.02: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   81.445457] ata2.02: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   81.503678] ata2.02: configured for UDMA/100
[   81.536857] ata2.03: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   81.536903] ata2.03: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   81.595123] ata2.03: configured for UDMA/100
[   81.627705] ata2.04: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[   81.627751] ata2.04: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[   81.685971] ata2.04: configured for UDMA/100
[   81.686132] ata2.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[   81.686178] ata2: failed to recover some devices, retrying in 5 secs
[   86.688055] ata2.05: hard resetting link
[   87.251661] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[   87.364235] ata2.00: configured for UDMA/100
[   87.472510] ata2.01: configured for UDMA/100
[   87.580225] ata2.02: configured for UDMA/100
[   87.688046] ata2.03: configured for UDMA/100
[   87.795499] ata2.04: configured for UDMA/100
[   87.795657] ata2.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[   87.811260] ata2.05: limiting SATA link speed to 1.5 Gbps
[   87.811306] ata2.05: limiting speed to UDMA7:PIO5
[   87.811351] ata2: failed to recover some devices, retrying in 5 secs
[   92.811668] ata2.05: hard resetting link
[   93.439228] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[   93.439391] ata2.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[   93.439438] ata2: failed to recover some devices, retrying in 5 secs
[   98.439635] ata2.05: hard resetting link
[   99.003241] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[   99.019230] ata2: EH pending after completion, repeating EH (cnt=4)
[   99.147138] ata2: EH complete
[   99.146576] scsi 0:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.146715] scsi 0:0:1:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.146840] scsi 0:0:2:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.146967] scsi 0:0:3:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.147091] scsi 0:0:4:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.147216] scsi 1:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.147343] scsi 1:0:1:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.147469] scsi 1:0:2:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.147596] scsi 1:0:3:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.147719] scsi 1:0:4:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[   99.148681] sata_sil24 0000:04:01.0: Applying completion IRQ loss on PCI-X errata fix
[   99.148986] scsi2 : sata_sil24
[   99.149081] scsi3 : sata_sil24
[   99.149153] scsi4 : sata_sil24
[   99.149226] scsi5 : sata_sil24
[   99.149288] ata3: SATA max UDMA/100 cmd 0xffffc20000330000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[   99.149352] ata4: SATA max UDMA/100 cmd 0xffffc20000332000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[   99.149415] ata5: SATA max UDMA/100 cmd 0xffffc20000334000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[   99.149479] ata6: SATA max UDMA/100 cmd 0xffffc20000336000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[  101.228942] ata3: SATA link down (SStatus 0 SControl 0)
[  103.307449] ata4: SATA link down (SStatus 0 SControl 0)
[  105.537856] ata5: SATA link up 1.5 Gbps (SStatus 113 SControl 0)
[  105.574723] ata5.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  105.574772] ata5.00: 586072368 sectors, multi 16: LBA48 NCQ (depth 31/32)
[  105.632988] ata5.00: configured for UDMA/100
[  107.844203] ata6: SATA link up 1.5 Gbps (SStatus 113 SControl 0)
[  107.909555] ata6.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  107.909602] ata6.00: 586072368 sectors, multi 16: LBA48 NCQ (depth 31/32)
[  108.109323] ata6.00: configured for UDMA/100
[  108.108757] scsi 4:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  108.108899] scsi 5:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  108.109516] scsi6 : sata_sil24
[  108.109614] scsi7 : sata_sil24
[  108.109679] ata7: SATA max UDMA/100 cmd 0xffffc20000348000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[  108.109745] ata8: SATA max UDMA/100 cmd 0xffffc2000034a000 ctl 0x0000000000000000 bmdma 0x0000000000000000 irq 0
[  110.186524] ata7: SATA link down (SStatus 0 SControl 0)
[  112.265034] ata8: SATA link down (SStatus 0 SControl 0)
[  112.316560] sata_nv 0000:00:0d.0: version 3.4
[  112.317788] scsi8 : sata_nv
[  112.324167] scsi9 : sata_nv
[  112.324252] ata9: SATA max UDMA/133 cmd 0x00000000000109f0 ctl 0x0000000000010bf2 bmdma 0x000000000001dc00 irq 0
[  112.324316] ata10: SATA max UDMA/133 cmd 0x0000000000010970 ctl 0x0000000000010b72 bmdma 0x000000000001dc08 irq 0
[  112.365391] sd 0:0:0:0: [sda] 586072368 512-byte hardware sectors (300069 MB)
[  112.365668] sd 0:0:0:0: [sda] Write Protect is off
[  112.365716] sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00
[  112.368722] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.372744] sd 0:0:0:0: [sda] 586072368 512-byte hardware sectors (300069 MB)
[  112.373000] sd 0:0:0:0: [sda] Write Protect is off
[  112.373047] sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00
[  112.374422] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.374490]  sda: sda1
[  112.390609] sd 0:0:0:0: [sda] Attached SCSI disk
[  112.391411] sd 0:0:1:0: [sdb] 586072368 512-byte hardware sectors (300069 MB)
[  112.391467] sd 0:0:1:0: [sdb] Write Protect is off
[  112.391512] sd 0:0:1:0: [sdb] Mode Sense: 00 3a 00 00
[  112.391525] sd 0:0:1:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.391621] sd 0:0:1:0: [sdb] 586072368 512-byte hardware sectors (300069 MB)
[  112.391675] sd 0:0:1:0: [sdb] Write Protect is off
[  112.391720] sd 0:0:1:0: [sdb] Mode Sense: 00 3a 00 00
[  112.391731] sd 0:0:1:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.391792]  sdb: sdb1
[  112.433805] sd 0:0:1:0: [sdb] Attached SCSI disk
[  112.434589] sd 0:0:2:0: [sdc] 586072368 512-byte hardware sectors (300069 MB)
[  112.434643] sd 0:0:2:0: [sdc] Write Protect is off
[  112.434688] sd 0:0:2:0: [sdc] Mode Sense: 00 3a 00 00
[  112.434700] sd 0:0:2:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.434793] sd 0:0:2:0: [sdc] 586072368 512-byte hardware sectors (300069 MB)
[  112.434846] sd 0:0:2:0: [sdc] Write Protect is off
[  112.434892] sd 0:0:2:0: [sdc] Mode Sense: 00 3a 00 00
[  112.434903] sd 0:0:2:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.434963]  sdc: sdc1
[  112.454363] sd 0:0:2:0: [sdc] Attached SCSI disk
[  112.455143] sd 0:0:3:0: [sdd] 586072368 512-byte hardware sectors (300069 MB)
[  112.455197] sd 0:0:3:0: [sdd] Write Protect is off
[  112.455242] sd 0:0:3:0: [sdd] Mode Sense: 00 3a 00 00
[  112.455253] sd 0:0:3:0: [sdd] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.455343] sd 0:0:3:0: [sdd] 586072368 512-byte hardware sectors (300069 MB)
[  112.455396] sd 0:0:3:0: [sdd] Write Protect is off
[  112.455441] sd 0:0:3:0: [sdd] Mode Sense: 00 3a 00 00
[  112.455452] sd 0:0:3:0: [sdd] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.455512]  sdd: sdd1
[  112.476720] sd 0:0:3:0: [sdd] Attached SCSI disk
[  112.477519] sd 0:0:4:0: [sde] 586072368 512-byte hardware sectors (300069 MB)
[  112.483764] sd 0:0:4:0: [sde] Write Protect is off
[  112.483810] sd 0:0:4:0: [sde] Mode Sense: 00 3a 00 00
[  112.483822] sd 0:0:4:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.483910] sd 0:0:4:0: [sde] 586072368 512-byte hardware sectors (300069 MB)
[  112.483964] sd 0:0:4:0: [sde] Write Protect is off
[  112.484009] sd 0:0:4:0: [sde] Mode Sense: 00 3a 00 00
[  112.484020] sd 0:0:4:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.484080]  sde: sde1
[  112.499838] sd 0:0:4:0: [sde] Attached SCSI disk
[  112.500659] sd 1:0:0:0: [sdf] 586072368 512-byte hardware sectors (300069 MB)
[  112.500714] sd 1:0:0:0: [sdf] Write Protect is off
[  112.500759] sd 1:0:0:0: [sdf] Mode Sense: 00 3a 00 00
[  112.500771] sd 1:0:0:0: [sdf] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.500858] sd 1:0:0:0: [sdf] 586072368 512-byte hardware sectors (300069 MB)
[  112.500911] sd 1:0:0:0: [sdf] Write Protect is off
[  112.500956] sd 1:0:0:0: [sdf] Mode Sense: 00 3a 00 00
[  112.500968] sd 1:0:0:0: [sdf] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.501028]  sdf: sdf1
[  112.517003] sd 1:0:0:0: [sdf] Attached SCSI disk
[  112.517849] sd 1:0:1:0: [sdg] 586072368 512-byte hardware sectors (300069 MB)
[  112.517905] sd 1:0:1:0: [sdg] Write Protect is off
[  112.517950] sd 1:0:1:0: [sdg] Mode Sense: 00 3a 00 00
[  112.517962] sd 1:0:1:0: [sdg] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.518050] sd 1:0:1:0: [sdg] 586072368 512-byte hardware sectors (300069 MB)
[  112.518103] sd 1:0:1:0: [sdg] Write Protect is off
[  112.518149] sd 1:0:1:0: [sdg] Mode Sense: 00 3a 00 00
[  112.518160] sd 1:0:1:0: [sdg] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.518221]  sdg: sdg1
[  112.533592] sd 1:0:1:0: [sdg] Attached SCSI disk
[  112.534453] sd 1:0:2:0: [sdh] 586072368 512-byte hardware sectors (300069 MB)
[  112.534508] sd 1:0:2:0: [sdh] Write Protect is off
[  112.534553] sd 1:0:2:0: [sdh] Mode Sense: 00 3a 00 00
[  112.534565] sd 1:0:2:0: [sdh] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.534654] sd 1:0:2:0: [sdh] 586072368 512-byte hardware sectors (300069 MB)
[  112.534708] sd 1:0:2:0: [sdh] Write Protect is off
[  112.534753] sd 1:0:2:0: [sdh] Mode Sense: 00 3a 00 00
[  112.534765] sd 1:0:2:0: [sdh] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.534825]  sdh: sdh1
[  112.550479] sd 1:0:2:0: [sdh] Attached SCSI disk
[  112.551366] sd 1:0:3:0: [sdi] 586072368 512-byte hardware sectors (300069 MB)
[  112.551420] sd 1:0:3:0: [sdi] Write Protect is off
[  112.551466] sd 1:0:3:0: [sdi] Mode Sense: 00 3a 00 00
[  112.551478] sd 1:0:3:0: [sdi] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.551570] sd 1:0:3:0: [sdi] 586072368 512-byte hardware sectors (300069 MB)
[  112.551623] sd 1:0:3:0: [sdi] Write Protect is off
[  112.551669] sd 1:0:3:0: [sdi] Mode Sense: 00 3a 00 00
[  112.551681] sd 1:0:3:0: [sdi] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.551741]  sdi: sdi1
[  112.565642] sd 1:0:3:0: [sdi] Attached SCSI disk
[  112.566561] sd 1:0:4:0: [sdj] 586072368 512-byte hardware sectors (300069 MB)
[  112.566616] sd 1:0:4:0: [sdj] Write Protect is off
[  112.566661] sd 1:0:4:0: [sdj] Mode Sense: 00 3a 00 00
[  112.566673] sd 1:0:4:0: [sdj] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.566766] sd 1:0:4:0: [sdj] 586072368 512-byte hardware sectors (300069 MB)
[  112.566820] sd 1:0:4:0: [sdj] Write Protect is off
[  112.566865] sd 1:0:4:0: [sdj] Mode Sense: 00 3a 00 00
[  112.566876] sd 1:0:4:0: [sdj] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.566936]  sdj: sdj1
[  112.581407] sd 1:0:4:0: [sdj] Attached SCSI disk
[  112.582355] sd 4:0:0:0: [sdk] 586072368 512-byte hardware sectors (300069 MB)
[  112.582411] sd 4:0:0:0: [sdk] Write Protect is off
[  112.582456] sd 4:0:0:0: [sdk] Mode Sense: 00 3a 00 00
[  112.582467] sd 4:0:0:0: [sdk] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.582562] sd 4:0:0:0: [sdk] 586072368 512-byte hardware sectors (300069 MB)
[  112.582615] sd 4:0:0:0: [sdk] Write Protect is off
[  112.582660] sd 4:0:0:0: [sdk] Mode Sense: 00 3a 00 00
[  112.582671] sd 4:0:0:0: [sdk] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.582731]  sdk: sdk1
[  112.598081] sd 4:0:0:0: [sdk] Attached SCSI disk
[  112.599062] sd 5:0:0:0: [sdl] 586072368 512-byte hardware sectors (300069 MB)
[  112.599116] sd 5:0:0:0: [sdl] Write Protect is off
[  112.599161] sd 5:0:0:0: [sdl] Mode Sense: 00 3a 00 00
[  112.599173] sd 5:0:0:0: [sdl] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.599261] sd 5:0:0:0: [sdl] 586072368 512-byte hardware sectors (300069 MB)
[  112.599313] sd 5:0:0:0: [sdl] Write Protect is off
[  112.599359] sd 5:0:0:0: [sdl] Mode Sense: 00 3a 00 00
[  112.599370] sd 5:0:0:0: [sdl] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  112.599430]  sdl: sdl1
[  112.613091] sd 5:0:0:0: [sdl] Attached SCSI disk
[  112.792671] ata9: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  112.844442] ata9.00: ATA-7: ST3500641AS, 3.AAJ, max UDMA/133
[  112.844493] ata9.00: 976773168 sectors, multi 1: LBA48 NCQ (depth 0/32)
[  112.927659] ata9.00: configured for UDMA/133
[  113.396227] ata10: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  113.446869] ata10.00: ATA-7: ST3500641AS, 3.AAJ, max UDMA/133
[  113.446921] ata10.00: 976773168 sectors, multi 1: LBA48 NCQ (depth 0/32)
[  113.530082] ata10.00: configured for UDMA/133
[  113.529519] scsi 8:0:0:0: Direct-Access     ATA      ST3500641AS      3.AA PQ: 0 ANSI: 5
[  113.530079] sd 8:0:0:0: [sdm] 976773168 512-byte hardware sectors (500108 MB)
[  113.530135] sd 8:0:0:0: [sdm] Write Protect is off
[  113.530180] sd 8:0:0:0: [sdm] Mode Sense: 00 3a 00 00
[  113.530193] sd 8:0:0:0: [sdm] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  113.530291] sd 8:0:0:0: [sdm] 976773168 512-byte hardware sectors (500108 MB)
[  113.530344] sd 8:0:0:0: [sdm] Write Protect is off
[  113.530389] sd 8:0:0:0: [sdm] Mode Sense: 00 3a 00 00
[  113.530401] sd 8:0:0:0: [sdm] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  113.530463]  sdm: sdm1 sdm2 sdm3
[  113.551040] sd 8:0:0:0: [sdm] Attached SCSI disk
[  113.551184] scsi 9:0:0:0: Direct-Access     ATA      ST3500641AS      3.AA PQ: 0 ANSI: 5
[  113.551298] sd 9:0:0:0: [sdn] 976773168 512-byte hardware sectors (500108 MB)
[  113.551353] sd 9:0:0:0: [sdn] Write Protect is off
[  113.551399] sd 9:0:0:0: [sdn] Mode Sense: 00 3a 00 00
[  113.551411] sd 9:0:0:0: [sdn] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  113.551513] sd 9:0:0:0: [sdn] 976773168 512-byte hardware sectors (500108 MB)
[  113.551566] sd 9:0:0:0: [sdn] Write Protect is off
[  113.551612] sd 9:0:0:0: [sdn] Mode Sense: 00 3a 00 00
[  113.551623] sd 9:0:0:0: [sdn] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  113.551685]  sdn: sdn1 sdn2 sdn3
[  113.586789] sd 9:0:0:0: [sdn] Attached SCSI disk
[  113.587689] scsi10 : sata_nv
[  113.587929] scsi11 : sata_nv
[  113.587998] ata11: SATA max UDMA/133 cmd 0x00000000000109e0 ctl 0x0000000000010be2 bmdma 0x000000000001c800 irq 0
[  113.588062] ata12: SATA max UDMA/133 cmd 0x0000000000010960 ctl 0x0000000000010b62 bmdma 0x000000000001c808 irq 0
[  114.055754] ata11: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[  114.108809] ata11.00: ATA-7: ST3500641AS, 3.AAJ, max UDMA/133
[  114.108858] ata11.00: 976773168 sectors, multi 1: LBA48 NCQ (depth 0/32)
[  114.192025] ata11.00: configured for UDMA/133
[  114.659320] ata12: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  114.711689] ata12.00: ATA-7: ST3500641AS, 3.AAJ, max UDMA/133
[  114.711737] ata12.00: 976773168 sectors, multi 1: LBA48 NCQ (depth 0/32)
[  114.794908] ata12.00: configured for UDMA/133
[  114.795020] scsi 10:0:0:0: Direct-Access     ATA      ST3500641AS      3.AA PQ: 0 ANSI: 5
[  114.795139] sd 10:0:0:0: [sdo] 976773168 512-byte hardware sectors (500108 MB)
[  114.795204] sd 10:0:0:0: [sdo] Write Protect is off
[  114.795250] sd 10:0:0:0: [sdo] Mode Sense: 00 3a 00 00
[  114.795262] sd 10:0:0:0: [sdo] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  114.795361] sd 10:0:0:0: [sdo] 976773168 512-byte hardware sectors (500108 MB)
[  114.795424] sd 10:0:0:0: [sdo] Write Protect is off
[  114.795469] sd 10:0:0:0: [sdo] Mode Sense: 00 3a 00 00
[  114.795481] sd 10:0:0:0: [sdo] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  114.795541]  sdo: sdo1 sdo2 sdo3
[  114.814713] sd 10:0:0:0: [sdo] Attached SCSI disk
[  114.814823] scsi 11:0:0:0: Direct-Access     ATA      ST3500641AS      3.AA PQ: 0 ANSI: 5
[  114.814928] sd 11:0:0:0: [sdp] 976773168 512-byte hardware sectors (500108 MB)
[  114.814991] sd 11:0:0:0: [sdp] Write Protect is off
[  114.815037] sd 11:0:0:0: [sdp] Mode Sense: 00 3a 00 00
[  114.815049] sd 11:0:0:0: [sdp] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  114.815142] sd 11:0:0:0: [sdp] 976773168 512-byte hardware sectors (500108 MB)
[  114.815205] sd 11:0:0:0: [sdp] Write Protect is off
[  114.815250] sd 11:0:0:0: [sdp] Mode Sense: 00 3a 00 00
[  114.815262] sd 11:0:0:0: [sdp] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  114.815322]  sdp: sdp1 sdp2 sdp3
[  114.843296] sd 11:0:0:0: [sdp] Attached SCSI disk
[  114.844174] scsi12 : sata_nv
[  114.844309] scsi13 : sata_nv
[  114.844375] ata13: SATA max UDMA/133 cmd 0x000000000001c400 ctl 0x000000000001c002 bmdma 0x000000000001b400 irq 0
[  114.844438] ata14: SATA max UDMA/133 cmd 0x000000000001bc00 ctl 0x000000000001b802 bmdma 0x000000000001b408 irq 0
[  115.310854] ata13: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  115.361243] ata13.00: ATA-7: ST3500641AS, 3.AAJ, max UDMA/133
[  115.361291] ata13.00: 976773168 sectors, multi 1: LBA48 NCQ (depth 0/32)
[  115.444459] ata13.00: configured for UDMA/133
[  115.910423] ata14: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  115.964155] ata14.00: ATA-7: ST3500641AS, 3.AAJ, max UDMA/133
[  115.964203] ata14.00: 976773168 sectors, multi 1: LBA48 NCQ (depth 0/32)
[  116.047375] ata14.00: configured for UDMA/133
[  116.047487] scsi 12:0:0:0: Direct-Access     ATA      ST3500641AS      3.AA PQ: 0 ANSI: 5
[  116.047604] sd 12:0:0:0: [sdq] 976773168 512-byte hardware sectors (500108 MB)
[  116.047669] sd 12:0:0:0: [sdq] Write Protect is off
[  116.047714] sd 12:0:0:0: [sdq] Mode Sense: 00 3a 00 00
[  116.047727] sd 12:0:0:0: [sdq] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  116.054016] sd 12:0:0:0: [sdq] 976773168 512-byte hardware sectors (500108 MB)
[  116.054079] sd 12:0:0:0: [sdq] Write Protect is off
[  116.054124] sd 12:0:0:0: [sdq] Mode Sense: 00 3a 00 00
[  116.054136] sd 12:0:0:0: [sdq] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  116.054197]  sdq: sdq1 sdq2 sdq3
[  116.075464] sd 12:0:0:0: [sdq] Attached SCSI disk
[  116.075573] scsi 13:0:0:0: Direct-Access     ATA      ST3500641AS      3.AA PQ: 0 ANSI: 5
[  116.075672] sd 13:0:0:0: [sdr] 976773168 512-byte hardware sectors (500108 MB)
[  116.075736] sd 13:0:0:0: [sdr] Write Protect is off
[  116.075781] sd 13:0:0:0: [sdr] Mode Sense: 00 3a 00 00
[  116.075793] sd 13:0:0:0: [sdr] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  116.075878] sd 13:0:0:0: [sdr] 976773168 512-byte hardware sectors (500108 MB)
[  116.075941] sd 13:0:0:0: [sdr] Write Protect is off
[  116.075986] sd 13:0:0:0: [sdr] Mode Sense: 00 3a 00 00
[  116.075998] sd 13:0:0:0: [sdr] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  116.076058]  sdr: sdr1 sdr2 sdr3
[  116.095768] sd 13:0:0:0: [sdr] Attached SCSI disk

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCHSET 4/4] implement PMP support, take 4
  2007-07-03  7:39 ` [PATCHSET 4/4] implement PMP support, take 4 Jim Paris
@ 2007-07-03  9:34   ` Tejun Heo
  2007-07-03 19:40     ` Jim Paris
  0 siblings, 1 reply; 28+ messages in thread
From: Tejun Heo @ 2007-07-03  9:34 UTC (permalink / raw)
  To: Jim Paris; +Cc: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao

Hey,

Jim Paris wrote:
> There are errors with ata1.05 and ata2.05.  I guess those are the
> SiI4726 management ports that were just ignored in the last take of
> PMP.  The EH on those causes a boot delay, but it's pretty short.

Argh... It isn't supposed to fail.  libata-pmp contains workarounds for
those ports now.

>> * Sil4726 is a bit too quirky.  Without the first fan-out port
>>   occupied, the thing acts really weirdly.  As long as the first port
>>   is occupied, it works okay.  This is reportedly fixed by new
>>   firmware.  I tried to update the firmware but installing 3124 driver
>>   on Windows was just too difficult for me and I gave up after thirty
>>   painful minutes.  Anyone up for testing?
> 
> I'll test the 4726 behavior with pulling disks etc including the first
> port.  I'll also search to see if I can find a Windows machine to
> update the firmware and let you know how things change.
> 
> There's a 4726 firmware update utility for Linux available:
>   http://www.siliconimage.com/support/downloadresults.aspx?pid=74
> It's closed source, but I wonder how it is supposed to work.  It seems
> to just probe /dev/sd* and read the first sector.  Maybe it wants that
> management port to be exposed as a SCSI device?

That only works with their proprietary driver ATM.  I'm talking with
SIMG to make it work with the upstream driver.

> [   53.331253] ata1.15: Port Multiplier 1.1, 0x1095:0x4726 r0, 6 ports, feat 0x9/0xb

Oh well, this is the first time I see r0.

> [   63.749131] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
> [   63.764490] ata1.05: limiting SATA link speed to 1.5 Gbps
> [   63.764537] ata1.05: limiting speed to UDMA7:PIO5
> [   63.764582] ata1: failed to recover some devices, retrying in 5 secs

If the Config Disk device can't stand IDENTIFY.  I suppose we're better
off disabling last two ports on r0.  I'll ask SIMG about it and add
quirks for r0.

Thanks for testing.

-- 
tejun

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCHSET 4/4] implement PMP support, take 4
  2007-07-03  9:34   ` Tejun Heo
@ 2007-07-03 19:40     ` Jim Paris
  0 siblings, 0 replies; 28+ messages in thread
From: Jim Paris @ 2007-07-03 19:40 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Jim Paris wrote:
> > Tejun Heo wrote:
> > > * Sil4726 is a bit too quirky.  Without the first fan-out port
> > >   occupied, the thing acts really weirdly.  As long as the first port
> > >   is occupied, it works okay.
> > 
> > I'll test the 4726 behavior with pulling disks etc including the first
> > port.  I'll also search to see if I can find a Windows machine to
> > update the firmware and let you know how things change.

Hi Tejun,

I tested some hotplug and didn't any problems at all.  I did:

Unplugged ata1.02
Plugged ata1.02
Unplugged ata1.00
Unplugged ata1.03
Plugged ata1.03
Turned off enclosure entirely
Turned on enclosure
Plugged ata1.00

In all cases, all attached disks were correctly recognized.  The log
is appended below.  I didn't bother trying to update the firmware
since it seems to be working just fine.


> If the Config Disk device can't stand IDENTIFY.  I suppose we're better
> off disabling last two ports on r0.  I'll ask SIMG about it and add
> quirks for r0.

OK, I'll gladly test anything you come up with.

Thanks,
-jim


[   53.323077] ata1.15: Port Multiplier 1.1, 0x1095:0x4726 r0, 6 ports, feat 0x9/0xb

Unplugged ata1.02:

[  685.221846] ata1.02: hard resetting link
[  686.201127] ata1.02: SATA link down (SStatus 0 SControl 300)
[  686.217114] ata1: failed to recover some devices, retrying in 5 secs
[  691.233422] ata1.02: hard resetting link
[  691.797006] ata1.02: SATA link down (SStatus 0 SControl 300)
[  691.828983] ata1.02: limiting SATA link speed to 1.5 Gbps
[  691.829034] ata1.02: limiting speed to UDMA/100:PIO3
[  691.829086] ata1: failed to recover some devices, retrying in 5 secs
[  696.849287] ata1.02: hard resetting link
[  697.480821] ata1.02: SATA link down (SStatus 0 SControl 310)
[  697.496808] ata1.02: disabled
[  698.032416] ata1.02: hard resetting link
[  698.663364] ata1.02: SATA link down (SStatus 0 SControl 300)
[  698.679354] ata1: EH complete
[  698.679979] ata1.02: detaching (SCSI 0:0:2:0)
[  698.680241] sd 0:0:2:0: [sdc] Synchronizing SCSI cache
[  698.680422] sd 0:0:2:0: [sdc] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  698.680511] sd 0:0:2:0: [sdc] Stopping disk
[  698.680559] sd 0:0:2:0: [sdc] START_STOP FAILED
[  698.680604] sd 0:0:2:0: [sdc] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK

Plugged ata1.02:

[  711.466523] ata1.02: hard resetting link
[  720.807647] ata1.02: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  720.852090] ata1.02: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  720.852142] ata1.02: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  720.924577] ata1.02: configured for UDMA/100
[  720.939552] ata1: EH complete
[  720.939878] scsi 0:0:2:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  720.940104] sd 0:0:2:0: [sdc] 586072368 512-byte hardware sectors (300069 MB)
[  720.940161] sd 0:0:2:0: [sdc] Write Protect is off
[  720.940220] sd 0:0:2:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  720.940328] sd 0:0:2:0: [sdc] 586072368 512-byte hardware sectors (300069 MB)
[  720.940382] sd 0:0:2:0: [sdc] Write Protect is off
[  720.940439] sd 0:0:2:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  720.940501]  sdc: sdc1
[  720.966807] sd 0:0:2:0: [sdc] Attached SCSI disk

Unplugged ata1.00:

[  767.021622] ata1.00: hard resetting link
[  768.000899] ata1.00: SATA link down (SStatus 0 SControl 300)
[  768.016887] ata1: failed to recover some devices, retrying in 5 secs
[  773.017199] ata1.00: hard resetting link
[  773.580790] ata1.00: SATA link down (SStatus 0 SControl 300)
[  773.612765] ata1.00: limiting SATA link speed to 1.5 Gbps
[  773.612814] ata1.00: limiting speed to UDMA/100:PIO3
[  773.612865] ata1: failed to recover some devices, retrying in 5 secs
[  778.613078] ata1.00: hard resetting link
[  779.240623] ata1.00: SATA link down (SStatus 0 SControl 310)
[  779.256610] ata1.00: disabled
[  779.776220] ata1.00: hard resetting link
[  780.403767] ata1.00: SATA link down (SStatus 0 SControl 300)
[  780.419757] ata1: EH complete
[  780.419813] ata1.00: detaching (SCSI 0:0:0:0)
[  780.420006] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  780.423967] sd 0:0:0:0: [sda] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  780.424066] sd 0:0:0:0: [sda] Stopping disk
[  780.424121] sd 0:0:0:0: [sda] START_STOP FAILED
[  780.424169] sd 0:0:0:0: [sda] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK

Unplugged ata1.03:

[  785.512005] ata1.03: hard resetting link
[  786.491286] ata1.03: SATA link down (SStatus 0 SControl 300)
[  786.507272] ata1: failed to recover some devices, retrying in 5 secs
[  791.523581] ata1.03: hard resetting link
[  792.087166] ata1.03: SATA link down (SStatus 0 SControl 300)
[  792.119140] ata1.03: limiting SATA link speed to 1.5 Gbps
[  792.119189] ata1.03: limiting speed to UDMA/100:PIO3
[  792.119239] ata1: failed to recover some devices, retrying in 5 secs
[  797.135449] ata1.03: hard resetting link
[  797.762986] ata1.03: SATA link down (SStatus 0 SControl 310)
[  797.778973] ata1.03: disabled
[  798.314580] ata1.03: hard resetting link
[  798.942118] ata1.03: SATA link down (SStatus 0 SControl 300)
[  798.958108] ata1: EH complete
[  798.958163] ata1.03: detaching (SCSI 0:0:3:0)
[  798.958410] sd 0:0:3:0: [sdd] Synchronizing SCSI cache
[  798.958585] sd 0:0:3:0: [sdd] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  798.958674] sd 0:0:3:0: [sdd] Stopping disk
[  798.958722] sd 0:0:3:0: [sdd] START_STOP FAILED
[  798.958767] sd 0:0:3:0: [sdd] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK

Plugged ata1.03:

[  801.616148] ata1.03: hard resetting link
[  810.925295] ata1.03: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  811.327359] ata1.03: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  811.327409] ata1.03: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  811.385625] ata1.03: configured for UDMA/100
[  811.400946] ata1: EH complete
[  811.401154] scsi 0:0:3:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  811.401349] sd 0:0:3:0: [sda] 586072368 512-byte hardware sectors (300069 MB)
[  811.401406] sd 0:0:3:0: [sda] Write Protect is off
[  811.401465] sd 0:0:3:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  811.401569] sd 0:0:3:0: [sda] 586072368 512-byte hardware sectors (300069 MB)
[  811.407812] sd 0:0:3:0: [sda] Write Protect is off
[  811.407899] sd 0:0:3:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  811.407961]  sda: sda1
[  811.425436] sd 0:0:3:0: [sda] Attached SCSI disk

Turned off the entire enclosure (ata1, ata2, ata5, ata6):

[  854.744805] ata6: hard resetting link
[  854.744975] ata5: hard resetting link
[  856.280406] ata1.15: hard resetting link
[  856.280954] ata2.15: hard resetting link
[  856.823499] ata6: SATA link down (SStatus 0 SControl 0)
[  856.823555] ata6: failed to recover some devices, retrying in 5 secs
[  856.823614] ata5: SATA link down (SStatus 0 SControl 0)
[  856.823665] ata5: failed to recover some devices, retrying in 5 secs
[  858.358371] ata1.15: SATA link down (SStatus 0 SControl 0)
[  858.358442] ata2.15: SATA link down (SStatus 0 SControl 0)
[  858.614294] ata1.15: retrying hardreset in 5 secs
[  858.614464] ata2.15: retrying hardreset in 5 secs
[  861.823813] ata6: hard resetting link
[  861.823870] ata5: hard resetting link
[  863.614493] ata1.15: hard resetting link
[  863.614552] ata2.15: hard resetting link
[  863.902286] ata6: SATA link down (SStatus 0 SControl 0)
[  863.902342] ata6: limiting SATA link speed to 1.5 Gbps
[  863.902393] ata6.00: limiting speed to UDMA/100:PIO3
[  863.902440] ata6: failed to recover some devices, retrying in 5 secs
[  863.902500] ata5: SATA link down (SStatus 0 SControl 0)
[  863.902551] ata5: limiting SATA link speed to 1.5 Gbps
[  863.902600] ata5.00: limiting speed to UDMA/100:PIO3
[  863.902647] ata5: failed to recover some devices, retrying in 5 secs
[  865.692970] ata1.15: SATA link down (SStatus 0 SControl 0)
[  865.693041] ata2.15: SATA link down (SStatus 0 SControl 0)
[  865.948898] ata1.15: limiting SATA link speed to 1.5 Gbps
[  865.948946] ata1.15: retrying hardreset in 5 secs
[  865.949120] ata2.15: limiting SATA link speed to 1.5 Gbps
[  865.949167] ata2.15: retrying hardreset in 5 secs
[  868.902601] ata6: hard resetting link
[  868.902658] ata5: hard resetting link
[  870.953090] ata1.15: hard resetting link
[  870.953151] ata2.15: hard resetting link
[  870.985070] ata6: SATA link down (SStatus 0 SControl 10)
[  870.985125] ata6.00: disabled
[  870.985181] ata5: SATA link down (SStatus 0 SControl 10)
[  870.985232] ata5.00: disabled
[  871.492692] ata6: EH complete
[  871.492746] ata5: EH complete
[  871.492798] ata6.00: detaching (SCSI 7:0:0:0)
[  871.492988] sd 7:0:0:0: [sdr] Synchronizing SCSI cache
[  871.495331] sd 7:0:0:0: [sdr] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  871.495430] sd 7:0:0:0: [sdr] Stopping disk
[  871.495698] sd 7:0:0:0: [sdr] START_STOP FAILED
[  871.495745] sd 7:0:0:0: [sdr] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  871.495911] ata5.00: detaching (SCSI 6:0:0:0)
[  871.496092] sd 6:0:0:0: [sdq] Synchronizing SCSI cache
[  871.496400] sd 6:0:0:0: [sdq] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  871.496493] sd 6:0:0:0: [sdq] Stopping disk
[  871.496671] sd 6:0:0:0: [sdq] START_STOP FAILED
[  871.496724] sd 6:0:0:0: [sdq] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  873.035564] ata1.15: SATA link down (SStatus 0 SControl 10)
[  873.035637] ata2.15: SATA link down (SStatus 0 SControl 10)
[  873.291490] ata1.15: retrying hardreset in 5 secs
[  873.291663] ata2.15: retrying hardreset in 5 secs
[  878.291687] ata1.15: hard resetting link
[  878.295681] ata2.15: hard resetting link
[  880.370163] ata1.15: SATA link down (SStatus 0 SControl 10)
[  880.374158] ata2.15: SATA link down (SStatus 0 SControl 10)
[  880.626087] ata1.15: retrying hardreset in 5 secs
[  880.630083] ata2.15: retrying hardreset in 5 secs
[  885.626286] ata1.15: hard resetting link
[  885.630280] ata2.15: hard resetting link
[  887.704762] ata1.15: SATA link down (SStatus 0 SControl 10)
[  887.708757] ata2.15: SATA link down (SStatus 0 SControl 10)
[  887.960737] ata1.15: Port Multiplier detaching
[  887.960809] ata1.01: disabled
[  887.960854] ata1.02: disabled
[  887.960902] ata1.03: disabled
[  887.960946] ata1.04: disabled
[  887.960995] ata1.00: disabled
[  887.961044] ata1: EH complete
[  887.961104] ata1.01: detaching (SCSI 0:0:1:0)
[  887.961302] sd 0:0:1:0: [sdb] Synchronizing SCSI cache
[  887.964553] sd 0:0:1:0: [sdb] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.964087] ata2.15: Port Multiplier detaching
[  887.964111] ata2.00: disabled
[  887.964115] ata2.01: disabled
[  887.964117] ata2.02: disabled
[  887.964119] ata2.03: disabled
[  887.964121] ata2.04: disabled
[  887.964124] ata2.00: disabled
[  887.964130] ata2: EH complete
[  887.965153] sd 0:0:1:0: [sdb] Stopping disk
[  887.965784] sd 0:0:1:0: [sdb] START_STOP FAILED
[  887.965834] sd 0:0:1:0: [sdb] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.965991] ata1.02: detaching (SCSI 0:0:2:0)
[  887.966155] sd 0:0:2:0: [sdc] Synchronizing SCSI cache
[  887.968029] sd 0:0:2:0: [sdc] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.968128] sd 0:0:2:0: [sdc] Stopping disk
[  887.968179] sd 0:0:2:0: [sdc] START_STOP FAILED
[  887.968225] sd 0:0:2:0: [sdc] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.968385] ata1.03: detaching (SCSI 0:0:3:0)
[  887.968551] sd 0:0:3:0: [sda] Synchronizing SCSI cache
[  887.968620] sd 0:0:3:0: [sda] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.968714] sd 0:0:3:0: [sda] Stopping disk
[  887.968764] sd 0:0:3:0: [sda] START_STOP FAILED
[  887.968812] sd 0:0:3:0: [sda] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.968935] ata1.04: detaching (SCSI 0:0:4:0)
[  887.969098] sd 0:0:4:0: [sde] Synchronizing SCSI cache
[  887.969162] sd 0:0:4:0: [sde] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.969255] sd 0:0:4:0: [sde] Stopping disk
[  887.969303] sd 0:0:4:0: [sde] START_STOP FAILED
[  887.969352] sd 0:0:4:0: [sde] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.975673] ata2.00: detaching (SCSI 1:0:0:0)
[  887.975826] sd 1:0:0:0: [sdf] Synchronizing SCSI cache
[  887.975887] sd 1:0:0:0: [sdf] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.975979] sd 1:0:0:0: [sdf] Stopping disk
[  887.976031] sd 1:0:0:0: [sdf] START_STOP FAILED
[  887.976077] sd 1:0:0:0: [sdf] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.976201] ata2.01: detaching (SCSI 1:0:1:0)
[  887.976351] sd 1:0:1:0: [sdg] Synchronizing SCSI cache
[  887.976412] sd 1:0:1:0: [sdg] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.976505] sd 1:0:1:0: [sdg] Stopping disk
[  887.976557] sd 1:0:1:0: [sdg] START_STOP FAILED
[  887.976605] sd 1:0:1:0: [sdg] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.976727] ata2.02: detaching (SCSI 1:0:2:0)
[  887.976880] sd 1:0:2:0: [sdh] Synchronizing SCSI cache
[  887.976941] sd 1:0:2:0: [sdh] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.977035] sd 1:0:2:0: [sdh] Stopping disk
[  887.977083] sd 1:0:2:0: [sdh] START_STOP FAILED
[  887.977133] sd 1:0:2:0: [sdh] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.977250] ata2.03: detaching (SCSI 1:0:3:0)
[  887.977401] sd 1:0:3:0: [sdi] Synchronizing SCSI cache
[  887.977460] sd 1:0:3:0: [sdi] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.977554] sd 1:0:3:0: [sdi] Stopping disk
[  887.977605] sd 1:0:3:0: [sdi] START_STOP FAILED
[  887.977651] sd 1:0:3:0: [sdi] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.977779] ata2.04: detaching (SCSI 1:0:4:0)
[  887.977932] sd 1:0:4:0: [sdj] Synchronizing SCSI cache
[  887.977993] sd 1:0:4:0: [sdj] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK
[  887.978085] sd 1:0:4:0: [sdj] Stopping disk
[  887.978135] sd 1:0:4:0: [sdj] START_STOP FAILED
[  887.978182] sd 1:0:4:0: [sdj] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK,SUGGEST_OK

Turned on the enclosure.  ata1.00 is still unplugged:

[  914.543194] ata6: hard resetting link
[  914.543595] ata5: hard resetting link
[  914.769024] ata1: hard resetting link
[  914.768702] ata2: hard resetting link
[  916.966675] ata2: SATA link up 3.0 Gbps (SStatus 123 SControl 0)
[  916.967234] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 0)
[  917.110543] ata2.15: Port Multiplier 1.1, 0x1095:0x4726 r0, 6 ports, feat 0x9/0xb
[  917.111101] ata1.15: Port Multiplier 1.1, 0x1095:0x4726 r0, 6 ports, feat 0x9/0xb
[  917.222475] ata2.00: hard resetting link
[  917.223035] ata1.00: hard resetting link
[  917.786057] ata2.00: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  917.786616] ata1.00: SATA link down (SStatus 0 SControl 300)
[  917.802043] ata2.01: hard resetting link
[  917.802603] ata1.01: hard resetting link
[  924.541684] ata6: hard resetting link
[  924.541787] ata5: hard resetting link
[  926.756014] ata5: SATA link up 1.5 Gbps (SStatus 113 SControl 0)
[  926.771997] ata6: SATA link up 1.5 Gbps (SStatus 113 SControl 0)
[  926.785908] ata5.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  926.785957] ata5.00: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  926.840036] ata6.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  926.840085] ata6.00: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  926.844175] ata5.00: configured for UDMA/100
[  926.844224] ata5: EH complete
[  926.844482] scsi 6:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  926.845662] sd 6:0:0:0: [sda] 586072368 512-byte hardware sectors (300069 MB)
[  926.845725] sd 6:0:0:0: [sda] Write Protect is off
[  926.846006] sd 6:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  926.846178] sd 6:0:0:0: [sda] 586072368 512-byte hardware sectors (300069 MB)
[  926.846234] sd 6:0:0:0: [sda] Write Protect is off
[  926.846467] sd 6:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  926.846532]  sda: sda1
[  926.883969] sd 6:0:0:0: [sda] Attached SCSI disk
[  926.935888] ata1.01: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  926.951868] ata1.02: hard resetting link
[  927.089749] ata6.00: configured for UDMA/100
[  927.089804] ata6: EH complete
[  927.090044] scsi 7:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  927.091176] sd 7:0:0:0: [sdb] 586072368 512-byte hardware sectors (300069 MB)
[  927.091246] sd 7:0:0:0: [sdb] Write Protect is off
[  927.091532] sd 7:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  927.091709] sd 7:0:0:0: [sdb] 586072368 512-byte hardware sectors (300069 MB)
[  927.091779] sd 7:0:0:0: [sdb] Write Protect is off
[  927.091840] sd 7:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  927.091904]  sdb:<6>ata2.01: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  927.239097] ata2.02: hard resetting link
[  927.265083]  sdb1
[  927.265218] sd 7:0:0:0: [sdb] Attached SCSI disk
[  936.408903] ata1.02: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  936.424890] ata1.03: hard resetting link
[  936.692139] ata2.02: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  936.708125] ata2.03: hard resetting link
[  945.909908] ata1.03: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  945.925895] ata1.04: hard resetting link
[  946.017273] ata2.03: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  946.033259] ata2.04: hard resetting link
[  955.278454] ata2.04: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  955.278507] ata2.05: hard resetting link
[  955.538818] ata1.04: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  955.538872] ata1.05: hard resetting link
[  955.842038] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[  955.884453] ata2.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  955.884505] ata2.00: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  955.942715] ata2.00: configured for UDMA/100
[  955.981937] ata2.01: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  955.981986] ata2.01: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.040204] ata2.01: configured for UDMA/100
[  956.086187] ata2.02: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.086236] ata2.02: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.102401] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[  956.144454] ata2.02: configured for UDMA/100
[  956.145604] ata1.01: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.145653] ata1.01: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.188834] ata2.03: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.188882] ata2.03: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.203868] ata1.01: configured for UDMA/100
[  956.243730] ata1.02: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.243778] ata1.02: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.247100] ata2.03: configured for UDMA/100
[  956.288708] ata2.04: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.288757] ata2.04: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.316179] ata1.02: configured for UDMA/100
[  956.346974] ata2.04: configured for UDMA/100
[  956.347150] ata2.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[  956.347199] ata2: failed to recover some devices, retrying in 5 secs
[  956.353522] ata1.03: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.353571] ata1.03: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.411786] ata1.03: configured for UDMA/100
[  956.457105] ata1.04: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[  956.457154] ata1.04: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[  956.515370] ata1.04: configured for UDMA/100
[  956.515540] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[  956.515588] ata1: failed to recover some devices, retrying in 5 secs
[  961.346535] ata2.05: hard resetting link
[  961.514408] ata1.05: hard resetting link
[  961.910126] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[  962.019086] ata2.00: configured for UDMA/100
[  962.078001] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[  962.124914] ata2.01: configured for UDMA/100
[  962.180368] ata1.01: configured for UDMA/100
[  962.229307] ata2.02: configured for UDMA/100
[  962.286784] ata1.02: configured for UDMA/100
[  962.331715] ata2.03: configured for UDMA/100
[  962.388299] ata1.03: configured for UDMA/100
[  962.431532] ata2.04: configured for UDMA/100
[  962.431706] ata2.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[  962.445730] ata2.05: limiting SATA link speed to 1.5 Gbps
[  962.445778] ata2.05: limiting speed to UDMA7:PIO5
[  962.445829] ata2: failed to recover some devices, retrying in 5 secs
[  962.491902] ata1.04: configured for UDMA/100
[  962.492073] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[  962.509683] ata1.05: limiting SATA link speed to 1.5 Gbps
[  962.509733] ata1.05: limiting speed to UDMA7:PIO5
[  962.509783] ata1: failed to recover some devices, retrying in 5 secs
[  967.446044] ata2.05: hard resetting link
[  967.509994] ata1.05: hard resetting link
[  968.073589] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[  968.073782] ata2.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[  968.073831] ata2: failed to recover some devices, retrying in 5 secs
[  968.137539] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[  968.137715] ata1.05: failed to IDENTIFY (I/O error, err_mask=0x1)
[  968.137764] ata1: failed to recover some devices, retrying in 5 secs
[  973.073899] ata2.05: hard resetting link
[  973.141846] ata1.05: hard resetting link
[  973.637490] ata2.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[  973.653479] ata2: EH pending after completion, repeating EH (cnt=4)
[  973.705439] ata1.05: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[  973.721431] ata1: EH pending after completion, repeating EH (cnt=4)
[  973.781385] ata2: EH complete
[  973.781599] scsi 1:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.782745] sd 1:0:0:0: [sdc] 586072368 512-byte hardware sectors (300069 MB)
[  973.782808] sd 1:0:0:0: [sdc] Write Protect is off
[  973.783091] sd 1:0:0:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.783266] sd 1:0:0:0: [sdc] 586072368 512-byte hardware sectors (300069 MB)
[  973.783322] sd 1:0:0:0: [sdc] Write Protect is off
[  973.783596] sd 1:0:0:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.783661]  sdc: sdc1
[  973.803836] sd 1:0:0:0: [sdc] Attached SCSI disk
[  973.804799] scsi 1:0:1:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.806206] sd 1:0:1:0: [sdd] 586072368 512-byte hardware sectors (300069 MB)
[  973.806279] sd 1:0:1:0: [sdd] Write Protect is off
[  973.806567] sd 1:0:1:0: [sdd] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.806741] sd 1:0:1:0: [sdd] 586072368 512-byte hardware sectors (300069 MB)
[  973.806798] sd 1:0:1:0: [sdd] Write Protect is off
[  973.807036] sd 1:0:1:0: [sdd] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.807099]  sdd: sdd1
[  973.826406] sd 1:0:1:0: [sdd] Attached SCSI disk
[  973.828828] scsi 1:0:2:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.829925] sd 1:0:2:0: [sde] 586072368 512-byte hardware sectors (300069 MB)
[  973.832408] sd 1:0:2:0: [sde] Write Protect is off
[  973.836405] sd 1:0:2:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.837640] sd 1:0:2:0: [sde] 586072368 512-byte hardware sectors (300069 MB)
[  973.837781] sd 1:0:2:0: [sde] Write Protect is off
[  973.837955] sd 1:0:2:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.838019]  sde:<6>ata1: EH complete
[  973.856112]  sde1
[  973.856258] sd 1:0:2:0: [sde] Attached SCSI disk
[  973.857341] scsi 1:0:3:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.859574] sd 1:0:3:0: [sdf] 586072368 512-byte hardware sectors (300069 MB)
[  973.859723] sd 1:0:3:0: [sdf] Write Protect is off
[  973.860516] sd 1:0:3:0: [sdf] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.860639] sd 1:0:3:0: [sdf] 586072368 512-byte hardware sectors (300069 MB)
[  973.860695] sd 1:0:3:0: [sdf] Write Protect is off
[  973.860757] sd 1:0:3:0: [sdf] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.860820]  sdf: sdf1
[  973.874922] sd 1:0:3:0: [sdf] Attached SCSI disk
[  973.877377] scsi 1:0:4:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.879591] sd 1:0:4:0: [sdg] 586072368 512-byte hardware sectors (300069 MB)
[  973.880372] sd 1:0:4:0: [sdg] Write Protect is off
[  973.884370] sd 1:0:4:0: [sdg] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.888370] sd 1:0:4:0: [sdg] 586072368 512-byte hardware sectors (300069 MB)
[  973.888433] sd 1:0:4:0: [sdg] Write Protect is off
[  973.889531] sd 1:0:4:0: [sdg] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.889597]  sdg: sdg1
[  973.908066] sd 1:0:4:0: [sdg] Attached SCSI disk
[  973.908364] scsi 0:0:1:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.912369] sd 0:0:1:0: [sdh] 586072368 512-byte hardware sectors (300069 MB)
[  973.913300] sd 0:0:1:0: [sdh] Write Protect is off
[  973.915499] sd 0:0:1:0: [sdh] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.915780] sd 0:0:1:0: [sdh] 586072368 512-byte hardware sectors (300069 MB)
[  973.915927] sd 0:0:1:0: [sdh] Write Protect is off
[  973.917297] sd 0:0:1:0: [sdh] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.917365]  sdh: sdh1
[  973.931851] sd 0:0:1:0: [sdh] Attached SCSI disk
[  973.933116] scsi 0:0:2:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.933392] sd 0:0:2:0: [sdi] 586072368 512-byte hardware sectors (300069 MB)
[  973.933937] sd 0:0:2:0: [sdi] Write Protect is off
[  973.934204] sd 0:0:2:0: [sdi] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.937270] sd 0:0:2:0: [sdi] 586072368 512-byte hardware sectors (300069 MB)
[  973.938128] sd 0:0:2:0: [sdi] Write Protect is off
[  973.939540] sd 0:0:2:0: [sdi] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.939607]  sdi: sdi1
[  973.954948] sd 0:0:2:0: [sdi] Attached SCSI disk
[  973.957276] scsi 0:0:3:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.959079] sd 0:0:3:0: [sdj] 586072368 512-byte hardware sectors (300069 MB)
[  973.960321] sd 0:0:3:0: [sdj] Write Protect is off
[  973.961247] sd 0:0:3:0: [sdj] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.964181] sd 0:0:3:0: [sdj] 586072368 512-byte hardware sectors (300069 MB)
[  973.964321] sd 0:0:3:0: [sdj] Write Protect is off
[  973.964648] sd 0:0:3:0: [sdj] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.964710]  sdj: sdj1
[  973.981606] sd 0:0:3:0: [sdj] Attached SCSI disk
[  973.985261] scsi 0:0:4:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[  973.986644] sd 0:0:4:0: [sdq] 586072368 512-byte hardware sectors (300069 MB)
[  973.986873] sd 0:0:4:0: [sdq] Write Protect is off
[  973.987098] sd 0:0:4:0: [sdq] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.988307] sd 0:0:4:0: [sdq] 586072368 512-byte hardware sectors (300069 MB)
[  973.988885] sd 0:0:4:0: [sdq] Write Protect is off
[  973.992324] sd 0:0:4:0: [sdq] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  973.992392]  sdq: sdq1
[  974.010309] sd 0:0:4:0: [sdq] Attached SCSI disk

Plugged ata1.00:

[  998.067505] ata1.00: hard resetting link
[  999.046782] ata1.00: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[ 1007.515467] ata1.00: failed to IDENTIFY (INIT_DEV_PARAMS failed, err_mask=0x80)
[ 1007.515531] ata1: failed to recover some devices, retrying in 5 secs
[ 1012.516856] ata1.00: hard resetting link
[ 1013.080448] ata1.00: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[ 1013.109654] ata1.00: ATA-7: ST3300822AS, 3.AAD, max UDMA/133
[ 1013.109703] ata1.00: 586072368 sectors, multi 0: LBA48 NCQ (depth 31/32)
[ 1013.167921] ata1.00: configured for UDMA/100
[ 1013.184371] ata1: EH pending after completion, repeating EH (cnt=4)
[ 1013.296289] ata1.00: hard resetting link
[ 1013.859874] ata1.00: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[ 1013.967009] ata1.00: configured for UDMA/100
[ 1013.983784] ata1: EH complete
[ 1013.983944] sd 0:0:1:0: [sdh] 586072368 512-byte hardware sectors (300069 MB)
[ 1013.984087] sd 0:0:1:0: [sdh] Write Protect is off
[ 1013.984305] sd 0:0:1:0: [sdh] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1013.984469] sd 0:0:2:0: [sdi] 586072368 512-byte hardware sectors (300069 MB)
[ 1013.984610] sd 0:0:2:0: [sdi] Write Protect is off
[ 1013.984820] sd 0:0:2:0: [sdi] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1013.984982] sd 0:0:3:0: [sdj] 586072368 512-byte hardware sectors (300069 MB)
[ 1013.985124] sd 0:0:3:0: [sdj] Write Protect is off
[ 1013.985334] sd 0:0:3:0: [sdj] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1013.985534] sd 0:0:4:0: [sdq] 586072368 512-byte hardware sectors (300069 MB)
[ 1013.985678] sd 0:0:4:0: [sdq] Write Protect is off
[ 1013.985912] sd 0:0:4:0: [sdq] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1013.986133] scsi 0:0:0:0: Direct-Access     ATA      ST3300822AS      3.AA PQ: 0 ANSI: 5
[ 1013.986349] sd 0:0:0:0: [sdr] 586072368 512-byte hardware sectors (300069 MB)
[ 1013.986488] sd 0:0:0:0: [sdr] Write Protect is off
[ 1013.986698] sd 0:0:0:0: [sdr] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1013.986898] sd 0:0:0:0: [sdr] 586072368 512-byte hardware sectors (300069 MB)
[ 1013.987038] sd 0:0:0:0: [sdr] Write Protect is off
[ 1013.987251] sd 0:0:0:0: [sdr] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 1013.987314]  sdr: sdr1
[ 1014.006839] sd 0:0:0:0: [sdr] Attached SCSI disk

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP
  2007-07-01 10:54 ` [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP Tejun Heo
@ 2007-07-12 20:24   ` Jeff Garzik
  2007-07-13  3:05     ` Tejun Heo
  0 siblings, 1 reply; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:24 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Extend ata_acpi_associate_sata_port() such that it can handle PMP and
> call it when PMP is attached and detached.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

Though not your fault, I predict much puking of BIOS code, when PMP are 
attached and suspend/whatever ACPI-related.  I doubt ACPI writers take 
PMP into account.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd()
  2007-07-01 10:54 ` [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
@ 2007-07-12 20:25   ` Jeff Garzik
  2007-07-13  3:06     ` Tejun Heo
  0 siblings, 1 reply; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:25 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Separate out sil24_exec_polled_cmd() from sil24_softreset().  This
> will be used to implement sil24_pmp_read/write().

you should order patches like these near the top of the first patchset, 
since they are so easy and quick to review and merge.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 07/15] sata_sil24: separate out sil24_do_softreset()
  2007-07-01 10:54 ` [PATCH 07/15] sata_sil24: separate out sil24_do_softreset() Tejun Heo
@ 2007-07-12 20:26   ` Jeff Garzik
  0 siblings, 0 replies; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Separate out sil24_do_softreset() which takes @pmp as its last
> argument.  This will be used to implement sil24_pmp_softreset().
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ditto last comment



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 12/15] ahci: separate out ahci_kick_engine()
  2007-07-01 10:54 ` [PATCH 12/15] ahci: separate out ahci_kick_engine() Tejun Heo
@ 2007-07-12 20:26   ` Jeff Garzik
  0 siblings, 0 replies; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Separate out stop_engine - CLO - start_engine sequence from
> ahci_softreset() and ahci_clo() into ahci_reset_engine() and use it in
> ahci_softreset() and ahci_post_internal_cmd().  The function will also
> be used to prepare for and clean up after PMP register access
> commands.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> ---
>  drivers/ata/ahci.c |   69 +++++++++++++++++++++++++++-------------------------
>  1 files changed, 36 insertions(+), 33 deletions(-)

ditto



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 13/15] ahci: separate out ahci_exec_polled_cmd()
  2007-07-01 10:54 ` [PATCH 13/15] ahci: separate out ahci_exec_polled_cmd() Tejun Heo
@ 2007-07-12 20:26   ` Jeff Garzik
  0 siblings, 0 replies; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Separate out ahci_exec_polled_cmd() from ahci_softreset().  This will
> be used to implement ahci_pmp_read/write().  ahci_exec_polled_cmd()
> performs reset_engine before returning if the command fails (times
> out).  This is to improve robustness.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> ---
>  drivers/ata/ahci.c |   54 +++++++++++++++++++++++++++++++--------------------
>  1 files changed, 33 insertions(+), 21 deletions(-)

ditto

might have to rediff to latest #upstream, versus my ahci.c changes



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 14/15] ahci: separate out ahci_do_softreset()
  2007-07-01 10:54 ` [PATCH 14/15] ahci: separate out ahci_do_softreset() Tejun Heo
@ 2007-07-12 20:26   ` Jeff Garzik
  0 siblings, 0 replies; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Separate out ahci_do_softreset() which takes @pmp as its last
> argument.  This will be used to implement ahci_pmp_softreset().
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ditto



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCHSET 4/4] implement PMP support, take 4
  2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
                   ` (15 preceding siblings ...)
  2007-07-03  7:39 ` [PATCHSET 4/4] implement PMP support, take 4 Jim Paris
@ 2007-07-12 20:27 ` Jeff Garzik
  16 siblings, 0 replies; 28+ messages in thread
From: Jeff Garzik @ 2007-07-12 20:27 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao

Tejun Heo wrote:
> Hello, all.
> 
> his is the fourth take of libata-pmp patchset.  This patchset contains
> 15 patches and implements PMP support.
> 
> #01-04: implement libata PMP support
> #05-09: implement sata_sil24 PMP support
> #10-15: implement ahci PMP support
> 
> Changes from the last take[L] are.
> 
> * updated to fit new #upstream
> * ACPI support for PMP fan-out ports added
> * improved general PMP EH behavior
> * various PMP chip specific quirks for smooth handling of first gen
>   products which at times are pretty quirky
> * AHCI PMP support added
> 
> Tested extensively with sil3214/32, ICH9R, JMB360/3 combined with
> sil3726, 4726 and 5744 port multipliers.  Disks from all major vendors
> and an SATAPI device is used as downstream devices.  sil5744 and 3726
> behave very nicely on all controllers.  Hotplugging and suspend/resume
> work well too.  There are some remaining issues.
> 
> * When attached to AHCI controller (ICH9R, JMB360/3), NCQ doesn't
>   work.  Things look okay as long as only one command is in flight but
>   as soon as the second command is issued (to the same device), hell
>   breaks loose and all sorts of errors occur including device abort,
>   bad PMP number and interface fatal error.  This behavior is common
>   across all PMP chips.  I've disabled NCQ if PMP is attached to an
>   ahci controller for now.
> 
> * Sil4726 is a bit too quirky.  Without the first fan-out port
>   occupied, the thing acts really weirdly.  As long as the first port
>   is occupied, it works okay.  This is reportedly fixed by new
>   firmware.  I tried to update the firmware but installing 3124 driver
>   on Windows was just too difficult for me and I gave up after thirty
>   painful minutes.  Anyone up for testing?
> 
> * Again, Sil4726 doesn't like ahci driver initialization sequence.
>   During driver initialization, the whole controller is reset and the
>   PHY seems to go offline and back online.  Sil4726 doesn't like it
>   and goes out for lunch for several secs after that which makes
>   initial probing think that the port is empty.  After probing is
>   complete, Sil4726 comes back and gets detected but at that point
>   detection is asynchronous and if boot device is on one of fan-out
>   ports, it can be a problem.  Again, this might have been fixed by
>   new firmware.  Anyone up for testing?
> 
> * The long boot delay on ASUS boards with on-board PMP chips should be
>   fixed by this patchset but I don't have such a board or Sil4723
>   which is used on those baords, so I'm not sure.  Anyone up for
>   testing?
> 
> This patchset is against
> 
>   libata-dev#upstream (4e1ae96828f6cee7b89ab8ca474c150fe211afd8)
>   + [1] misc-updates patchset
>   + [2] libata-link patchset, take 4
>   + [3] libata-pmp-prep patchset, take 4

patchset overall seems OK to me



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP
  2007-07-12 20:24   ` Jeff Garzik
@ 2007-07-13  3:05     ` Tejun Heo
  0 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-13  3:05 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Alan Cox, linux-ide, Forrest Zhao

Jeff Garzik wrote:
> Tejun Heo wrote:
>> Extend ata_acpi_associate_sata_port() such that it can handle PMP and
>> call it when PMP is attached and detached.
>>
>> Signed-off-by: Tejun Heo <htejun@gmail.com>
> 
> Though not your fault, I predict much puking of BIOS code, when PMP are
> attached and suspend/whatever ACPI-related.  I doubt ACPI writers take
> PMP into account.

In most cases, ACPI just would be disabled when PMP is attached and
reenabled when detached, so it should be generally okay.  I'm not sure
if anyone would implement PMP ACPI methods but at least one vendor is
selling a motherboard with on-board PMP, so maybe....

-- 
tejun

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd()
  2007-07-12 20:25   ` Jeff Garzik
@ 2007-07-13  3:06     ` Tejun Heo
  0 siblings, 0 replies; 28+ messages in thread
From: Tejun Heo @ 2007-07-13  3:06 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Alan Cox, linux-ide, Forrest Zhao

Jeff Garzik wrote:
> Tejun Heo wrote:
>> Separate out sil24_exec_polled_cmd() from sil24_softreset().  This
>> will be used to implement sil24_pmp_read/write().
> 
> you should order patches like these near the top of the first patchset,
> since they are so easy and quick to review and merge.

Alright, will move.

-- 
tejun

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2007-07-13  3:10 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-01 10:54 [PATCHSET 4/4] implement PMP support, take 4 Tejun Heo
2007-07-01 10:54 ` [PATCH 01/15] libata-pmp: update ata_eh_reset() for PMP Tejun Heo
2007-07-01 10:54 ` [PATCH 02/15] libata-pmp: implement Port Multiplier support Tejun Heo
2007-07-01 10:54 ` [PATCH 03/15] libata-pmp: hook PMP support and enable it Tejun Heo
2007-07-01 10:54 ` [PATCH 04/15] libata-pmp: extend ACPI support to cover PMP Tejun Heo
2007-07-12 20:24   ` Jeff Garzik
2007-07-13  3:05     ` Tejun Heo
2007-07-01 10:54 ` [PATCH 09/15] sata_sil24: implement PORT_RST Tejun Heo
2007-07-01 10:54 ` [PATCH 07/15] sata_sil24: separate out sil24_do_softreset() Tejun Heo
2007-07-12 20:26   ` Jeff Garzik
2007-07-01 10:54 ` [PATCH 06/15] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
2007-07-12 20:25   ` Jeff Garzik
2007-07-13  3:06     ` Tejun Heo
2007-07-01 10:54 ` [PATCH 08/15] sata_sil24: implement PMP support Tejun Heo
2007-07-01 10:54 ` [PATCH 05/15] sata_sil24: replace sil24_update_tf() with sil24_read_tf() Tejun Heo
2007-07-01 10:54 ` [PATCH 14/15] ahci: separate out ahci_do_softreset() Tejun Heo
2007-07-12 20:26   ` Jeff Garzik
2007-07-01 10:54 ` [PATCH 10/15] libata-pmp: implement qc_defer for command switching PMP support Tejun Heo
2007-07-01 10:54 ` [PATCH 11/15] ahci: use deadline instead of fixed timeout for 1st FIS for SRST Tejun Heo
2007-07-01 10:54 ` [PATCH 12/15] ahci: separate out ahci_kick_engine() Tejun Heo
2007-07-12 20:26   ` Jeff Garzik
2007-07-01 10:54 ` [PATCH 13/15] ahci: separate out ahci_exec_polled_cmd() Tejun Heo
2007-07-12 20:26   ` Jeff Garzik
2007-07-01 10:54 ` [PATCH 15/15] ahci: implement PMP support Tejun Heo
2007-07-03  7:39 ` [PATCHSET 4/4] implement PMP support, take 4 Jim Paris
2007-07-03  9:34   ` Tejun Heo
2007-07-03 19:40     ` Jim Paris
2007-07-12 20:27 ` Jeff Garzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).