All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET 1/3] implement ata_link, take 2
@ 2006-07-08  5:45 Tejun Heo
  2006-07-08  5:45 ` [PATCH 01/17] libata-link: separate out ata_eh_handle_dev_fail() Tejun Heo
                   ` (16 more replies)
  0 siblings, 17 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide, htejun

Hello, all.

This is part of patchset series described in [T].

This is the second take of implement-ata_link patchset.  This patchset
contains 17 patches which can be categorized as follows.

#01-02: prep
#03-04: implement ata_link
#05-08: make libata deal with link instead of port
#09-11: misc link stuff (link init, reset_tries, ata_link_abort())
#12-17: add ap->pmp_link[] and update libata to deal with multiple
	links

ata_link abstracts PHY and sits between ata_port and ata_device.  The
following attributes are moved to ata_link from ata_port.

- active command state (active_tag, sactive)
- [hw_]sata_spd_limit
- eh_info and eh_context
- device array

With above and a few extra fields, a link can fully host attached
devices including qc management and EH/hotplug.  This patchset makes
libata ready to handle PM links.

Changes from the last take[L] are.

* updated to fit new #upstream
* ata_eh_handle_dev_fail() is separated out from ata_eh_recover() to
  ease making EH batch later.
* Link resume handling udpated.
* Power Management is linkified.

This patchset is against

  upstream (309bade002e9226781c2d7a015340d0089e399b5)
  + [1] hp-poll patchset, take #2

Thanks.

--
tejun

[T] http://article.gmane.org/gmane.linux.ide/11927
[L] http://article.gmane.org/gmane.linux.ide/10106
[1] http://article.gmane.org/gmane.linux.ide/11862



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

* [PATCH 02/17] libata-link: add PMP related ATA constants
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
  2006-07-08  5:45 ` [PATCH 01/17] libata-link: separate out ata_eh_handle_dev_fail() Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-19 20:24   ` Jeff Garzik
  2006-07-08  5:45 ` [PATCH 03/17] libata-link: introduce ata_link Tejun Heo
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Add Port Multiplier related ATA constants and macros.  Some of these
will be used by ata_link implementation.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 include/linux/ata.h |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

4681138079e48198ac890673c23d58a57a4743b4
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 3671af8..26494bb 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -154,6 +154,8 @@ enum {
 	ATA_CMD_READ_NATIVE_MAX	= 0xF8,
 	ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
 	ATA_CMD_READ_LOG_EXT	= 0x2f,
+	ATA_CMD_PMP_READ	= 0xE4,
+	ATA_CMD_PMP_WRITE	= 0xE8,
 
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
@@ -190,6 +192,28 @@ enum {
 						   0=to device, 1=to host */
 	ATAPI_CDB_LEN		= 16,
 
+	/* PMP stuff */
+	SATA_PMP_MAX_PORTS	= 15,
+	SATA_PMP_CTRL_PORT	= 15,
+
+	SATA_PMP_GSCR_DWORDS	= 128,
+	SATA_PMP_GSCR_PROD_ID	= 0,
+	SATA_PMP_GSCR_REV	= 1,
+	SATA_PMP_GSCR_PORT_INFO	= 2,
+	SATA_PMP_GSCR_ERROR	= 32,
+	SATA_PMP_GSCR_ERROR_EN	= 33,
+	SATA_PMP_GSCR_FEAT	= 64,
+	SATA_PMP_GSCR_FEAT_EN	= 96,
+
+	SATA_PMP_PSCR_STATUS	= 0,
+	SATA_PMP_PSCR_ERROR	= 1,
+	SATA_PMP_PSCR_CONTROL	= 2,
+
+	SATA_PMP_FEAT_BIST	= (1 << 0),
+	SATA_PMP_FEAT_PMREQ	= (1 << 1),
+	SATA_PMP_FEAT_DYNSSC	= (1 << 2),
+	SATA_PMP_FEAT_NOTIFY	= (1 << 3),
+
 	/* cable types */
 	ATA_CBL_NONE		= 0,
 	ATA_CBL_PATA40		= 1,
@@ -366,4 +390,9 @@ static inline int lba_48_ok(u64 block, u
 	return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
 }
 
+#define sata_pmp_gscr_vendor(gscr)	((gscr)[SATA_PMP_GSCR_PROD_ID] & 0xffff)
+#define sata_pmp_gscr_devid(gscr)	((gscr)[SATA_PMP_GSCR_PROD_ID] >> 16)
+#define sata_pmp_gscr_rev(gscr)		(((gscr)[SATA_PMP_GSCR_REV] >> 8) & 0xff)
+#define sata_pmp_gscr_ports(gscr)	((gscr)[SATA_PMP_GSCR_PORT_INFO] & 0xf)
+
 #endif /* __LINUX_ATA_H__ */
-- 
1.3.2



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

* [PATCH 01/17] libata-link: separate out ata_eh_handle_dev_fail()
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 02/17] libata-link: add PMP related ATA constants Tejun Heo
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Separate out ata_eh_handle_dev_fail() from ata_eh_recover().  This is
in preparation of ata_link and PMP support.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-eh.c |   91 +++++++++++++++++++++++++---------------------
 1 files changed, 50 insertions(+), 41 deletions(-)

9f7fbf1bc05472523f3fe382d96a1d0b4dfef2a5
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index bd89608..05f0506 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1892,6 +1892,55 @@ static int ata_eh_skip_recovery(struct a
 	return 1;
 }
 
+static void ata_eh_handle_dev_fail(struct ata_device *dev, int err,
+				   int down_xfermask)
+{
+	struct ata_port *ap = dev->ap;
+	struct ata_eh_context *ehc = &ap->eh_context;
+
+	switch (err) {
+	case -ENODEV:
+		/* device missing, schedule probing */
+		ehc->i.probe_mask |= (1 << dev->devno);
+	case -EINVAL:
+		ehc->tries[dev->devno] = 0;
+		break;
+	case -EIO:
+		sata_down_spd_limit(ap);
+	default:
+		ehc->tries[dev->devno]--;
+		if (down_xfermask &&
+		    ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
+			ehc->tries[dev->devno] = 0;
+	}
+
+	if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
+		/* disable device if it has used up all its chances */
+		ata_dev_disable(dev);
+
+		/* detach if offline */
+		if (ata_port_offline(ap))
+			ata_eh_detach_dev(dev);
+
+		/* probe if requested */
+		if ((ehc->i.probe_mask & (1 << dev->devno)) &&
+		    !(ehc->did_probe_mask & (1 << dev->devno))) {
+			ata_eh_detach_dev(dev);
+			ata_dev_init(dev);
+
+			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+			ehc->did_probe_mask |= (1 << dev->devno);
+			ehc->i.action |= ATA_EH_SOFTRESET;
+		}
+	} else {
+		/* soft didn't work?  be haaaaard */
+		if (ehc->i.flags & ATA_EHI_DID_RESET)
+			ehc->i.action |= ATA_EH_HARDRESET;
+		else
+			ehc->i.action |= ATA_EH_SOFTRESET;
+	}
+}
+
 /**
  *	ata_eh_recover - recover host port after error
  *	@ap: host port to recover
@@ -2003,47 +2052,7 @@ static int ata_eh_recover(struct ata_por
 	goto out;
 
  dev_fail:
-	switch (rc) {
-	case -ENODEV:
-		/* device missing, schedule probing */
-		ehc->i.probe_mask |= (1 << dev->devno);
-	case -EINVAL:
-		ehc->tries[dev->devno] = 0;
-		break;
-	case -EIO:
-		sata_down_spd_limit(ap);
-	default:
-		ehc->tries[dev->devno]--;
-		if (down_xfermask &&
-		    ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
-			ehc->tries[dev->devno] = 0;
-	}
-
-	if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
-		/* disable device if it has used up all its chances */
-		ata_dev_disable(dev);
-
-		/* detach if offline */
-		if (ata_port_offline(ap))
-			ata_eh_detach_dev(dev);
-
-		/* probe if requested */
-		if ((ehc->i.probe_mask & (1 << dev->devno)) &&
-		    !(ehc->did_probe_mask & (1 << dev->devno))) {
-			ata_eh_detach_dev(dev);
-			ata_dev_init(dev);
-
-			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-			ehc->did_probe_mask |= (1 << dev->devno);
-			ehc->i.action |= ATA_EH_SOFTRESET;
-		}
-	} else {
-		/* soft didn't work?  be haaaaard */
-		if (ehc->i.flags & ATA_EHI_DID_RESET)
-			ehc->i.action |= ATA_EH_HARDRESET;
-		else
-			ehc->i.action |= ATA_EH_SOFTRESET;
-	}
+	ata_eh_handle_dev_fail(dev, rc, down_xfermask);
 
 	if (ata_port_nr_enabled(ap)) {
 		ata_port_printk(ap, KERN_WARNING, "failed to recover some "
-- 
1.3.2



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

* [PATCH 03/17] libata-link: introduce ata_link
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
  2006-07-08  5:45 ` [PATCH 01/17] libata-link: separate out ata_eh_handle_dev_fail() Tejun Heo
  2006-07-08  5:45 ` [PATCH 02/17] libata-link: add PMP related ATA constants Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-19 20:26   ` Jeff Garzik
  2006-07-08  5:45 ` [PATCH 05/17] libata-link: linkify PHY-related functions Tejun Heo
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Introduce ata_link.  It abstracts PHY and sits between ata_port and
ata_device.  This new level of abstraction is necessary to support
SATA Port Multiplier, which basically adds a bunch of links (PHYs) to
a ATA host port.  Fields related to command execution, spd_limit and
EH are per-link and thus moved to ata_link.

Except for the host link, each link can be connected to at most one
device and thus contains one struct ata_device.  Slave device (PATA or
emulated SATA) is a special case for the host link and is handled by
struct ata_device storage __dev1 put right after the host link in
struct ata_port.

This patch only defines the host link.  Multiple link handling will be
added later.  Also, a lot of ap->link derefences are added but many of
them will be removed as each part is converted to deal directly with
ata_link instead of ata_port.

This patch introduces no behavior change.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/ahci.c         |   20 +++---
 drivers/scsi/ata_piix.c     |    4 +
 drivers/scsi/libata-bmdma.c |    4 +
 drivers/scsi/libata-core.c  |  147 +++++++++++++++++++++++--------------------
 drivers/scsi/libata-eh.c    |  100 +++++++++++++++--------------
 drivers/scsi/libata-scsi.c  |   40 ++++++------
 drivers/scsi/pdc_adma.c     |    4 +
 drivers/scsi/sata_mv.c      |    6 +-
 drivers/scsi/sata_nv.c      |    4 +
 drivers/scsi/sata_promise.c |    4 +
 drivers/scsi/sata_qstor.c   |    4 +
 drivers/scsi/sata_sil.c     |    8 +-
 drivers/scsi/sata_sil24.c   |   10 +--
 drivers/scsi/sata_sx4.c     |    4 +
 drivers/scsi/sata_vsc.c     |    2 -
 include/linux/libata.h      |   39 +++++++----
 16 files changed, 211 insertions(+), 189 deletions(-)

a083d01fa61bd520c3fc5b6ca4b47f5295a15513
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 30c2722..e3ec344 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -651,7 +651,7 @@ static int ahci_softreset(struct ata_por
 	/* restart engine */
 	ahci_start_engine(ap);
 
-	ata_tf_init(ap->device, &tf);
+	ata_tf_init(ap->link.device, &tf);
 	fis = pp->cmd_tbl;
 
 	/* issue the first D2H Register FIS */
@@ -726,7 +726,7 @@ static int ahci_hardreset(struct ata_por
 	ahci_stop_engine(ap);
 
 	/* clear D2H reception area to properly wait for D2H FIS */
-	ata_tf_init(ap->device, &tf);
+	ata_tf_init(ap->link.device, &tf);
 	tf.command = 0xff;
 	ata_tf_to_fis(&tf, d2h_fis, 0);
 
@@ -845,7 +845,7 @@ static void ahci_qc_prep(struct ata_queu
 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->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	unsigned int err_mask = 0, action = 0;
 	struct ata_queued_cmd *qc;
 	u32 serror;
@@ -892,7 +892,7 @@ static void ahci_error_intr(struct ata_p
 	ehi->serror |= serror;
 	ehi->action |= action;
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc)
 		qc->err_mask |= err_mask;
 	else
@@ -908,7 +908,7 @@ static void ahci_host_intr(struct ata_po
 {
 	void __iomem *mmio = ap->host_set->mmio_base;
 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	u32 status, qc_active;
 	int rc;
 
@@ -920,7 +920,7 @@ static void ahci_host_intr(struct ata_po
 		return;
 	}
 
-	if (ap->sactive)
+	if (ap->link.sactive)
 		qc_active = readl(port_mmio + PORT_SCR_ACT);
 	else
 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
@@ -938,13 +938,13 @@ static void ahci_host_intr(struct ata_po
 	/* hmmm... a spurious interupt */
 
 	/* some devices send D2H reg with I bit set during NCQ command phase */
-	if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+	if (ap->link.sactive && status & PORT_IRQ_D2H_REG_FIS)
 		return;
 
 	/* ignore interim PIO setup fis interrupts */
-	if (ata_tag_valid(ap->active_tag)) {
+	if (ata_tag_valid(ap->link.active_tag)) {
 		struct ata_queued_cmd *qc =
-			ata_qc_from_tag(ap, ap->active_tag);
+			ata_qc_from_tag(ap, ap->link.active_tag);
 
 		if (qc && qc->tf.protocol == ATA_PROT_PIO &&
 		    (status & PORT_IRQ_PIOS_FIS))
@@ -954,7 +954,7 @@ static void ahci_host_intr(struct ata_po
 	if (ata_ratelimit())
 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
 				"(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
-				status, ap->active_tag, ap->sactive);
+				status, ap->link.active_tag, ap->link.sactive);
 }
 
 static void ahci_irq_clear(struct ata_port *ap)
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 94b1261..9e24049 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -475,7 +475,7 @@ static int piix_pata_prereset(struct ata
 
 	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
 		ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
-		ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+		ap->link.eh_context.i.action &= ~ATA_EH_RESET_MASK;
 		return 0;
 	}
 
@@ -549,7 +549,7 @@ static int piix_sata_prereset(struct ata
 
 	if (!present_mask) {
 		ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
-		ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+		ap->link.eh_context.i.action &= ~ATA_EH_RESET_MASK;
 		return 0;
 	}
 
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 9ce221f..c931a26 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -714,12 +714,12 @@ void ata_bmdma_drive_eh(struct ata_port 
 			ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 			ata_postreset_fn_t postreset)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	struct ata_queued_cmd *qc;
 	unsigned long flags;
 	int thaw = 0;
 
-	qc = __ata_qc_from_tag(ap, ap->active_tag);
+	qc = __ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
 		qc = NULL;
 
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1021c72..9e19d12 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -421,7 +421,7 @@ static const char *sata_spd_string(unsig
 
 void ata_dev_disable(struct ata_device *dev)
 {
-	if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
+	if (ata_dev_enabled(dev) && ata_msg_drv(dev->link->ap)) {
 		ata_dev_printk(dev, KERN_WARNING, "disabled\n");
 		dev->class++;
 	}
@@ -790,7 +790,7 @@ void ata_dev_select(struct ata_port *ap,
 	ap->ops->dev_select(ap, device);
 
 	if (wait) {
-		if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+		if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
 			msleep(150);
 		ata_wait_idle(ap);
 	}
@@ -996,7 +996,8 @@ unsigned ata_exec_internal(struct ata_de
 			   struct ata_taskfile *tf, const u8 *cdb,
 			   int dma_dir, void *buf, unsigned int buflen)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	u8 command = tf->command;
 	struct ata_queued_cmd *qc;
 	unsigned int tag, preempted_tag;
@@ -1036,11 +1037,11 @@ unsigned ata_exec_internal(struct ata_de
 	qc->dev = dev;
 	ata_qc_reinit(qc);
 
-	preempted_tag = ap->active_tag;
-	preempted_sactive = ap->sactive;
+	preempted_tag = link->active_tag;
+	preempted_sactive = link->sactive;
 	preempted_qc_active = ap->qc_active;
-	ap->active_tag = ATA_TAG_POISON;
-	ap->sactive = 0;
+	link->active_tag = ATA_TAG_POISON;
+	link->sactive = 0;
 	ap->qc_active = 0;
 
 	/* prepare & issue qc */
@@ -1108,8 +1109,8 @@ unsigned ata_exec_internal(struct ata_de
 	err_mask = qc->err_mask;
 
 	ata_qc_free(qc);
-	ap->active_tag = preempted_tag;
-	ap->sactive = preempted_sactive;
+	link->active_tag = preempted_tag;
+	link->sactive = preempted_sactive;
 	ap->qc_active = preempted_qc_active;
 
 	/* XXX - Some LLDDs (sata_mv) disable port on command failure.
@@ -1214,7 +1215,7 @@ unsigned int ata_pio_need_iordy(const st
 int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 		    int post_reset, u16 *id)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	unsigned int class = *p_class;
 	struct ata_taskfile tf;
 	unsigned int err_mask = 0;
@@ -1300,13 +1301,14 @@ int ata_dev_read_id(struct ata_device *d
 
 static inline u8 ata_dev_knobble(struct ata_device *dev)
 {
-	return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+	struct ata_port *ap = dev->link->ap;
+	return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
 }
 
 static void ata_dev_config_ncq(struct ata_device *dev,
 			       char *desc, size_t desc_sz)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
 
 	if (!ata_id_has_ncq(dev->id)) {
@@ -1334,7 +1336,7 @@ static void ata_set_port_max_cmd_len(str
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
 			ap->host->max_cmd_len = max_t(unsigned int,
 						      ap->host->max_cmd_len,
-						      ap->device[i].cdb_len);
+						      ap->link.device[i].cdb_len);
 	}
 }
 
@@ -1354,7 +1356,7 @@ static void ata_set_port_max_cmd_len(str
  */
 int ata_dev_configure(struct ata_device *dev, int print_info)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	const u16 *id = dev->id;
 	unsigned int xfer_mask;
 	int rc;
@@ -1547,7 +1549,7 @@ static int ata_bus_probe(struct ata_port
 	ap->ops->phy_reset(ap);
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		if (!(ap->flags & ATA_FLAG_DISABLED) &&
 		    dev->class != ATA_DEV_UNKNOWN)
@@ -1564,11 +1566,11 @@ static int ata_bus_probe(struct ata_port
 	   state is undefined. Record the mode */
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ap->device[i].pio_mode = XFER_PIO_0;
+		ap->link.device[i].pio_mode = XFER_PIO_0;
 
 	/* read IDENTIFY page and configure devices */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		if (tries[i])
 			dev->class = classes[i];
@@ -1593,7 +1595,7 @@ static int ata_bus_probe(struct ata_port
 	}
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_enabled(&ap->device[i]))
+		if (ata_dev_enabled(&ap->link.device[i]))
 			return 0;
 
 	/* no device present, disable port */
@@ -1754,8 +1756,8 @@ void sata_phy_reset(struct ata_port *ap)
 
 struct ata_device *ata_dev_pair(struct ata_device *adev)
 {
-	struct ata_port *ap = adev->ap;
-	struct ata_device *pair = &ap->device[1 - adev->devno];
+	struct ata_link *link = adev->link;
+	struct ata_device *pair = &link->device[1 - adev->devno];
 	if (!ata_dev_enabled(pair))
 		return NULL;
 	return pair;
@@ -1776,8 +1778,8 @@ struct ata_device *ata_dev_pair(struct a
 
 void ata_port_disable(struct ata_port *ap)
 {
-	ap->device[0].class = ATA_DEV_NONE;
-	ap->device[1].class = ATA_DEV_NONE;
+	ap->link.device[0].class = ATA_DEV_NONE;
+	ap->link.device[1].class = ATA_DEV_NONE;
 	ap->flags |= ATA_FLAG_DISABLED;
 }
 
@@ -1804,7 +1806,7 @@ int sata_down_spd_limit(struct ata_port 
 	if (rc)
 		return rc;
 
-	mask = ap->sata_spd_limit;
+	mask = ap->link.sata_spd_limit;
 	if (mask <= 1)
 		return -EINVAL;
 	highbit = fls(mask) - 1;
@@ -1818,7 +1820,7 @@ int sata_down_spd_limit(struct ata_port 
 	if (!mask)
 		return -EINVAL;
 
-	ap->sata_spd_limit = mask;
+	ap->link.sata_spd_limit = mask;
 
 	ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
 			sata_spd_string(fls(mask)));
@@ -1830,10 +1832,10 @@ static int __sata_set_spd_needed(struct 
 {
 	u32 spd, limit;
 
-	if (ap->sata_spd_limit == UINT_MAX)
+	if (ap->link.sata_spd_limit == UINT_MAX)
 		limit = 0;
 	else
-		limit = fls(ap->sata_spd_limit);
+		limit = fls(ap->link.sata_spd_limit);
 
 	spd = (*scontrol >> 4) & 0xf;
 	*scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
@@ -1846,7 +1848,7 @@ static int __sata_set_spd_needed(struct 
  *	@ap: Port in question
  *
  *	Test whether the spd limit in SControl matches
- *	@ap->sata_spd_limit.  This function is used to determine
+ *	@ap->link.sata_spd_limit.  This function is used to determine
  *	whether hardreset is necessary to apply SATA spd
  *	configuration.
  *
@@ -2146,7 +2148,7 @@ int ata_set_mode(struct ata_port *ap, st
 		 * return error code and failing device on failure.
 		 */
 		for (i = 0; i < ATA_MAX_DEVICES; i++) {
-			if (ata_dev_ready(&ap->device[i])) {
+			if (ata_dev_ready(&ap->link.device[i])) {
 				ap->ops->set_mode(ap);
 				break;
 			}
@@ -2158,7 +2160,7 @@ int ata_set_mode(struct ata_port *ap, st
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		unsigned int pio_mask, dma_mask;
 
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		if (!ata_dev_enabled(dev))
 			continue;
@@ -2179,7 +2181,7 @@ int ata_set_mode(struct ata_port *ap, st
 
 	/* step 2: always set host PIO timings */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 		if (!ata_dev_enabled(dev))
 			continue;
 
@@ -2197,7 +2199,7 @@ int ata_set_mode(struct ata_port *ap, st
 
 	/* step 3: set host DMA timings */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		if (!ata_dev_enabled(dev) || !dev->dma_mode)
 			continue;
@@ -2210,7 +2212,7 @@ int ata_set_mode(struct ata_port *ap, st
 
 	/* step 4: update devices' xfer mode */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		/* don't udpate suspended devices' xfer mode */
 		if (!ata_dev_ready(dev))
@@ -2419,6 +2421,7 @@ static unsigned int ata_bus_softreset(st
 
 void ata_bus_reset(struct ata_port *ap)
 {
+	struct ata_device *device = ap->link.device;
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	u8 err;
@@ -2451,23 +2454,23 @@ void ata_bus_reset(struct ata_port *ap)
 	/*
 	 * determine by signature whether we have ATA or ATAPI devices
 	 */
-	ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+	device[0].class = ata_dev_try_classify(ap, 0, &err);
 	if ((slave_possible) && (err != 0x81))
-		ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+		device[1].class = ata_dev_try_classify(ap, 1, &err);
 
 	/* re-enable interrupts */
 	if (ap->ioaddr.ctl_addr)	/* FIXME: hack. create a hook instead */
 		ata_irq_on(ap);
 
 	/* is double-select really necessary? */
-	if (ap->device[1].class != ATA_DEV_NONE)
+	if (device[1].class != ATA_DEV_NONE)
 		ap->ops->dev_select(ap, 1);
-	if (ap->device[0].class != ATA_DEV_NONE)
+	if (device[0].class != ATA_DEV_NONE)
 		ap->ops->dev_select(ap, 0);
 
 	/* if no devices were detected, disable this port */
-	if ((ap->device[0].class == ATA_DEV_NONE) &&
-	    (ap->device[1].class == ATA_DEV_NONE))
+	if ((device[0].class == ATA_DEV_NONE) &&
+	    (device[1].class == ATA_DEV_NONE))
 		goto err_out;
 
 	if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
@@ -2583,7 +2586,7 @@ int sata_phy_resume(struct ata_port *ap,
 
 static void ata_wait_spinup(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	unsigned long end, secs;
 	int rc;
 
@@ -2624,7 +2627,7 @@ static void ata_wait_spinup(struct ata_p
  */
 int ata_std_prereset(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	int rc;
 
@@ -2730,7 +2733,7 @@ int ata_std_softreset(struct ata_port *a
  */
 int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	u32 scontrol;
 	int rc;
@@ -2992,7 +2995,7 @@ static int ata_dev_same_device(struct at
 int ata_dev_revalidate(struct ata_device *dev, int post_reset)
 {
 	unsigned int class = dev->class;
-	u16 *id = (void *)dev->ap->sector_buf;
+	u16 *id = (void *)dev->link->ap->sector_buf;
 	int rc;
 
 	if (!ata_dev_enabled(dev)) {
@@ -3079,7 +3082,7 @@ static int ata_dma_blacklisted(const str
 	 * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
 	 * if the LLDD handles only interrupts in the HSM_ST_LAST state.
 	 */
-	if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+	if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) &&
 	    (dev->flags & ATA_DFLAG_CDB_INTR))
 		return 1;
 
@@ -3119,7 +3122,8 @@ static int ata_dma_blacklisted(const str
  */
 static void ata_dev_xfermask(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	struct ata_host_set *hs = ap->host_set;
 	unsigned long xfer_mask;
 	int i;
@@ -3135,7 +3139,7 @@ static void ata_dev_xfermask(struct ata_
 
 	/* FIXME: Use port-wide xfermask for now */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *d = &ap->device[i];
+		struct ata_device *d = &link->device[i];
 
 		if (ata_dev_absent(d))
 			continue;
@@ -3641,7 +3645,7 @@ #endif /* __BIG_ENDIAN */
 void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
 			unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	unsigned int i;
 	unsigned int words = buflen >> 1;
 	u16 *buf16 = (u16 *) buf;
@@ -3687,7 +3691,7 @@ void ata_mmio_data_xfer(struct ata_devic
 void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
 		       unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	unsigned int words = buflen >> 1;
 
 	/* Transfer multiple of 2 bytes */
@@ -4389,7 +4393,7 @@ static struct ata_queued_cmd *ata_qc_new
 
 struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct ata_queued_cmd *qc;
 
 	qc = ata_qc_new(ap);
@@ -4432,6 +4436,7 @@ void ata_qc_free(struct ata_queued_cmd *
 void __ata_qc_complete(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
+	struct ata_link *link = qc->dev->link;
 
 	WARN_ON(qc == NULL);	/* ata_qc_from_tag _might_ return NULL */
 	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -4441,9 +4446,9 @@ void __ata_qc_complete(struct ata_queued
 
 	/* command should be marked inactive atomically with qc completion */
 	if (qc->tf.protocol == ATA_PROT_NCQ)
-		ap->sactive &= ~(1 << qc->tag);
+		link->sactive &= ~(1 << qc->tag);
 	else
-		ap->active_tag = ATA_TAG_POISON;
+		link->active_tag = ATA_TAG_POISON;
 
 	/* atapi: mark qc as inactive to prevent the interrupt handler
 	 * from completing the command twice later, before the error handler
@@ -4604,19 +4609,20 @@ static inline int ata_should_dma_map(str
 void ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
+	struct ata_link *link = qc->dev->link;
 
 	/* Make sure only one non-NCQ command is outstanding.  The
 	 * check is skipped for old EH because it reuses active qc to
 	 * request ATAPI sense.
 	 */
-	WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+	WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
 
 	if (qc->tf.protocol == ATA_PROT_NCQ) {
-		WARN_ON(ap->sactive & (1 << qc->tag));
-		ap->sactive |= 1 << qc->tag;
+		WARN_ON(link->sactive & (1 << qc->tag));
+		link->sactive |= 1 << qc->tag;
 	} else {
-		WARN_ON(ap->sactive);
-		ap->active_tag = qc->tag;
+		WARN_ON(link->sactive);
+		link->active_tag = qc->tag;
 	}
 
 	qc->flags |= ATA_QCFLAG_ACTIVE;
@@ -4907,7 +4913,7 @@ irqreturn_t ata_interrupt (int irq, void
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
 			    (qc->flags & ATA_QCFLAG_ACTIVE))
 				handled |= ata_host_intr(ap, qc);
@@ -5107,8 +5113,8 @@ static int ata_host_set_request_pm(struc
 		}
 
 		ap->pflags |= ATA_PFLAG_PM_PENDING;
-		ap->eh_info.action |= action;
-		ap->eh_info.flags |= ehi_flags;
+		ap->link.eh_info.action |= action;
+		ap->link.eh_info.flags |= ehi_flags;
 
 		ata_port_schedule_eh(ap);
 
@@ -5157,7 +5163,7 @@ int ata_host_set_suspend(struct ata_host
 		struct ata_port *ap = host_set->ports[i];
 
 		for (j = 0; j < ATA_MAX_DEVICES; j++) {
-			struct ata_device *dev = &ap->device[j];
+			struct ata_device *dev = &ap->link.device[j];
 
 			if (ata_dev_ready(dev)) {
 				ata_port_printk(ap, KERN_WARNING,
@@ -5288,11 +5294,12 @@ static void ata_host_remove(struct ata_p
  */
 void ata_dev_init(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
 	/* SATA spd limit is bound to the first device */
-	ap->sata_spd_limit = ap->hw_sata_spd_limit;
+	link->sata_spd_limit = link->hw_sata_spd_limit;
 
 	/* High bits of dev->flags are used to record warm plug
 	 * requests which occur asynchronously.  Synchronize using
@@ -5350,8 +5357,8 @@ static void ata_host_init(struct ata_por
 	ap->udma_mask = ent->udma_mask;
 	ap->flags |= ent->host_flags;
 	ap->ops = ent->port_ops;
-	ap->hw_sata_spd_limit = UINT_MAX;
-	ap->active_tag = ATA_TAG_POISON;
+	ap->link.hw_sata_spd_limit = UINT_MAX;
+	ap->link.active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
 #if defined(ATA_VERBOSE_DEBUG)
@@ -5375,9 +5382,11 @@ #endif
 	if (ap->flags & ATA_FLAG_SATA)
 		ap->cbl = ATA_CBL_SATA;
 
+	ap->link.ap = ap;
+
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		dev->ap = ap;
+		struct ata_device *dev = &ap->link.device[i];
+		dev->link = &ap->link;
 		dev->devno = i;
 		ata_dev_init(dev);
 	}
@@ -5538,9 +5547,9 @@ int ata_device_add(const struct ata_prob
 		/* init sata_spd_limit to the current value */
 		if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
 			int spd = (scontrol >> 4) & 0xf;
-			ap->hw_sata_spd_limit &= (1 << spd) - 1;
+			ap->link.hw_sata_spd_limit &= (1 << spd) - 1;
 		}
-		ap->sata_spd_limit = ap->hw_sata_spd_limit;
+		ap->link.sata_spd_limit = ap->link.hw_sata_spd_limit;
 
 		rc = scsi_add_host(ap->host, dev);
 		if (rc) {
@@ -5553,7 +5562,7 @@ int ata_device_add(const struct ata_prob
 		}
 
 		if (ap->ops->error_handler) {
-			struct ata_eh_info *ehi = &ap->eh_info;
+			struct ata_eh_info *ehi = &ap->link.eh_info;
 			unsigned long flags;
 
 			ata_port_probe(ap);
@@ -5644,7 +5653,7 @@ void ata_port_detach(struct ata_port *ap
 	spin_lock_irqsave(ap->lock, flags);
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ata_dev_disable(&ap->device[i]);
+		ata_dev_disable(&ap->link.device[i]);
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 05f0506..80cdfc2 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -110,7 +110,7 @@ static int ata_ering_map(struct ata_erin
 
 static unsigned int ata_eh_dev_action(struct ata_device *dev)
 {
-	struct ata_eh_context *ehc = &dev->ap->eh_context;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
 
 	return ehc->i.action | ehc->i.dev_action[dev->devno];
 }
@@ -176,7 +176,7 @@ enum scsi_eh_timer_return ata_scsi_timed
 
 	ret = EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
@@ -283,9 +283,9 @@ void ata_scsi_error(struct Scsi_Host *ho
 		/* fetch & clear EH info */
 		spin_lock_irqsave(ap->lock, flags);
 
-		memset(&ap->eh_context, 0, sizeof(ap->eh_context));
-		ap->eh_context.i = ap->eh_info;
-		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+		memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context));
+		ap->link.eh_context.i = ap->link.eh_info;
+		memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info));
 
 		ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
 		ap->pflags &= ~ATA_PFLAG_EH_PENDING;
@@ -320,7 +320,7 @@ void ata_scsi_error(struct Scsi_Host *ho
 		}
 
 		/* this run is complete, make sure EH info is clear */
-		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+		memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info));
 
 		/* Clear host_eh_scheduled while holding ap->lock such
 		 * that if exception occurs after this point but
@@ -331,7 +331,7 @@ void ata_scsi_error(struct Scsi_Host *ho
 
 		spin_unlock_irqrestore(ap->lock, flags);
 	} else {
-		WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+		WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
 		ap->ops->eng_timeout(ap);
 	}
 
@@ -486,7 +486,7 @@ void ata_eng_timeout(struct ata_port *ap
 {
 	DPRINTK("ENTER\n");
 
-	ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+	ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
 
 	DPRINTK("EXIT\n");
 }
@@ -747,7 +747,7 @@ void ata_eh_qc_retry(struct ata_queued_c
  */
 static void ata_eh_detach_dev(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	unsigned long flags;
 
 	ata_dev_disable(dev);
@@ -762,8 +762,8 @@ static void ata_eh_detach_dev(struct ata
 	}
 
 	/* clear per-dev EH actions */
-	ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
-	ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+	ata_eh_clear_action(dev, &dev->link->eh_info, ATA_EH_PERDEV_MASK);
+	ata_eh_clear_action(dev, &dev->link->eh_context.i, ATA_EH_PERDEV_MASK);
 
 	spin_unlock_irqrestore(ap->lock, flags);
 }
@@ -775,8 +775,8 @@ static void ata_eh_detach_dev(struct ata
  *	@action: action about to be performed
  *
  *	Called just before performing EH actions to clear related bits
- *	in @ap->eh_info such that eh actions are not unnecessarily
- *	repeated.
+ *	in @ap->link.eh_info such that eh actions are not
+ *	unnecessarily repeated.
  *
  *	LOCKING:
  *	None.
@@ -788,9 +788,9 @@ static void ata_eh_about_to_do(struct at
 
 	spin_lock_irqsave(ap->lock, flags);
 
-	ata_eh_clear_action(dev, &ap->eh_info, action);
+	ata_eh_clear_action(dev, &ap->link.eh_info, action);
 
-	if (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
+	if (!(ap->link.eh_context.i.flags & ATA_EHI_QUIET))
 		ap->pflags |= ATA_PFLAG_RECOVERED;
 
 	spin_unlock_irqrestore(ap->lock, flags);
@@ -803,7 +803,7 @@ static void ata_eh_about_to_do(struct at
  *	@action: action just completed
  *
  *	Called right after performing EH actions to clear related bits
- *	in @ap->eh_context.
+ *	in @ap->link.eh_context.
  *
  *	LOCKING:
  *	None.
@@ -811,7 +811,7 @@ static void ata_eh_about_to_do(struct at
 static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
 			unsigned int action)
 {
-	ata_eh_clear_action(dev, &ap->eh_context.i, action);
+	ata_eh_clear_action(dev, &ap->link.eh_context.i, action);
 }
 
 /**
@@ -905,7 +905,7 @@ static unsigned int ata_read_log_page(st
 static int ata_eh_read_log_10h(struct ata_device *dev,
 			       int *tag, struct ata_taskfile *tf)
 {
-	u8 *buf = dev->ap->sector_buf;
+	u8 *buf = dev->link->ap->sector_buf;
 	unsigned int err_mask;
 	u8 csum;
 	int i;
@@ -958,7 +958,7 @@ static int ata_eh_read_log_10h(struct at
 static unsigned int atapi_eh_request_sense(struct ata_device *dev,
 					   unsigned char *sense_buf)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct ata_taskfile tf;
 	u8 cdb[ATAPI_CDB_LEN];
 
@@ -1009,7 +1009,7 @@ static unsigned int atapi_eh_request_sen
  */
 static void ata_eh_analyze_serror(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	u32 serror = ehc->i.serror;
 	unsigned int err_mask = 0, action = 0;
 
@@ -1051,8 +1051,8 @@ static void ata_eh_analyze_serror(struct
  */
 static void ata_eh_analyze_ncq_error(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
-	struct ata_device *dev = ap->device;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_device *dev = ap->link.device;
 	struct ata_queued_cmd *qc;
 	struct ata_taskfile tf;
 	int tag, rc;
@@ -1062,7 +1062,7 @@ static void ata_eh_analyze_ncq_error(str
 		return;
 
 	/* is it NCQ device error? */
-	if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+	if (!ap->link.sactive || !(ehc->i.err_mask & AC_ERR_DEV))
 		return;
 
 	/* has LLDD analyzed already? */
@@ -1084,7 +1084,7 @@ static void ata_eh_analyze_ncq_error(str
 		return;
 	}
 
-	if (!(ap->sactive & (1 << tag))) {
+	if (!(ap->link.sactive & (1 << tag))) {
 		ata_port_printk(ap, KERN_ERR, "log page 10h reported "
 				"inactive tag %d\n", tag);
 		return;
@@ -1271,7 +1271,7 @@ static int ata_eh_speed_down(struct ata_
 		return 0;
 
 	/* speed down SATA link speed if possible */
-	if (sata_down_spd_limit(dev->ap) == 0)
+	if (sata_down_spd_limit(dev->link->ap) == 0)
 		return ATA_EH_HARDRESET;
 
 	/* lower transfer mode */
@@ -1296,7 +1296,7 @@ static int ata_eh_speed_down(struct ata_
  */
 static void ata_eh_autopsy(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	unsigned int action = ehc->i.action;
 	struct ata_device *failed_dev = NULL;
 	unsigned int all_err_mask = 0;
@@ -1396,7 +1396,7 @@ static void ata_eh_autopsy(struct ata_po
  */
 static void ata_eh_report(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	const char *frozen, *desc;
 	int tag, nr_failed = 0;
 
@@ -1425,15 +1425,15 @@ static void ata_eh_report(struct ata_por
 	if (ehc->i.dev) {
 		ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
 			       "SAct 0x%x SErr 0x%x action 0x%x%s\n",
-			       ehc->i.err_mask, ap->sactive, ehc->i.serror,
-			       ehc->i.action, frozen);
+			       ehc->i.err_mask, ap->link.sactive,
+			       ehc->i.serror, ehc->i.action, frozen);
 		if (desc)
 			ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
 	} else {
 		ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
 				"SAct 0x%x SErr 0x%x action 0x%x%s\n",
-				ehc->i.err_mask, ap->sactive, ehc->i.serror,
-				ehc->i.action, frozen);
+				ehc->i.err_mask, ap->link.sactive,
+				ehc->i.serror, ehc->i.action, frozen);
 		if (desc)
 			ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
 	}
@@ -1496,7 +1496,7 @@ static int ata_eh_reset(struct ata_port 
 			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
 			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
 	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
@@ -1610,7 +1610,7 @@ static int ata_eh_reset(struct ata_port 
 		 * controller state is undefined.  Record the mode.
 		 */
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ap->device[i].pio_mode = XFER_PIO_0;
+			ap->link.device[i].pio_mode = XFER_PIO_0;
 
 		if (postreset)
 			postreset(ap, classes);
@@ -1626,7 +1626,7 @@ static int ata_eh_reset(struct ata_port 
 static int ata_eh_revalidate_and_attach(struct ata_port *ap,
 					struct ata_device **r_failed_dev)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	struct ata_device *dev;
 	unsigned long flags;
 	int i, rc = 0;
@@ -1636,7 +1636,7 @@ static int ata_eh_revalidate_and_attach(
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		unsigned int action;
 
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 		action = ata_eh_dev_action(dev);
 
 		if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
@@ -1709,7 +1709,7 @@ static int ata_eh_suspend(struct ata_por
 		unsigned long flags;
 		unsigned int action, err_mask;
 
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 		action = ata_eh_dev_action(dev);
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
@@ -1772,7 +1772,7 @@ static void ata_eh_prep_resume(struct at
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		unsigned int action;
 
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 		action = ata_eh_dev_action(dev);
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
@@ -1810,7 +1810,7 @@ static int ata_eh_resume(struct ata_port
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		unsigned int action, err_mask;
 
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 		action = ata_eh_dev_action(dev);
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
@@ -1845,7 +1845,7 @@ static int ata_port_nr_enabled(struct at
 	int i, cnt = 0;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_enabled(&ap->device[i]))
+		if (ata_dev_enabled(&ap->link.device[i]))
 			cnt++;
 	return cnt;
 }
@@ -1855,19 +1855,19 @@ static int ata_port_nr_vacant(struct ata
 	int i, cnt = 0;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ap->device[i].class == ATA_DEV_UNKNOWN)
+		if (ap->link.device[i].class == ATA_DEV_UNKNOWN)
 			cnt++;
 	return cnt;
 }
 
 static int ata_eh_skip_recovery(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	int i;
 
 	/* skip if all possible devices are suspended */
 	for (i = 0; i < ata_port_max_devices(ap); i++) {
-		struct ata_device *dev = &ap->device[i];
+		struct ata_device *dev = &ap->link.device[i];
 
 		if (ata_dev_absent(dev) || ata_dev_ready(dev))
 			break;
@@ -1882,7 +1882,7 @@ static int ata_eh_skip_recovery(struct a
 
 	/* skip if class codes for all vacant slots are ATA_DEV_NONE */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+		struct ata_device *dev = &ap->link.device[i];
 
 		if (dev->class == ATA_DEV_UNKNOWN &&
 		    ehc->classes[dev->devno] != ATA_DEV_NONE)
@@ -1895,8 +1895,8 @@ static int ata_eh_skip_recovery(struct a
 static void ata_eh_handle_dev_fail(struct ata_device *dev, int err,
 				   int down_xfermask)
 {
-	struct ata_port *ap = dev->ap;
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = dev->link->ap;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
 
 	switch (err) {
 	case -ENODEV:
@@ -1966,7 +1966,7 @@ static int ata_eh_recover(struct ata_por
 			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 			  ata_postreset_fn_t postreset)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	struct ata_device *dev;
 	int down_xfermask, i, rc;
 
@@ -1974,7 +1974,7 @@ static int ata_eh_recover(struct ata_por
 
 	/* prep for recovery */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
@@ -2071,7 +2071,7 @@ static int ata_eh_recover(struct ata_por
 		ata_hp_poll_activate(ap);
 
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ata_dev_disable(&ap->device[i]);
+			ata_dev_disable(&ap->link.device[i]);
 	}
 
 	DPRINTK("EXIT, rc=%d\n", rc);
@@ -2236,7 +2236,7 @@ static void ata_eh_handle_port_resume(st
 	timeout = jiffies + HZ; /* 1s max */
 	while (1) {
 		for (i = 0; i < ATA_MAX_DEVICES; i++) {
-			struct ata_device *dev = &ap->device[i];
+			struct ata_device *dev = &ap->link.device[i];
 			unsigned int action = ata_eh_dev_action(dev);
 
 			if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
@@ -2286,7 +2286,7 @@ static void ata_hp_poll_worker(void *dat
 		rc = ap->ops->hp_poll(ap);
 		if (rc) {
 			if (rc > 0) {
-				ata_ehi_hotplugged(&ap->eh_info);
+				ata_ehi_hotplugged(&ap->link.eh_info);
 				ata_port_freeze(ap);
 			}
 			list_del_init(&ap->hp_poll_entry);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 7ced41e..c947da7 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -440,8 +440,8 @@ int ata_scsi_device_suspend(struct scsi_
 	action = ATA_EH_SUSPEND;
 	if (state.event != PM_EVENT_SUSPEND)
 		action |= ATA_EH_PM_FREEZE;
-	ap->eh_info.dev_action[dev->devno] |= action;
-	ap->eh_info.flags |= ATA_EHI_QUIET;
+	dev->link->eh_info.dev_action[dev->devno] |= action;
+	dev->link->eh_info.flags |= ATA_EHI_QUIET;
 	ata_port_schedule_eh(ap);
 
 	spin_unlock_irqrestore(ap->lock, flags);
@@ -485,7 +485,7 @@ int ata_scsi_device_resume(struct scsi_d
 {
 	struct ata_port *ap = ata_shost_to_port(sdev->host);
 	struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi;
 	unsigned long flags;
 	unsigned int action;
 
@@ -500,6 +500,7 @@ int ata_scsi_device_resume(struct scsi_d
 		goto out_unlock;
 
 	/* request resume */
+	ehi = &dev->link->eh_info;
 	action = ATA_EH_RESUME;
 	if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
 		__ata_ehi_hotplugged(ehi);
@@ -1420,7 +1421,7 @@ static void ata_scsi_qc_complete(struct 
 	if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
 	    ((qc->tf.feature == SETFEATURES_WC_ON) ||
 	     (qc->tf.feature == SETFEATURES_WC_OFF))) {
-		qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
+		qc->dev->link->eh_info.action |= ATA_EH_REVALIDATE;
 		ata_port_schedule_eh(qc->ap);
 	}
 
@@ -1474,16 +1475,16 @@ static void ata_scsi_qc_complete(struct 
  */
 static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
 
 	if (!(dev->flags & ATA_DFLAG_NCQ))
 		return 0;
 
 	if (is_io) {
-		if (!ata_tag_valid(ap->active_tag))
+		if (!ata_tag_valid(link->active_tag))
 			return 0;
 	} else {
-		if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
+		if (!ata_tag_valid(link->active_tag) && !link->sactive)
 			return 0;
 	}
 	return 1;
@@ -2466,7 +2467,7 @@ static unsigned int atapi_xlat(struct at
 static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
 {
 	if (likely(id < ATA_MAX_DEVICES))
-		return &ap->device[id];
+		return &ap->link.device[id];
 	return NULL;
 }
 
@@ -2498,7 +2499,7 @@ static int ata_scsi_dev_enabled(struct a
 	if (unlikely(!ata_dev_enabled(dev)))
 		return 0;
 
-	if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+	if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
 		if (unlikely(dev->class == ATA_DEV_ATAPI)) {
 			ata_dev_printk(dev, KERN_WARNING,
 				       "WARNING: ATAPI is %s, device ignored.\n",
@@ -2925,7 +2926,7 @@ void ata_scsi_scan_host(struct ata_port 
 		return;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+		struct ata_device *dev = &ap->link.device[i];
 		struct scsi_device *sdev;
 
 		if (!ata_dev_enabled(dev) || dev->sdev)
@@ -2975,7 +2976,7 @@ int ata_scsi_offline_dev(struct ata_devi
  */
 static void ata_scsi_remove_dev(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct scsi_device *sdev;
 	unsigned long flags;
 
@@ -3048,7 +3049,7 @@ void ata_scsi_hotplug(void *data)
 
 	/* unplug detached devices */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+		struct ata_device *dev = &ap->link.device[i];
 		unsigned long flags;
 
 		if (!(dev->flags & ATA_DFLAG_DETACHED))
@@ -3069,7 +3070,7 @@ void ata_scsi_hotplug(void *data)
 	 * unattached devices.
 	 */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+		struct ata_device *dev = &ap->link.device[i];
 		if (ata_dev_enabled(dev) && !dev->sdev) {
 			queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
 			break;
@@ -3099,6 +3100,7 @@ static int ata_scsi_user_scan(struct Scs
 			      unsigned int id, unsigned int lun)
 {
 	struct ata_port *ap = ata_shost_to_port(shost);
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	unsigned long flags;
 	int rc = 0;
 
@@ -3112,15 +3114,15 @@ static int ata_scsi_user_scan(struct Scs
 	spin_lock_irqsave(ap->lock, flags);
 
 	if (id == SCAN_WILD_CARD) {
-		ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
-		ap->eh_info.action |= ATA_EH_SOFTRESET;
+		ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+		ehi->action |= ATA_EH_SOFTRESET;
 	} else {
 		struct ata_device *dev = ata_find_dev(ap, id);
 
 		if (dev) {
-			ap->eh_info.probe_mask |= 1 << dev->devno;
-			ap->eh_info.action |= ATA_EH_SOFTRESET;
-			ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+			ehi->probe_mask |= 1 << dev->devno;
+			ehi->action |= ATA_EH_SOFTRESET;
+			ehi->flags |= ATA_EHI_RESUME_LINK;
 		} else
 			rc = -EINVAL;
 	}
@@ -3152,7 +3154,7 @@ void ata_scsi_dev_rescan(void *data)
 	unsigned int i;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		if (ata_dev_enabled(dev) && dev->sdev)
 			scsi_rescan_device(&(dev->sdev->sdev_gendev));
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index d1f38c3..c5fa35f 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -462,7 +462,7 @@ static inline unsigned int adma_intr_pkt
 		pp = ap->private_data;
 		if (!pp || pp->state != adma_state_pkt)
 			continue;
-		qc = ata_qc_from_tag(ap, ap->active_tag);
+		qc = ata_qc_from_tag(ap, ap->link.active_tag);
 		if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 			if ((status & (aPERR | aPSD | aUIRQ)))
 				qc->err_mask |= AC_ERR_OTHER;
@@ -487,7 +487,7 @@ static inline unsigned int adma_intr_mmi
 			struct adma_port_priv *pp = ap->private_data;
 			if (!pp || pp->state != adma_state_mmio)
 				continue;
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 
 				/* check main status, clearing INTRQ */
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 1053c7c..8c4d9be 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -1417,7 +1417,7 @@ static void mv_host_intr(struct ata_host
 		}
 
 		if (handled) {
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
 				VPRINTK("port %u IRQ found for qc, "
 					"ata_status 0x%x\n", port,ata_status);
@@ -1939,7 +1939,7 @@ static void __mv_phy_reset(struct ata_po
 	struct mv_host_priv *hpriv = ap->host_set->private_data;
 	void __iomem *port_mmio = mv_ap_base(ap);
 	struct ata_taskfile tf;
-	struct ata_device *dev = &ap->device[0];
+	struct ata_device *dev = &ap->link.device[0];
 	unsigned long timeout;
 	int retry = 5;
 	u32 sstatus;
@@ -2047,7 +2047,7 @@ static void mv_eng_timeout(struct ata_po
 	mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no,
 			 to_pci_dev(ap->host_set->dev));
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
         printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
 	       ap->host_set->mmio_base, ap, qc, qc->scsicmd,
 	       &qc->scsicmd->cmnd);
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 7bd9305..6659faa 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -314,7 +314,7 @@ static irqreturn_t nv_generic_interrupt(
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 				handled += ata_host_intr(ap, qc);
 			else
@@ -332,7 +332,7 @@ static irqreturn_t nv_generic_interrupt(
 
 static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
 {
-	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	int handled;
 
 	/* freeze if hotplugged */
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 64631bd..74ec4cd 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -445,7 +445,7 @@ static void pdc_eng_timeout(struct ata_p
 
 	spin_lock_irqsave(&host_set->lock, flags);
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -552,7 +552,7 @@ static irqreturn_t pdc_interrupt (int ir
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 				handled += pdc_host_intr(ap, qc);
 		}
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index d374c1d..e047890 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -401,7 +401,7 @@ static inline unsigned int qs_intr_pkt(s
 				struct qs_port_priv *pp = ap->private_data;
 				if (!pp || pp->state != qs_state_pkt)
 					continue;
-				qc = ata_qc_from_tag(ap, ap->active_tag);
+				qc = ata_qc_from_tag(ap, ap->link.active_tag);
 				if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 					switch (sHST) {
 					case 0: /* successful CPB */
@@ -434,7 +434,7 @@ static inline unsigned int qs_intr_mmio(
 			struct qs_port_priv *pp = ap->private_data;
 			if (!pp || pp->state != qs_state_mmio)
 				continue;
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 
 				/* check main status, clearing INTRQ */
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 62deca4..baad7c4 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -305,7 +305,7 @@ static void sil_post_set_mode (struct at
 	unsigned int i;
 
 	for (i = 0; i < 2; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 		if (!ata_dev_enabled(dev))
 			dev_mode[i] = 0;	/* PIO0/1/2 */
 		else if (dev->flags & ATA_DFLAG_PIO)
@@ -359,7 +359,7 @@ static void sil_scr_write (struct ata_po
 
 static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
 {
-	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	u8 status;
 
 	if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
@@ -378,8 +378,8 @@ static void sil_host_intr(struct ata_por
 		 * repeat probing needlessly.
 		 */
 		if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
-			ata_ehi_hotplugged(&ap->eh_info);
-			ap->eh_info.serror |= serror;
+			ata_ehi_hotplugged(&ap->link.eh_info);
+			ap->link.eh_info.serror |= serror;
 		}
 
 		goto freeze;
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index f57afa5..298c1d8 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -759,7 +759,7 @@ static void sil24_thaw(struct ata_port *
 static void sil24_error_intr(struct ata_port *ap)
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	int freeze = 0;
 	u32 irq_stat;
 
@@ -811,7 +811,7 @@ static void sil24_error_intr(struct ata_
 		}
 
 		/* record error info */
-		qc = ata_qc_from_tag(ap, ap->active_tag);
+		qc = ata_qc_from_tag(ap, ap->link.active_tag);
 		if (qc) {
 			sil24_update_tf(ap);
 			qc->err_mask |= err_mask;
@@ -855,7 +855,7 @@ static inline void sil24_host_intr(struc
 	if (rc > 0)
 		return;
 	if (rc < 0) {
-		struct ata_eh_info *ehi = &ap->eh_info;
+		struct ata_eh_info *ehi = &ap->link.eh_info;
 		ehi->err_mask |= AC_ERR_HSM;
 		ehi->action |= ATA_EH_SOFTRESET;
 		ata_port_freeze(ap);
@@ -865,7 +865,7 @@ static inline void sil24_host_intr(struc
 	if (ata_ratelimit())
 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
 			"(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
-			slot_stat, ap->active_tag, ap->sactive);
+			slot_stat, ap->link.active_tag, ap->link.sactive);
 }
 
 static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -907,7 +907,7 @@ static irqreturn_t sil24_interrupt(int i
 
 static void sil24_error_handler(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 
 	if (sil24_init_port(ap)) {
 		ata_eh_freeze_port(ap);
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index ccc8cad..bf1178c 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -838,7 +838,7 @@ static irqreturn_t pdc20621_interrupt (i
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 				handled += pdc20621_host_intr(ap, qc, (i > 4),
 							      mmio_base);
@@ -865,7 +865,7 @@ static void pdc_eng_timeout(struct ata_p
 
 	spin_lock_irqsave(&host_set->lock, flags);
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index d7da4c2..52290e9 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -232,7 +232,7 @@ static irqreturn_t vsc_sata_interrupt (i
 			if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
 				struct ata_queued_cmd *qc;
 
-				qc = ata_qc_from_tag(ap, ap->active_tag);
+				qc = ata_qc_from_tag(ap, ap->link.active_tag);
 				if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 					handled += ata_host_intr(ap, qc);
 				else if (is_vsc_sata_int_err(i, int_status)) {
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 1609309..0395e2f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -437,7 +437,7 @@ struct ata_ering {
 };
 
 struct ata_device {
-	struct ata_port		*ap;
+	struct ata_link		*link;
 	unsigned int		devno;		/* 0 or 1 */
 	unsigned long		flags;		/* ATA_DFLAG_xxx */
 	struct scsi_device	*sdev;		/* attached SCSI device */
@@ -496,6 +496,23 @@ struct ata_eh_context {
 	unsigned int		did_probe_mask;
 };
 
+struct ata_link {
+	struct ata_port		*ap;
+
+	unsigned int		active_tag;	/* active tag on this link */
+	u32			sactive;	/* active NCQ commands */
+
+	unsigned int		hw_sata_spd_limit;
+	unsigned int		sata_spd_limit;
+
+	/* record runtime error info, protected by host_set lock */
+	struct ata_eh_info	eh_info;
+	/* EH context */
+	struct ata_eh_context	eh_context;
+
+	struct ata_device	device[1];
+};
+
 struct ata_port {
 	struct Scsi_Host	*host;	/* our co-allocated scsi host */
 	const struct ata_port_operations *ops;
@@ -520,22 +537,13 @@ struct ata_port {
 	unsigned int		mwdma_mask;
 	unsigned int		udma_mask;
 	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
-	unsigned int		hw_sata_spd_limit;
-	unsigned int		sata_spd_limit;	/* SATA PHY speed limit */
-
-	/* record runtime error info, protected by host_set lock */
-	struct ata_eh_info	eh_info;
-	/* EH context owned by EH */
-	struct ata_eh_context	eh_context;
-
-	struct ata_device	device[ATA_MAX_DEVICES];
 
 	struct ata_queued_cmd	qcmd[ATA_MAX_QUEUE];
 	unsigned long		qc_allocated;
 	unsigned int		qc_active;
 
-	unsigned int		active_tag;
-	u32			sactive;
+	struct ata_link		link;	/* host default link */
+	struct ata_device	__dev1;	/* storage for link.device[1] */
 
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
@@ -851,8 +859,11 @@ extern void ata_do_eh(struct ata_port *a
 #define ata_port_printk(ap, lv, fmt, args...) \
 	printk(lv"ata%u: "fmt, (ap)->id , ##args)
 
+#define ata_link_printk(link, lv, fmt, args...) \
+	printk(lv"ata%u: "fmt, (link)->ap->id , ##args)
+
 #define ata_dev_printk(dev, lv, fmt, args...) \
-	printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args)
+	printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->id, (dev)->devno , ##args)
 
 /*
  * ata_eh_info helpers
@@ -1090,7 +1101,7 @@ static inline void ata_tf_init(struct at
 {
 	memset(tf, 0, sizeof(*tf));
 
-	tf->ctl = dev->ap->ctl;
+	tf->ctl = dev->link->ap->ctl;
 	if (dev->devno == 0)
 		tf->device = ATA_DEVICE_OBS;
 	else
-- 
1.3.2



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

* [PATCH 04/17] libata-link: implement and use link/device iterators
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (5 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 08/17] libata-link: linkify config/EH related functions Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 06/17] libata-link: linkify EH action helpers Tejun Heo
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Multiple links and different number of devices per link should be
considered to iterate over links and devices.  This patch implements
and uses link and device iterators - ata_port_for_each_link() and
ata_link_for_each_dev() - and ata_link_max_devices().

This change makes a lot of functions iterate over only possible
devices instead of from dev 0 to dev ATA_MAX_DEVICES.  All such
changes have been examined and nothing should be broken.

While at it, add a separating comment before device helpers to
distinguish them better from link helpers and others.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |   81 +++++++++++--------------
 drivers/scsi/libata-eh.c   |  142 +++++++++++++++++++++-----------------------
 drivers/scsi/libata-scsi.c |   24 +++----
 include/linux/libata.h     |   14 +++-
 4 files changed, 122 insertions(+), 139 deletions(-)

54cdc69a26dfa3426b384b04b357e0fa7903b559
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9e19d12..0dcd2ec 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1329,14 +1329,14 @@ static void ata_dev_config_ncq(struct at
 
 static void ata_set_port_max_cmd_len(struct ata_port *ap)
 {
-	int i;
+	struct ata_device *dev;
 
 	if (ap->host) {
 		ap->host->max_cmd_len = 0;
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ata_link_for_each_dev(dev, &ap->link)
 			ap->host->max_cmd_len = max_t(unsigned int,
 						      ap->host->max_cmd_len,
-						      ap->link.device[i].cdb_len);
+						      dev->cdb_len);
 	}
 }
 
@@ -1534,13 +1534,13 @@ static int ata_bus_probe(struct ata_port
 {
 	unsigned int classes[ATA_MAX_DEVICES];
 	int tries[ATA_MAX_DEVICES];
-	int i, rc, down_xfermask;
+	int rc, down_xfermask;
 	struct ata_device *dev;
 
 	ata_port_probe(ap);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		tries[i] = ATA_PROBE_MAX_TRIES;
+	ata_link_for_each_dev(dev, &ap->link)
+		tries[dev->devno] = ATA_PROBE_MAX_TRIES;
 
  retry:
 	down_xfermask = 0;
@@ -1548,9 +1548,7 @@ static int ata_bus_probe(struct ata_port
 	/* reset and determine device classes */
 	ap->ops->phy_reset(ap);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (!(ap->flags & ATA_FLAG_DISABLED) &&
 		    dev->class != ATA_DEV_UNKNOWN)
 			classes[dev->devno] = dev->class;
@@ -1565,15 +1563,13 @@ static int ata_bus_probe(struct ata_port
 	/* after the reset the device state is PIO 0 and the controller
 	   state is undefined. Record the mode */
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ap->link.device[i].pio_mode = XFER_PIO_0;
+	ata_link_for_each_dev(dev, &ap->link)
+		dev->pio_mode = XFER_PIO_0;
 
 	/* read IDENTIFY page and configure devices */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
-
-		if (tries[i])
-			dev->class = classes[i];
+	ata_link_for_each_dev(dev, &ap->link) {
+		if (tries[dev->devno])
+			dev->class = classes[dev->devno];
 
 		if (!ata_dev_enabled(dev))
 			continue;
@@ -1594,9 +1590,10 @@ static int ata_bus_probe(struct ata_port
 		goto fail;
 	}
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_enabled(&ap->link.device[i]))
+	ata_link_for_each_dev(dev, &ap->link) {
+		if (ata_dev_enabled(dev))
 			return 0;
+	}
 
 	/* no device present, disable port */
 	ata_port_disable(ap);
@@ -2139,16 +2136,17 @@ static int ata_dev_set_mode(struct ata_d
  */
 int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
 {
+	struct ata_link *link = &ap->link;
 	struct ata_device *dev;
-	int i, rc = 0, used_dma = 0, found = 0;
+	int rc = 0, used_dma = 0, found = 0;
 
 	/* has private set_mode? */
 	if (ap->ops->set_mode) {
 		/* FIXME: make ->set_mode handle no device case and
 		 * return error code and failing device on failure.
 		 */
-		for (i = 0; i < ATA_MAX_DEVICES; i++) {
-			if (ata_dev_ready(&ap->link.device[i])) {
+		ata_link_for_each_dev(dev, link) {
+			if (ata_dev_ready(dev)) {
 				ap->ops->set_mode(ap);
 				break;
 			}
@@ -2157,11 +2155,9 @@ int ata_set_mode(struct ata_port *ap, st
 	}
 
 	/* step 1: calculate xfer_mask */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+	ata_link_for_each_dev(dev, link) {
 		unsigned int pio_mask, dma_mask;
 
-		dev = &ap->link.device[i];
-
 		if (!ata_dev_enabled(dev))
 			continue;
 
@@ -2180,8 +2176,7 @@ int ata_set_mode(struct ata_port *ap, st
 		goto out;
 
 	/* step 2: always set host PIO timings */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (!ata_dev_enabled(dev))
 			continue;
 
@@ -2198,9 +2193,7 @@ int ata_set_mode(struct ata_port *ap, st
 	}
 
 	/* step 3: set host DMA timings */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		if (!ata_dev_enabled(dev) || !dev->dma_mode)
 			continue;
 
@@ -2211,9 +2204,7 @@ int ata_set_mode(struct ata_port *ap, st
 	}
 
 	/* step 4: update devices' xfer mode */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		/* don't udpate suspended devices' xfer mode */
 		if (!ata_dev_ready(dev))
 			continue;
@@ -3125,8 +3116,8 @@ static void ata_dev_xfermask(struct ata_
 	struct ata_link *link = dev->link;
 	struct ata_port *ap = link->ap;
 	struct ata_host_set *hs = ap->host_set;
+	struct ata_device *d;
 	unsigned long xfer_mask;
-	int i;
 
 	xfer_mask = ata_pack_xfermask(ap->pio_mask,
 				      ap->mwdma_mask, ap->udma_mask);
@@ -3137,10 +3128,8 @@ static void ata_dev_xfermask(struct ata_
 	if (ap->cbl == ATA_CBL_PATA40)
 		xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
 
-	/* FIXME: Use port-wide xfermask for now */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *d = &link->device[i];
-
+	/* FIXME: Use link-wide xfermask for now */
+	ata_link_for_each_dev(d, link) {
 		if (ata_dev_absent(d))
 			continue;
 
@@ -5149,7 +5138,7 @@ static int ata_host_set_request_pm(struc
  */
 int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
 {
-	int i, j, rc;
+	int i, rc;
 
 	rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
 	if (rc)
@@ -5161,10 +5150,9 @@ int ata_host_set_suspend(struct ata_host
 	 */
 	for (i = 0; i < host_set->n_ports; i++) {
 		struct ata_port *ap = host_set->ports[i];
+		struct ata_device *dev;
 
-		for (j = 0; j < ATA_MAX_DEVICES; j++) {
-			struct ata_device *dev = &ap->link.device[j];
-
+		ata_link_for_each_dev(dev, &ap->link) {
 			if (ata_dev_ready(dev)) {
 				ata_port_printk(ap, KERN_WARNING,
 						"suspend failed, device %d "
@@ -5384,7 +5372,7 @@ #endif
 
 	ap->link.ap = ap;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+	for (i = 0; i < ata_link_max_devices(&ap->link); i++) {
 		struct ata_device *dev = &ap->link.device[i];
 		dev->link = &ap->link;
 		dev->devno = i;
@@ -5570,7 +5558,8 @@ int ata_device_add(const struct ata_prob
 			/* kick EH for boot probing */
 			spin_lock_irqsave(ap->lock, flags);
 
-			ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+			ehi->probe_mask =
+				(1 << ata_link_max_devices(&ap->link)) - 1;
 			ehi->action |= ATA_EH_SOFTRESET;
 			ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
@@ -5635,7 +5624,7 @@ err_free_ret:
 void ata_port_detach(struct ata_port *ap)
 {
 	unsigned long flags;
-	int i;
+	struct ata_device *dev;
 
 	if (!ap->ops->error_handler)
 		return;
@@ -5652,8 +5641,8 @@ void ata_port_detach(struct ata_port *ap
 	 */
 	spin_lock_irqsave(ap->lock, flags);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ata_dev_disable(&ap->link.device[i]);
+	ata_link_for_each_dev(dev, &ap->link)
+		ata_dev_disable(dev);
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 80cdfc2..fb6e3f8 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -115,23 +115,24 @@ static unsigned int ata_eh_dev_action(st
 	return ehc->i.action | ehc->i.dev_action[dev->devno];
 }
 
-static void ata_eh_clear_action(struct ata_device *dev,
+static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
 				struct ata_eh_info *ehi, unsigned int action)
 {
-	int i;
+	struct ata_device *tdev;
 
 	if (!dev) {
 		ehi->action &= ~action;
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ehi->dev_action[i] &= ~action;
+		ata_link_for_each_dev(tdev, link)
+			ehi->dev_action[tdev->devno] &= ~action;
 	} else {
 		/* doesn't make sense for port-wide EH actions */
 		WARN_ON(!(action & ATA_EH_PERDEV_MASK));
 
 		/* break ehi->action into ehi->dev_action */
 		if (ehi->action & action) {
-			for (i = 0; i < ATA_MAX_DEVICES; i++)
-				ehi->dev_action[i] |= ehi->action & action;
+			ata_link_for_each_dev(tdev, link)
+				ehi->dev_action[tdev->devno] |=
+					ehi->action & action;
 			ehi->action &= ~action;
 		}
 
@@ -747,7 +748,8 @@ void ata_eh_qc_retry(struct ata_queued_c
  */
 static void ata_eh_detach_dev(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->link->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
 	ata_dev_disable(dev);
@@ -762,8 +764,8 @@ static void ata_eh_detach_dev(struct ata
 	}
 
 	/* clear per-dev EH actions */
-	ata_eh_clear_action(dev, &dev->link->eh_info, ATA_EH_PERDEV_MASK);
-	ata_eh_clear_action(dev, &dev->link->eh_context.i, ATA_EH_PERDEV_MASK);
+	ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
+	ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
 
 	spin_unlock_irqrestore(ap->lock, flags);
 }
@@ -788,7 +790,7 @@ static void ata_eh_about_to_do(struct at
 
 	spin_lock_irqsave(ap->lock, flags);
 
-	ata_eh_clear_action(dev, &ap->link.eh_info, action);
+	ata_eh_clear_action(&ap->link, dev, &ap->link.eh_info, action);
 
 	if (!(ap->link.eh_context.i.flags & ATA_EHI_QUIET))
 		ap->pflags |= ATA_PFLAG_RECOVERED;
@@ -811,7 +813,7 @@ static void ata_eh_about_to_do(struct at
 static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
 			unsigned int action)
 {
-	ata_eh_clear_action(dev, &ap->link.eh_context.i, action);
+	ata_eh_clear_action(&ap->link, dev, &ap->link.eh_context.i, action);
 }
 
 /**
@@ -1455,10 +1457,11 @@ static void ata_eh_report(struct ata_por
 static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
 			unsigned int *classes)
 {
-	int i, rc;
+	struct ata_device *dev;
+	int rc;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		classes[i] = ATA_DEV_UNKNOWN;
+	ata_link_for_each_dev(dev, &ap->link)
+		classes[dev->devno] = ATA_DEV_UNKNOWN;
 
 	rc = reset(ap, classes);
 	if (rc)
@@ -1468,14 +1471,16 @@ static int ata_do_reset(struct ata_port 
 	 * is complete and convert all ATA_DEV_UNKNOWN to
 	 * ATA_DEV_NONE.
 	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (classes[i] != ATA_DEV_UNKNOWN)
+	ata_link_for_each_dev(dev, &ap->link)
+		if (classes[dev->devno] != ATA_DEV_UNKNOWN)
 			break;
 
-	if (i < ATA_MAX_DEVICES)
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			if (classes[i] == ATA_DEV_UNKNOWN)
-				classes[i] = ATA_DEV_NONE;
+	if (dev) {
+		ata_link_for_each_dev(dev, &ap->link) {
+			if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+				classes[dev->devno] = ATA_DEV_NONE;
+		}
+	}
 
 	return 0;
 }
@@ -1500,9 +1505,10 @@ static int ata_eh_reset(struct ata_port 
 	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
 	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
+	struct ata_device *dev;
 	unsigned int action;
 	ata_reset_fn_t reset;
-	int i, did_followup_srst, rc;
+	int did_followup_srst, rc;
 
 	/* Determine which reset to use and record in ehc->i.action.
 	 * prereset() may examine and modify it.
@@ -1531,8 +1537,8 @@ static int ata_eh_reset(struct ata_port 
 		reset = softreset;
 	else {
 		/* prereset told us not to reset, bang classes and return */
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			classes[i] = ATA_DEV_NONE;
+		ata_link_for_each_dev(dev, &ap->link)
+			classes[dev->devno] = ATA_DEV_NONE;
 		return 0;
 	}
 
@@ -1609,8 +1615,8 @@ static int ata_eh_reset(struct ata_port 
 		/* After the reset, the device state is PIO 0 and the
 		 * controller state is undefined.  Record the mode.
 		 */
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ap->link.device[i].pio_mode = XFER_PIO_0;
+		ata_link_for_each_dev(dev, &ap->link)
+			dev->pio_mode = XFER_PIO_0;
 
 		if (postreset)
 			postreset(ap, classes);
@@ -1629,15 +1635,12 @@ static int ata_eh_revalidate_and_attach(
 	struct ata_eh_context *ehc = &ap->link.eh_context;
 	struct ata_device *dev;
 	unsigned long flags;
-	int i, rc = 0;
+	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		unsigned int action;
-
-		dev = &ap->link.device[i];
-		action = ata_eh_dev_action(dev);
+	ata_link_for_each_dev(dev, &ap->link) {
+		unsigned int action = ata_eh_dev_action(dev);
 
 		if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
 			if (ata_port_offline(ap)) {
@@ -1701,16 +1704,14 @@ static int ata_eh_revalidate_and_attach(
 static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
 {
 	struct ata_device *dev;
-	int i, rc = 0;
+	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+	ata_link_for_each_dev(dev, &ap->link) {
+		unsigned int action = ata_eh_dev_action(dev);
+		unsigned int err_mask;
 		unsigned long flags;
-		unsigned int action, err_mask;
-
-		dev = &ap->link.device[i];
-		action = ata_eh_dev_action(dev);
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
 			continue;
@@ -1765,15 +1766,11 @@ static void ata_eh_prep_resume(struct at
 {
 	struct ata_device *dev;
 	unsigned long flags;
-	int i;
 
 	DPRINTK("ENTER\n");
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		unsigned int action;
-
-		dev = &ap->link.device[i];
-		action = ata_eh_dev_action(dev);
+	ata_link_for_each_dev(dev, &ap->link) {
+		unsigned int action = ata_eh_dev_action(dev);
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
 			continue;
@@ -1803,15 +1800,13 @@ static void ata_eh_prep_resume(struct at
 static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
 {
 	struct ata_device *dev;
-	int i, rc = 0;
+	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		unsigned int action, err_mask;
-
-		dev = &ap->link.device[i];
-		action = ata_eh_dev_action(dev);
+	ata_link_for_each_dev(dev, &ap->link) {
+		unsigned int action = ata_eh_dev_action(dev);
+		unsigned int err_mask;
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
 			continue;
@@ -1842,20 +1837,22 @@ static int ata_eh_resume(struct ata_port
 
 static int ata_port_nr_enabled(struct ata_port *ap)
 {
-	int i, cnt = 0;
+	struct ata_device *dev;
+	int cnt = 0;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_enabled(&ap->link.device[i]))
+	ata_link_for_each_dev(dev, &ap->link)
+		if (ata_dev_enabled(dev))
 			cnt++;
 	return cnt;
 }
 
 static int ata_port_nr_vacant(struct ata_port *ap)
 {
-	int i, cnt = 0;
+	struct ata_device *dev;
+	int cnt = 0;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ap->link.device[i].class == ATA_DEV_UNKNOWN)
+	ata_link_for_each_dev(dev, &ap->link)
+		if (dev->class == ATA_DEV_UNKNOWN)
 			cnt++;
 	return cnt;
 }
@@ -1863,17 +1860,15 @@ static int ata_port_nr_vacant(struct ata
 static int ata_eh_skip_recovery(struct ata_port *ap)
 {
 	struct ata_eh_context *ehc = &ap->link.eh_context;
-	int i;
+	struct ata_device *dev;
 
 	/* skip if all possible devices are suspended */
-	for (i = 0; i < ata_port_max_devices(ap); i++) {
-		struct ata_device *dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (ata_dev_absent(dev) || ata_dev_ready(dev))
 			break;
 	}
 
-	if (i == ata_port_max_devices(ap))
+	if (dev == NULL)
 		return 1;
 
 	/* always thaw frozen port and recover failed devices */
@@ -1881,9 +1876,7 @@ static int ata_eh_skip_recovery(struct a
 		return 0;
 
 	/* skip if class codes for all vacant slots are ATA_DEV_NONE */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (dev->class == ATA_DEV_UNKNOWN &&
 		    ehc->classes[dev->devno] != ATA_DEV_NONE)
 			return 0;
@@ -1968,14 +1961,12 @@ static int ata_eh_recover(struct ata_por
 {
 	struct ata_eh_context *ehc = &ap->link.eh_context;
 	struct ata_device *dev;
-	int down_xfermask, i, rc;
+	int down_xfermask, rc;
 
 	DPRINTK("ENTER\n");
 
 	/* prep for recovery */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, &ap->link) {
 		ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
 		/* process hotplug request */
@@ -2007,8 +1998,8 @@ static int ata_eh_recover(struct ata_por
 	if (ata_eh_skip_recovery(ap))
 		ehc->i.action = 0;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ehc->classes[i] = ATA_DEV_UNKNOWN;
+	ata_link_for_each_dev(dev, &ap->link)
+		ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
 
 	/* reset */
 	if (ehc->i.action & ATA_EH_RESET_MASK) {
@@ -2070,8 +2061,8 @@ static int ata_eh_recover(struct ata_por
 		/* recovery failed, activate hp-poll */
 		ata_hp_poll_activate(ap);
 
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ata_dev_disable(&ap->link.device[i]);
+		ata_link_for_each_dev(dev, &ap->link);
+			ata_dev_disable(dev);
 	}
 
 	DPRINTK("EXIT, rc=%d\n", rc);
@@ -2214,7 +2205,7 @@ static void ata_eh_handle_port_resume(st
 {
 	unsigned long timeout;
 	unsigned long flags;
-	int i, rc = 0;
+	int rc = 0;
 
 	/* are we resuming? */
 	spin_lock_irqsave(ap->lock, flags);
@@ -2235,8 +2226,9 @@ static void ata_eh_handle_port_resume(st
 	/* give devices time to request EH */
 	timeout = jiffies + HZ; /* 1s max */
 	while (1) {
-		for (i = 0; i < ATA_MAX_DEVICES; i++) {
-			struct ata_device *dev = &ap->link.device[i];
+		struct ata_device *dev;
+
+		ata_link_for_each_dev(dev, &ap->link) {
 			unsigned int action = ata_eh_dev_action(dev);
 
 			if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
@@ -2244,7 +2236,7 @@ static void ata_eh_handle_port_resume(st
 				break;
 		}
 
-		if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+		if (dev == NULL || time_after(jiffies, timeout))
 			break;
 		msleep(10);
 	}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index c947da7..8c0229b 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -511,7 +511,7 @@ int ata_scsi_device_resume(struct scsi_d
 	/* We don't want autopsy and verbose EH messages.  Disable
 	 * those if we're the only device on this link.
 	 */
-	if (ata_port_max_devices(ap) == 1)
+	if (ata_link_max_devices(dev->link) == 1)
 		ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
 	ata_port_schedule_eh(ap);
@@ -2466,7 +2466,7 @@ static unsigned int atapi_xlat(struct at
 
 static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
 {
-	if (likely(id < ATA_MAX_DEVICES))
+	if (likely(id < ata_link_max_devices(&ap->link)))
 		return &ap->link.device[id];
 	return NULL;
 }
@@ -2920,19 +2920,18 @@ void ata_scsi_simulate(struct ata_device
 
 void ata_scsi_scan_host(struct ata_port *ap)
 {
-	unsigned int i;
+	struct ata_device *dev;
 
 	if (ap->flags & ATA_FLAG_DISABLED)
 		return;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->link.device[i];
+	ata_link_for_each_dev(dev, &ap->link) {
 		struct scsi_device *sdev;
 
 		if (!ata_dev_enabled(dev) || dev->sdev)
 			continue;
 
-		sdev = __scsi_add_device(ap->host, 0, i, 0, NULL);
+		sdev = __scsi_add_device(ap->host, 0, dev->devno, 0, NULL);
 		if (!IS_ERR(sdev)) {
 			dev->sdev = sdev;
 			scsi_device_put(sdev);
@@ -3038,7 +3037,7 @@ static void ata_scsi_remove_dev(struct a
 void ata_scsi_hotplug(void *data)
 {
 	struct ata_port *ap = data;
-	int i;
+	struct ata_device *dev;
 
 	if (ap->pflags & ATA_PFLAG_UNLOADING) {
 		DPRINTK("ENTER/EXIT - unloading\n");
@@ -3048,8 +3047,7 @@ void ata_scsi_hotplug(void *data)
 	DPRINTK("ENTER\n");
 
 	/* unplug detached devices */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->link.device[i];
+	ata_link_for_each_dev(dev, &ap->link) {
 		unsigned long flags;
 
 		if (!(dev->flags & ATA_DFLAG_DETACHED))
@@ -3069,8 +3067,7 @@ void ata_scsi_hotplug(void *data)
 	 * failed silently.  Requeue if there are enabled but
 	 * unattached devices.
 	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->link.device[i];
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (ata_dev_enabled(dev) && !dev->sdev) {
 			queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
 			break;
@@ -3151,11 +3148,8 @@ void ata_scsi_dev_rescan(void *data)
 {
 	struct ata_port *ap = data;
 	struct ata_device *dev;
-	unsigned int i;
-
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->link.device[i];
 
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (ata_dev_enabled(dev) && dev->sdev)
 			scsi_rescan_device(&(dev->sdev->sdev_gendev));
 	}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 0395e2f..990a555 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -986,15 +986,23 @@ static inline unsigned int ata_dev_ready
 }
 
 /*
- * port helpers
+ * link helpers
  */
-static inline int ata_port_max_devices(const struct ata_port *ap)
+static inline int ata_link_max_devices(const struct ata_link *link)
 {
-	if (ap->flags & ATA_FLAG_SLAVE_POSS)
+	if (link->ap->flags & ATA_FLAG_SLAVE_POSS)
 		return 2;
 	return 1;
 }
 
+#define ata_port_for_each_link(lk, ap) \
+	for ((lk) = &(ap)->link; (lk); (lk) = NULL)
+
+#define ata_link_for_each_dev(dev, link) \
+	for ((dev) = (link)->device; \
+	     (dev) - (link)->device < ata_link_max_devices(link) || (dev = NULL); \
+	     (dev)++)
+
 
 static inline u8 ata_chk_status(struct ata_port *ap)
 {
-- 
1.3.2



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

* [PATCH 06/17] libata-link: linkify EH action helpers
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (6 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 04/17] libata-link: implement and use link/device iterators Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 10/17] libata-link: implement link->reset_tries Tejun Heo
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Make ata_eh_about_to_do() and ata_eh_done() deal with ata_link instead
of ata_port.

This patch introduces no behavior change.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-eh.c |   39 ++++++++++++++++++++-------------------
 1 files changed, 20 insertions(+), 19 deletions(-)

b01d20e457820a1e839d5944f9d654ef5963fa33
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 22ca9a2..62c75d4 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -772,27 +772,28 @@ static void ata_eh_detach_dev(struct ata
 
 /**
  *	ata_eh_about_to_do - about to perform eh_action
- *	@ap: target ATA port
+ *	@link: target ATA link
  *	@dev: target ATA dev for per-dev action (can be NULL)
  *	@action: action about to be performed
  *
  *	Called just before performing EH actions to clear related bits
- *	in @ap->link.eh_info such that eh actions are not
- *	unnecessarily repeated.
+ *	in @link->eh_info such that eh actions are not unnecessarily
+ *	repeated.
  *
  *	LOCKING:
  *	None.
  */
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
+static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
 			       unsigned int action)
 {
+	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
 	spin_lock_irqsave(ap->lock, flags);
 
-	ata_eh_clear_action(&ap->link, dev, &ap->link.eh_info, action);
+	ata_eh_clear_action(link, dev, &link->eh_info, action);
 
-	if (!(ap->link.eh_context.i.flags & ATA_EHI_QUIET))
+	if (!(link->eh_context.i.flags & ATA_EHI_QUIET))
 		ap->pflags |= ATA_PFLAG_RECOVERED;
 
 	spin_unlock_irqrestore(ap->lock, flags);
@@ -800,20 +801,20 @@ static void ata_eh_about_to_do(struct at
 
 /**
  *	ata_eh_done - EH action complete
- *	@ap: target ATA port
+ *	@link: target ATA link
  *	@dev: target ATA dev for per-dev action (can be NULL)
  *	@action: action just completed
  *
  *	Called right after performing EH actions to clear related bits
- *	in @ap->link.eh_context.
+ *	in @link->eh_context.
  *
  *	LOCKING:
  *	None.
  */
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
+static void ata_eh_done(struct ata_link *link, struct ata_device *dev,
 			unsigned int action)
 {
-	ata_eh_clear_action(&ap->link, dev, &ap->link.eh_context.i, action);
+	ata_eh_clear_action(link, dev, &link->eh_context.i, action);
 }
 
 /**
@@ -1561,7 +1562,7 @@ static int ata_eh_reset(struct ata_port 
 				reset == softreset ? "soft" : "hard");
 
 	/* reset */
-	ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+	ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
 	ehc->i.flags |= ATA_EHI_DID_RESET;
 
 	rc = ata_do_reset(ap, reset, classes);
@@ -1580,7 +1581,7 @@ static int ata_eh_reset(struct ata_port 
 			return -EINVAL;
 		}
 
-		ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+		ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
 		rc = ata_do_reset(ap, reset, classes);
 
 		if (rc == 0 && classify &&
@@ -1624,7 +1625,7 @@ static int ata_eh_reset(struct ata_port 
 			postreset(ap, classes);
 
 		/* reset successful, schedule revalidation */
-		ata_eh_done(ap, NULL, ATA_EH_RESET_MASK);
+		ata_eh_done(link, NULL, ATA_EH_RESET_MASK);
 		ehc->i.action |= ATA_EH_REVALIDATE;
 	}
 
@@ -1650,13 +1651,13 @@ static int ata_eh_revalidate_and_attach(
 				break;
 			}
 
-			ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
+			ata_eh_about_to_do(&ap->link, dev, ATA_EH_REVALIDATE);
 			rc = ata_dev_revalidate(dev,
 					ehc->i.flags & ATA_EHI_DID_RESET);
 			if (rc)
 				break;
 
-			ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+			ata_eh_done(&ap->link, dev, ATA_EH_REVALIDATE);
 
 			/* schedule the scsi_rescan_device() here */
 			queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
@@ -1720,7 +1721,7 @@ static int ata_eh_suspend(struct ata_por
 
 		WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
 
-		ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+		ata_eh_about_to_do(&ap->link, dev, ATA_EH_SUSPEND);
 
 		if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
 			/* flush cache */
@@ -1743,7 +1744,7 @@ static int ata_eh_suspend(struct ata_por
 		dev->flags |= ATA_DFLAG_SUSPENDED;
 		spin_unlock_irqrestore(ap->lock, flags);
 
-		ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+		ata_eh_done(&ap->link, dev, ATA_EH_SUSPEND);
 	}
 
 	if (rc)
@@ -1813,7 +1814,7 @@ static int ata_eh_resume(struct ata_port
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
 			continue;
 
-		ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+		ata_eh_about_to_do(&ap->link, dev, ATA_EH_RESUME);
 
 		if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
 			err_mask = ata_do_simple_cmd(dev,
@@ -1827,7 +1828,7 @@ static int ata_eh_resume(struct ata_port
 			}
 		}
 
-		ata_eh_done(ap, dev, ATA_EH_RESUME);
+		ata_eh_done(&ap->link, dev, ATA_EH_RESUME);
 	}
 
 	if (rc)
-- 
1.3.2



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

* [PATCH 08/17] libata-link: linkify config/EH related functions
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (4 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 07/17] libata-link: linkify reset Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 04/17] libata-link: implement and use link/device iterators Tejun Heo
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Make the following functions deal with ata_link instead of ata_port.

* ata_set_mode()
* ata_eh_autopsy() and related functions
* ata_eh_report() and related functions
* suspend/resume related functions
* ata_eh_recover() and related functions

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    8 +-
 drivers/scsi/libata-eh.c   |  161 +++++++++++++++++++++++---------------------
 drivers/scsi/libata.h      |    3 +
 3 files changed, 91 insertions(+), 81 deletions(-)

9f6869b65ed5dc741ca33747d34c7ebb3186e495
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9f6b905..e8170e5 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1584,7 +1584,7 @@ static int ata_bus_probe(struct ata_port
 	}
 
 	/* configure transfer mode */
-	rc = ata_set_mode(ap, &dev);
+	rc = ata_set_mode(&ap->link, &dev);
 	if (rc) {
 		down_xfermask = 1;
 		goto fail;
@@ -2122,7 +2122,7 @@ static int ata_dev_set_mode(struct ata_d
 
 /**
  *	ata_set_mode - Program timings and issue SET FEATURES - XFER
- *	@ap: port on which timings will be programmed
+ *	@link: link on which timings will be programmed
  *	@r_failed_dev: out paramter for failed device
  *
  *	Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
@@ -2135,9 +2135,9 @@ static int ata_dev_set_mode(struct ata_d
  *	RETURNS:
  *	0 on success, negative errno otherwise
  */
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
-	struct ata_link *link = &ap->link;
+	struct ata_port *ap = link->ap;
 	struct ata_device *dev;
 	int rc = 0, used_dma = 0, found = 0;
 
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 5475e2f..d574486 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1002,7 +1002,7 @@ static unsigned int atapi_eh_request_sen
 
 /**
  *	ata_eh_analyze_serror - analyze SError for a failed port
- *	@ap: ATA port to analyze SError for
+ *	@link: ATA link to analyze SError for
  *
  *	Analyze SError if available and further determine cause of
  *	failure.
@@ -1010,9 +1010,9 @@ static unsigned int atapi_eh_request_sen
  *	LOCKING:
  *	None.
  */
-static void ata_eh_analyze_serror(struct ata_port *ap)
+static void ata_eh_analyze_serror(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_eh_context *ehc = &link->eh_context;
 	u32 serror = ehc->i.serror;
 	unsigned int err_mask = 0, action = 0;
 
@@ -1042,7 +1042,7 @@ static void ata_eh_analyze_serror(struct
 
 /**
  *	ata_eh_analyze_ncq_error - analyze NCQ error
- *	@ap: ATA port to analyze NCQ error for
+ *	@link: ATA link to analyze NCQ error for
  *
  *	Read log page 10h, determine the offending qc and acquire
  *	error status TF.  For NCQ device errors, all LLDDs have to do
@@ -1052,10 +1052,11 @@ static void ata_eh_analyze_serror(struct
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+static void ata_eh_analyze_ncq_error(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
-	struct ata_device *dev = ap->link.device;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_device *dev = link->device;
 	struct ata_queued_cmd *qc;
 	struct ata_taskfile tf;
 	int tag, rc;
@@ -1065,7 +1066,7 @@ static void ata_eh_analyze_ncq_error(str
 		return;
 
 	/* is it NCQ device error? */
-	if (!ap->link.sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+	if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
 		return;
 
 	/* has LLDD analyzed already? */
@@ -1082,13 +1083,13 @@ static void ata_eh_analyze_ncq_error(str
 	/* okay, this error is ours */
 	rc = ata_eh_read_log_10h(dev, &tag, &tf);
 	if (rc) {
-		ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+		ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
 				"(errno=%d)\n", rc);
 		return;
 	}
 
-	if (!(ap->link.sactive & (1 << tag))) {
-		ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+	if (!(link->sactive & (1 << tag))) {
+		ata_link_printk(link, KERN_ERR, "log page 10h reported "
 				"inactive tag %d\n", tag);
 		return;
 	}
@@ -1288,18 +1289,18 @@ static int ata_eh_speed_down(struct ata_
 
 /**
  *	ata_eh_autopsy - analyze error and determine recovery action
- *	@ap: ATA port to perform autopsy on
+ *	@link: ATA link to perform autopsy on
  *
- *	Analyze why @ap failed and determine which recovery action is
- *	needed.  This function also sets more detailed AC_ERR_* values
- *	and fills sense data for ATAPI CHECK SENSE.
+ *	Analyze why @link failed and determine which recovery actions
+ *	are needed.  This function also sets more detailed AC_ERR_*
+ *	values and fills sense data for ATAPI CHECK SENSE.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_autopsy(struct ata_port *ap)
+static void ata_eh_autopsy(struct ata_link *link)
 {
-	struct ata_link *link = &ap->link;
+	struct ata_port *ap = link->ap;
 	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned int action = ehc->i.action;
 	struct ata_device *failed_dev = NULL;
@@ -1317,12 +1318,12 @@ static void ata_eh_autopsy(struct ata_po
 	rc = sata_scr_read(link, SCR_ERROR, &serror);
 	if (rc == 0) {
 		ehc->i.serror |= serror;
-		ata_eh_analyze_serror(ap);
+		ata_eh_analyze_serror(link);
 	} else if (rc != -EOPNOTSUPP)
 		action |= ATA_EH_HARDRESET;
 
 	/* analyze NCQ failure */
-	ata_eh_analyze_ncq_error(ap);
+	ata_eh_analyze_ncq_error(link);
 
 	/* any real error trumps AC_ERR_OTHER */
 	if (ehc->i.err_mask & ~AC_ERR_OTHER)
@@ -1333,7 +1334,7 @@ static void ata_eh_autopsy(struct ata_po
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED))
+		if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
 			continue;
 
 		/* inherit upper level err_mask */
@@ -1391,16 +1392,17 @@ static void ata_eh_autopsy(struct ata_po
 
 /**
  *	ata_eh_report - report error handling to user
- *	@ap: ATA port EH is going on
+ *	@link: ATA link EH is going on
  *
  *	Report EH to user.
  *
  *	LOCKING:
  *	None.
  */
-static void ata_eh_report(struct ata_port *ap)
+static void ata_eh_report(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	const char *frozen, *desc;
 	int tag, nr_failed = 0;
 
@@ -1411,7 +1413,7 @@ static void ata_eh_report(struct ata_por
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED))
+		if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
 			continue;
 		if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
 			continue;
@@ -1429,23 +1431,24 @@ static void ata_eh_report(struct ata_por
 	if (ehc->i.dev) {
 		ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
 			       "SAct 0x%x SErr 0x%x action 0x%x%s\n",
-			       ehc->i.err_mask, ap->link.sactive,
+			       ehc->i.err_mask, link->sactive,
 			       ehc->i.serror, ehc->i.action, frozen);
 		if (desc)
 			ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
 	} else {
-		ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
+		ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
 				"SAct 0x%x SErr 0x%x action 0x%x%s\n",
-				ehc->i.err_mask, ap->link.sactive,
+				ehc->i.err_mask, link->sactive,
 				ehc->i.serror, ehc->i.action, frozen);
 		if (desc)
-			ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+			ata_link_printk(link, KERN_ERR, "(%s)\n", desc);
 	}
 
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+		if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+		    qc->dev->link != link || !qc->err_mask)
 			continue;
 
 		ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
@@ -1631,17 +1634,18 @@ static int ata_eh_reset(struct ata_link 
 	return rc;
 }
 
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+static int ata_eh_revalidate_and_attach(struct ata_link *link,
 					struct ata_device **r_failed_dev)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_device *dev;
 	unsigned long flags;
 	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		unsigned int action = ata_eh_dev_action(dev);
 
 		if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
@@ -1650,13 +1654,13 @@ static int ata_eh_revalidate_and_attach(
 				break;
 			}
 
-			ata_eh_about_to_do(&ap->link, dev, ATA_EH_REVALIDATE);
+			ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
 			rc = ata_dev_revalidate(dev,
 					ehc->i.flags & ATA_EHI_DID_RESET);
 			if (rc)
 				break;
 
-			ata_eh_done(&ap->link, dev, ATA_EH_REVALIDATE);
+			ata_eh_done(link, dev, ATA_EH_REVALIDATE);
 
 			/* schedule the scsi_rescan_device() here */
 			queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
@@ -1689,7 +1693,7 @@ static int ata_eh_revalidate_and_attach(
 
 /**
  *	ata_eh_suspend - handle suspend EH action
- *	@ap: target host port
+ *	@link: target link
  *	@r_failed_dev: result parameter to indicate failing device
  *
  *	Handle suspend EH action.  Disk devices are spinned down and
@@ -1703,14 +1707,16 @@ static int ata_eh_revalidate_and_attach(
  *	RETURNS:
  *	0 on success, -errno otherwise
  */
-static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+static int ata_eh_suspend(struct ata_link *link,
+			  struct ata_device **r_failed_dev)
 {
+	struct ata_port *ap = link->ap;
 	struct ata_device *dev;
 	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		unsigned int action = ata_eh_dev_action(dev);
 		unsigned int err_mask;
 		unsigned long flags;
@@ -1720,7 +1726,7 @@ static int ata_eh_suspend(struct ata_por
 
 		WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
 
-		ata_eh_about_to_do(&ap->link, dev, ATA_EH_SUSPEND);
+		ata_eh_about_to_do(link, dev, ATA_EH_SUSPEND);
 
 		if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
 			/* flush cache */
@@ -1743,7 +1749,7 @@ static int ata_eh_suspend(struct ata_por
 		dev->flags |= ATA_DFLAG_SUSPENDED;
 		spin_unlock_irqrestore(ap->lock, flags);
 
-		ata_eh_done(&ap->link, dev, ATA_EH_SUSPEND);
+		ata_eh_done(link, dev, ATA_EH_SUSPEND);
 	}
 
 	if (rc)
@@ -1755,7 +1761,7 @@ static int ata_eh_suspend(struct ata_por
 
 /**
  *	ata_eh_prep_resume - prep for resume EH action
- *	@ap: target host port
+ *	@link: target link
  *
  *	Clear SUSPENDED in preparation for scheduled resume actions.
  *	This allows other parts of EH to access the devices being
@@ -1764,14 +1770,15 @@ static int ata_eh_suspend(struct ata_por
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_prep_resume(struct ata_port *ap)
+static void ata_eh_prep_resume(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
 	struct ata_device *dev;
 	unsigned long flags;
 
 	DPRINTK("ENTER\n");
 
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		unsigned int action = ata_eh_dev_action(dev);
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
@@ -1787,7 +1794,7 @@ static void ata_eh_prep_resume(struct at
 
 /**
  *	ata_eh_resume - handle resume EH action
- *	@ap: target host port
+ *	@link: target link
  *	@r_failed_dev: result parameter to indicate failing device
  *
  *	Handle resume EH action.  Target devices are already reset and
@@ -1799,21 +1806,22 @@ static void ata_eh_prep_resume(struct at
  *	RETURNS:
  *	0 on success, -errno otherwise
  */
-static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+static int ata_eh_resume(struct ata_link *link,
+			 struct ata_device **r_failed_dev)
 {
 	struct ata_device *dev;
 	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		unsigned int action = ata_eh_dev_action(dev);
 		unsigned int err_mask;
 
 		if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
 			continue;
 
-		ata_eh_about_to_do(&ap->link, dev, ATA_EH_RESUME);
+		ata_eh_about_to_do(link, dev, ATA_EH_RESUME);
 
 		if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
 			err_mask = ata_do_simple_cmd(dev,
@@ -1827,7 +1835,7 @@ static int ata_eh_resume(struct ata_port
 			}
 		}
 
-		ata_eh_done(&ap->link, dev, ATA_EH_RESUME);
+		ata_eh_done(link, dev, ATA_EH_RESUME);
 	}
 
 	if (rc)
@@ -1837,35 +1845,35 @@ static int ata_eh_resume(struct ata_port
 	return 0;
 }
 
-static int ata_port_nr_enabled(struct ata_port *ap)
+static int ata_link_nr_enabled(struct ata_link *link)
 {
 	struct ata_device *dev;
 	int cnt = 0;
 
-	ata_link_for_each_dev(dev, &ap->link)
+	ata_link_for_each_dev(dev, link)
 		if (ata_dev_enabled(dev))
 			cnt++;
 	return cnt;
 }
 
-static int ata_port_nr_vacant(struct ata_port *ap)
+static int ata_link_nr_vacant(struct ata_link *link)
 {
 	struct ata_device *dev;
 	int cnt = 0;
 
-	ata_link_for_each_dev(dev, &ap->link)
+	ata_link_for_each_dev(dev, link)
 		if (dev->class == ATA_DEV_UNKNOWN)
 			cnt++;
 	return cnt;
 }
 
-static int ata_eh_skip_recovery(struct ata_port *ap)
+static int ata_eh_skip_recovery(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_device *dev;
 
 	/* skip if all possible devices are suspended */
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_absent(dev) || ata_dev_ready(dev))
 			break;
 	}
@@ -1874,11 +1882,11 @@ static int ata_eh_skip_recovery(struct a
 		return 1;
 
 	/* always thaw frozen port and recover failed devices */
-	if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap))
+	if (link->ap->pflags & ATA_PFLAG_FROZEN || ata_link_nr_enabled(link))
 		return 0;
 
 	/* skip if class codes for all vacant slots are ATA_DEV_NONE */
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		if (dev->class == ATA_DEV_UNKNOWN &&
 		    ehc->classes[dev->devno] != ATA_DEV_NONE)
 			return 0;
@@ -1890,8 +1898,8 @@ static int ata_eh_skip_recovery(struct a
 static void ata_eh_handle_dev_fail(struct ata_device *dev, int err,
 				   int down_xfermask)
 {
-	struct ata_port *ap = dev->link->ap;
-	struct ata_eh_context *ehc = &dev->link->eh_context;
+	struct ata_link *link = dev->link;
+	struct ata_eh_context *ehc = &link->eh_context;
 
 	switch (err) {
 	case -ENODEV:
@@ -1901,7 +1909,7 @@ static void ata_eh_handle_dev_fail(struc
 		ehc->tries[dev->devno] = 0;
 		break;
 	case -EIO:
-		sata_down_spd_limit(&ap->link);
+		sata_down_spd_limit(link);
 	default:
 		ehc->tries[dev->devno]--;
 		if (down_xfermask &&
@@ -1914,7 +1922,7 @@ static void ata_eh_handle_dev_fail(struc
 		ata_dev_disable(dev);
 
 		/* detach if offline */
-		if (ata_link_offline(&ap->link))
+		if (ata_link_offline(link))
 			ata_eh_detach_dev(dev);
 
 		/* probe if requested */
@@ -1961,14 +1969,15 @@ static int ata_eh_recover(struct ata_por
 			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 			  ata_postreset_fn_t postreset)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_link *link = &ap->link;
+	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_device *dev;
 	int down_xfermask, rc;
 
 	DPRINTK("ENTER\n");
 
 	/* prep for recovery */
-	ata_link_for_each_dev(dev, &ap->link) {
+	ata_link_for_each_dev(dev, link) {
 		ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
 		/* process hotplug request */
@@ -1994,23 +2003,23 @@ static int ata_eh_recover(struct ata_por
 		goto out;
 
 	/* prep for resume */
-	ata_eh_prep_resume(ap);
+	ata_eh_prep_resume(link);
 
 	/* skip EH if possible. */
-	if (ata_eh_skip_recovery(ap))
+	if (ata_eh_skip_recovery(link))
 		ehc->i.action = 0;
 
-	ata_link_for_each_dev(dev, &ap->link)
+	ata_link_for_each_dev(dev, link)
 		ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
 
 	/* reset */
 	if (ehc->i.action & ATA_EH_RESET_MASK) {
 		ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(&ap->link, ata_port_nr_vacant(ap), prereset,
+		rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset,
 				  softreset, hardreset, postreset);
 		if (rc) {
-			ata_port_printk(ap, KERN_ERR,
+			ata_link_printk(link, KERN_ERR,
 					"reset failed, giving up\n");
 			goto out;
 		}
@@ -2019,18 +2028,18 @@ static int ata_eh_recover(struct ata_por
 	}
 
 	/* revalidate existing devices and attach new ones */
-	rc = ata_eh_revalidate_and_attach(ap, &dev);
+	rc = ata_eh_revalidate_and_attach(link, &dev);
 	if (rc)
 		goto dev_fail;
 
 	/* resume devices */
-	rc = ata_eh_resume(ap, &dev);
+	rc = ata_eh_resume(link, &dev);
 	if (rc)
 		goto dev_fail;
 
 	/* configure transfer mode if the port has been reset */
 	if (ehc->i.flags & ATA_EHI_DID_RESET) {
-		rc = ata_set_mode(ap, &dev);
+		rc = ata_set_mode(link, &dev);
 		if (rc) {
 			down_xfermask = 1;
 			goto dev_fail;
@@ -2038,7 +2047,7 @@ static int ata_eh_recover(struct ata_por
 	}
 
 	/* suspend devices */
-	rc = ata_eh_suspend(ap, &dev);
+	rc = ata_eh_suspend(link, &dev);
 	if (rc)
 		goto dev_fail;
 
@@ -2047,8 +2056,8 @@ static int ata_eh_recover(struct ata_por
  dev_fail:
 	ata_eh_handle_dev_fail(dev, rc, down_xfermask);
 
-	if (ata_port_nr_enabled(ap)) {
-		ata_port_printk(ap, KERN_WARNING, "failed to recover some "
+	if (ata_link_nr_enabled(link)) {
+		ata_link_printk(link, KERN_WARNING, "failed to recover some "
 				"devices, retrying in 5 secs\n");
 		ssleep(5);
 	} else {
@@ -2063,7 +2072,7 @@ static int ata_eh_recover(struct ata_por
 		/* recovery failed, activate hp-poll */
 		ata_hp_poll_activate(ap);
 
-		ata_link_for_each_dev(dev, &ap->link);
+		ata_link_for_each_dev(dev, link);
 			ata_dev_disable(dev);
 	}
 
@@ -2130,8 +2139,8 @@ void ata_do_eh(struct ata_port *ap, ata_
 	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 {
-	ata_eh_autopsy(ap);
-	ata_eh_report(ap);
+	ata_eh_autopsy(&ap->link);
+	ata_eh_report(&ap->link);
 	ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
 	ata_eh_finish(ap);
 }
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 69b9b0e..c544d88 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -57,7 +57,8 @@ extern int ata_dev_configure(struct ata_
 extern int sata_down_spd_limit(struct ata_link *link);
 extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_set_mode(struct ata_link *link,
+			struct ata_device **r_failed_dev);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
 extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-- 
1.3.2



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

* [PATCH 05/17] libata-link: linkify PHY-related functions
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (2 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 03/17] libata-link: introduce ata_link Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 07/17] libata-link: linkify reset Tejun Heo
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Make the following PHY-related functions to deal with ata_link instead
of ata_port.

* sata_print_link_status()
* sata_down_spd_limit()
* ata_set_sata_spd_limit() and friends
* sata_link_debounce/resume()
* sata_scr_valid/read/write/write_flush()
* ata_link_on/offline()

This patch introduces no behavior change.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/ahci.c         |    6 +
 drivers/scsi/libata-bmdma.c |    2 
 drivers/scsi/libata-core.c  |  229 +++++++++++++++++++++++--------------------
 drivers/scsi/libata-eh.c    |   24 ++---
 drivers/scsi/libata.h       |    4 -
 drivers/scsi/sata_mv.c      |   14 +--
 drivers/scsi/sata_sil24.c   |   10 +-
 include/linux/libata.h      |   19 ++--
 8 files changed, 164 insertions(+), 144 deletions(-)

e547f513500d9d4e27c46afa390647f4a9f21a22
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index e3ec344..d105cd1 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -621,7 +621,7 @@ static int ahci_softreset(struct ata_por
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(&ap->link)) {
 		DPRINTK("PHY reports no device\n");
 		*class = ATA_DEV_NONE;
 		return 0;
@@ -695,7 +695,7 @@ static int ahci_softreset(struct ata_por
 	msleep(150);
 
 	*class = ATA_DEV_NONE;
-	if (ata_port_online(ap)) {
+	if (ata_link_online(&ap->link)) {
 		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
 			rc = -EIO;
 			reason = "device not ready";
@@ -734,7 +734,7 @@ static int ahci_hardreset(struct ata_por
 
 	ahci_start_engine(ap);
 
-	if (rc == 0 && ata_port_online(ap))
+	if (rc == 0 && ata_link_online(&ap->link))
 		*class = ahci_dev_classify(ap);
 	if (*class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index c931a26..ba6db93 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -776,7 +776,7 @@ void ata_bmdma_error_handler(struct ata_
 	ata_reset_fn_t hardreset;
 
 	hardreset = NULL;
-	if (sata_scr_valid(ap))
+	if (sata_scr_valid(&ap->link))
 		hardreset = sata_std_hardreset;
 
 	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 0dcd2ec..2326843 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1607,7 +1607,7 @@ static int ata_bus_probe(struct ata_port
 		tries[dev->devno] = 0;
 		break;
 	case -EIO:
-		sata_down_spd_limit(ap);
+		sata_down_spd_limit(&ap->link);
 		/* fall through */
 	default:
 		tries[dev->devno]--;
@@ -1642,28 +1642,28 @@ void ata_port_probe(struct ata_port *ap)
 
 /**
  *	sata_print_link_status - Print SATA link status
- *	@ap: SATA port to printk link status about
+ *	@link: SATA link to printk link status about
  *
  *	This function prints link speed and status of a SATA link.
  *
  *	LOCKING:
  *	None.
  */
-static void sata_print_link_status(struct ata_port *ap)
+static void sata_print_link_status(struct ata_link *link)
 {
 	u32 sstatus, scontrol, tmp;
 
-	if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+	if (sata_scr_read(link, SCR_STATUS, &sstatus))
 		return;
-	sata_scr_read(ap, SCR_CONTROL, &scontrol);
+	sata_scr_read(link, SCR_CONTROL, &scontrol);
 
-	if (ata_port_online(ap)) {
+	if (ata_link_online(link)) {
 		tmp = (sstatus >> 4) & 0xf;
-		ata_port_printk(ap, KERN_INFO,
+		ata_link_printk(link, KERN_INFO,
 				"SATA link up %s (SStatus %X SControl %X)\n",
 				sata_spd_string(tmp), sstatus, scontrol);
 	} else {
-		ata_port_printk(ap, KERN_INFO,
+		ata_link_printk(link, KERN_INFO,
 				"SATA link down (SStatus %X SControl %X)\n",
 				sstatus, scontrol);
 	}
@@ -1683,32 +1683,33 @@ static void sata_print_link_status(struc
  */
 void __sata_phy_reset(struct ata_port *ap)
 {
-	u32 sstatus;
+	struct ata_link *link = &ap->link;
 	unsigned long timeout = jiffies + (HZ * 5);
+	u32 sstatus;
 
 	if (ap->flags & ATA_FLAG_SATA_RESET) {
 		/* issue phy wake/reset */
-		sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+		sata_scr_write_flush(link, SCR_CONTROL, 0x301);
 		/* Couldn't find anything in SATA I/II specs, but
 		 * AHCI-1.1 10.4.2 says at least 1 ms. */
 		mdelay(1);
 	}
 	/* phy wake/clear reset */
-	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+	sata_scr_write_flush(link, SCR_CONTROL, 0x300);
 
 	/* wait for phy to become ready, if necessary */
 	do {
 		msleep(200);
-		sata_scr_read(ap, SCR_STATUS, &sstatus);
+		sata_scr_read(link, SCR_STATUS, &sstatus);
 		if ((sstatus & 0xf) != 1)
 			break;
 	} while (time_before(jiffies, timeout));
 
 	/* print link status */
-	sata_print_link_status(ap);
+	sata_print_link_status(link);
 
 	/* TODO: phy layer with polling, timeouts, etc. */
-	if (!ata_port_offline(ap))
+	if (!ata_link_offline(link))
 		ata_port_probe(ap);
 	else
 		ata_port_disable(ap);
@@ -1782,9 +1783,9 @@ void ata_port_disable(struct ata_port *a
 
 /**
  *	sata_down_spd_limit - adjust SATA spd limit downward
- *	@ap: Port to adjust SATA spd limit for
+ *	@link: Link to adjust SATA spd limit for
  *
- *	Adjust SATA spd limit of @ap downward.  Note that this
+ *	Adjust SATA spd limit of @link downward.  Note that this
  *	function only adjusts the limit.  The change must be applied
  *	using sata_set_spd().
  *
@@ -1794,16 +1795,16 @@ void ata_port_disable(struct ata_port *a
  *	RETURNS:
  *	0 on success, negative errno on failure
  */
-int sata_down_spd_limit(struct ata_port *ap)
+int sata_down_spd_limit(struct ata_link *link)
 {
 	u32 sstatus, spd, mask;
 	int rc, highbit;
 
-	rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+	rc = sata_scr_read(link, SCR_STATUS, &sstatus);
 	if (rc)
 		return rc;
 
-	mask = ap->link.sata_spd_limit;
+	mask = link->sata_spd_limit;
 	if (mask <= 1)
 		return -EINVAL;
 	highbit = fls(mask) - 1;
@@ -1817,22 +1818,22 @@ int sata_down_spd_limit(struct ata_port 
 	if (!mask)
 		return -EINVAL;
 
-	ap->link.sata_spd_limit = mask;
+	link->sata_spd_limit = mask;
 
-	ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+	ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
 			sata_spd_string(fls(mask)));
 
 	return 0;
 }
 
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
 {
 	u32 spd, limit;
 
-	if (ap->link.sata_spd_limit == UINT_MAX)
+	if (link->sata_spd_limit == UINT_MAX)
 		limit = 0;
 	else
-		limit = fls(ap->link.sata_spd_limit);
+		limit = fls(link->sata_spd_limit);
 
 	spd = (*scontrol >> 4) & 0xf;
 	*scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
@@ -1842,10 +1843,10 @@ static int __sata_set_spd_needed(struct 
 
 /**
  *	sata_set_spd_needed - is SATA spd configuration needed
- *	@ap: Port in question
+ *	@link: Link in question
  *
  *	Test whether the spd limit in SControl matches
- *	@ap->link.sata_spd_limit.  This function is used to determine
+ *	@link->sata_spd_limit.  This function is used to determine
  *	whether hardreset is necessary to apply SATA spd
  *	configuration.
  *
@@ -1855,21 +1856,21 @@ static int __sata_set_spd_needed(struct 
  *	RETURNS:
  *	1 if SATA spd configuration is needed, 0 otherwise.
  */
-int sata_set_spd_needed(struct ata_port *ap)
+int sata_set_spd_needed(struct ata_link *link)
 {
 	u32 scontrol;
 
-	if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+	if (sata_scr_read(link, SCR_CONTROL, &scontrol))
 		return 0;
 
-	return __sata_set_spd_needed(ap, &scontrol);
+	return __sata_set_spd_needed(link, &scontrol);
 }
 
 /**
  *	sata_set_spd - set SATA spd according to spd limit
- *	@ap: Port to set SATA spd for
+ *	@link: Link to set SATA spd for
  *
- *	Set SATA spd of @ap according to sata_spd_limit.
+ *	Set SATA spd of @link according to sata_spd_limit.
  *
  *	LOCKING:
  *	Inherited from caller.
@@ -1878,18 +1879,18 @@ int sata_set_spd_needed(struct ata_port 
  *	0 if spd doesn't need to be changed, 1 if spd has been
  *	changed.  Negative errno if SCR registers are inaccessible.
  */
-int sata_set_spd(struct ata_port *ap)
+int sata_set_spd(struct ata_link *link)
 {
 	u32 scontrol;
 	int rc;
 
-	if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
-	if (!__sata_set_spd_needed(ap, &scontrol))
+	if (!__sata_set_spd_needed(link, &scontrol))
 		return 0;
 
-	if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+	if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	return 1;
@@ -2483,11 +2484,11 @@ err_out:
 }
 
 /**
- *	sata_phy_debounce - debounce SATA phy status
- *	@ap: ATA port to debounce SATA phy status for
+ *	sata_link_debounce - debounce SATA phy status
+ *	@link: ATA link to debounce SATA phy status for
  *	@params: timing parameters { interval, duratinon, timeout } in msec
  *
- *	Make sure SStatus of @ap reaches stable state, determined by
+ *	Make sure SStatus of @link reaches stable state, determined by
  *	holding the same value where DET is not 1 for @duration polled
  *	every @interval, before @timeout.  Timeout constraints the
  *	beginning of the stable state.  Because, after hot unplugging,
@@ -2500,7 +2501,7 @@ err_out:
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
+int sata_link_debounce(struct ata_link *link, const unsigned long *params)
 {
 	unsigned long interval_msec = params[0];
 	unsigned long duration = params[1] * HZ / 1000;
@@ -2509,7 +2510,7 @@ int sata_phy_debounce(struct ata_port *a
 	u32 last, cur;
 	int rc;
 
-	if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+	if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
 		return rc;
 	cur &= 0xf;
 
@@ -2518,7 +2519,7 @@ int sata_phy_debounce(struct ata_port *a
 
 	while (1) {
 		msleep(interval_msec);
-		if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+		if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
 			return rc;
 		cur &= 0xf;
 
@@ -2542,11 +2543,11 @@ int sata_phy_debounce(struct ata_port *a
 }
 
 /**
- *	sata_phy_resume - resume SATA phy
- *	@ap: ATA port to resume SATA phy for
+ *	sata_link_resume - resume SATA link
+ *	@link: ATA link to resume SATA
  *	@params: timing parameters { interval, duratinon, timeout } in msec
  *
- *	Resume SATA phy of @ap and debounce it.
+ *	Resume SATA phy @link and debounce it.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2554,17 +2555,17 @@ int sata_phy_debounce(struct ata_port *a
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
+int sata_link_resume(struct ata_link *link, const unsigned long *params)
 {
 	u32 scontrol;
 	int rc;
 
-	if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
 	scontrol = (scontrol & 0x0f0) | 0x300;
 
-	if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+	if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	/* Some PHYs react badly if SStatus is pounded immediately
@@ -2572,7 +2573,7 @@ int sata_phy_resume(struct ata_port *ap,
 	 */
 	msleep(200);
 
-	return sata_phy_debounce(ap, params);
+	return sata_link_debounce(link, params);
 }
 
 static void ata_wait_spinup(struct ata_port *ap)
@@ -2583,10 +2584,11 @@ static void ata_wait_spinup(struct ata_p
 
 	/* first, debounce phy if SATA */
 	if (ap->cbl == ATA_CBL_SATA) {
-		rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
+		rc = sata_link_debounce(&ap->link, sata_deb_timing_hotplug);
 
 		/* if debounced successfully and offline, no need to wait */
-		if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
+		if ((rc == 0 || rc == -EOPNOTSUPP) &&
+		    ata_link_offline(&ap->link))
 			return;
 	}
 
@@ -2618,7 +2620,8 @@ static void ata_wait_spinup(struct ata_p
  */
 int ata_std_prereset(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_link *link = &ap->link;
+	struct ata_eh_context *ehc = &link->eh_context;
 	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	int rc;
 
@@ -2635,9 +2638,9 @@ int ata_std_prereset(struct ata_port *ap
 	if (ehc->i.action & ATA_EH_HARDRESET)
 		return 0;
 
-	/* if SATA, resume phy */
+	/* if SATA, resume link */
 	if (ap->cbl == ATA_CBL_SATA) {
-		rc = sata_phy_resume(ap, timing);
+		rc = sata_link_resume(link, timing);
 		if (rc && rc != -EOPNOTSUPP) {
 			/* phy resume failed */
 			ata_port_printk(ap, KERN_WARNING, "failed to resume "
@@ -2649,7 +2652,7 @@ int ata_std_prereset(struct ata_port *ap
 	/* Wait for !BSY if the controller can wait for the first D2H
 	 * Reg FIS and we don't know that no device is attached.
 	 */
-	if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
+	if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link))
 		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
 
 	return 0;
@@ -2670,13 +2673,14 @@ int ata_std_prereset(struct ata_port *ap
  */
 int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
 {
+	struct ata_link *link = &ap->link;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	unsigned int devmask = 0, err_mask;
 	u8 err;
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		classes[0] = ATA_DEV_NONE;
 		goto out;
 	}
@@ -2724,37 +2728,37 @@ int ata_std_softreset(struct ata_port *a
  */
 int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
-	const unsigned long *timing = sata_ehc_deb_timing(ehc);
+	struct ata_link *link = &ap->link;
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
 	u32 scontrol;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	if (sata_set_spd_needed(ap)) {
+	if (sata_set_spd_needed(link)) {
 		/* SATA spec says nothing about how to reconfigure
 		 * spd.  To be on the safe side, turn off phy during
 		 * reconfiguration.  This works for at least ICH7 AHCI
 		 * and Sil3124.
 		 */
-		if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+		if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 			return rc;
 
 		scontrol = (scontrol & 0x0f0) | 0x302;
 
-		if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+		if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
 			return rc;
 
-		sata_set_spd(ap);
+		sata_set_spd(link);
 	}
 
 	/* issue phy wake/reset */
-	if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
 	scontrol = (scontrol & 0x0f0) | 0x301;
 
-	if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+	if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -2763,10 +2767,10 @@ int sata_std_hardreset(struct ata_port *
 	msleep(1);
 
 	/* bring phy back */
-	sata_phy_resume(ap, timing);
+	sata_link_resume(link, timing);
 
 	/* TODO: phy layer with polling, timeouts, etc. */
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		*class = ATA_DEV_NONE;
 		DPRINTK("EXIT, link offline\n");
 		return 0;
@@ -2800,16 +2804,17 @@ int sata_std_hardreset(struct ata_port *
  */
 void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
 {
+	struct ata_link *link = &ap->link;
 	u32 serror;
 
 	DPRINTK("ENTER\n");
 
 	/* print link status */
-	sata_print_link_status(ap);
+	sata_print_link_status(link);
 
 	/* clear SError */
-	if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
-		sata_scr_write(ap, SCR_ERROR, serror);
+	if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+		sata_scr_write(link, SCR_ERROR, serror);
 
 	/* re-enable interrupts */
 	if (!ap->ops->error_handler) {
@@ -2852,12 +2857,13 @@ void ata_std_postreset(struct ata_port *
  */
 void sata_std_hp_poll_activate(struct ata_port *ap)
 {
+	struct ata_link *link = &ap->link;
 	u32 serror;
 
-	sata_scr_read(ap, SCR_ERROR, &serror);
+	sata_scr_read(link, SCR_ERROR, &serror);
 	serror &= SERR_PHYRDY_CHG | SERR_DEV_XCHG;
 	if (serror)
-		sata_scr_write(ap, SCR_ERROR, serror);
+		sata_scr_write(link, SCR_ERROR, serror);
 
 	ap->hp_poll_data = 0;
 }
@@ -2879,10 +2885,11 @@ void sata_std_hp_poll_activate(struct at
 int sata_std_hp_poll(struct ata_port *ap)
 {
 	unsigned long state = (unsigned long)ap->hp_poll_data;
+	struct ata_link *link = &ap->link;
 	u32 serror;
 	int rc = 0;
 
-	sata_scr_read(ap, SCR_ERROR, &serror);
+	sata_scr_read(link, SCR_ERROR, &serror);
 	serror &= SERR_PHYRDY_CHG | SERR_DEV_XCHG;
 
 	switch (state) {
@@ -2893,7 +2900,7 @@ int sata_std_hp_poll(struct ata_port *ap
 			 * hotplug event till hotplug event stays
 			 * quiescent for one full polling interval.
 			 */
-			sata_scr_write(ap, SCR_ERROR, serror);
+			sata_scr_write(link, SCR_ERROR, serror);
 			state = 1;
 		}
 		break;
@@ -2902,7 +2909,7 @@ int sata_std_hp_poll(struct ata_port *ap
 		if (!serror)
 			rc = 1;
 		else
-			sata_scr_write(ap, SCR_ERROR, serror);
+			sata_scr_write(link, SCR_ERROR, serror);
 		break;
 	}
 
@@ -4916,9 +4923,9 @@ irqreturn_t ata_interrupt (int irq, void
 
 /**
  *	sata_scr_valid - test whether SCRs are accessible
- *	@ap: ATA port to test SCR accessibility for
+ *	@link: ATA link to test SCR accessibility for
  *
- *	Test whether SCRs are accessible for @ap.
+ *	Test whether SCRs are accessible for @link.
  *
  *	LOCKING:
  *	None.
@@ -4926,18 +4933,20 @@ irqreturn_t ata_interrupt (int irq, void
  *	RETURNS:
  *	1 if SCRs are accessible, 0 otherwise.
  */
-int sata_scr_valid(struct ata_port *ap)
+int sata_scr_valid(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
+
 	return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
 }
 
 /**
  *	sata_scr_read - read SCR register of the specified port
- *	@ap: ATA port to read SCR for
+ *	@link: ATA link to read SCR for
  *	@reg: SCR to read
  *	@val: Place to store read value
  *
- *	Read SCR register @reg of @ap into *@val.  This function is
+ *	Read SCR register @reg of @link into *@val.  This function is
  *	guaranteed to succeed if the cable type of the port is SATA
  *	and the port implements ->scr_read.
  *
@@ -4947,9 +4956,11 @@ int sata_scr_valid(struct ata_port *ap)
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
 {
-	if (sata_scr_valid(ap)) {
+	struct ata_port *ap = link->ap;
+
+	if (sata_scr_valid(link)) {
 		*val = ap->ops->scr_read(ap, reg);
 		return 0;
 	}
@@ -4958,11 +4969,11 @@ int sata_scr_read(struct ata_port *ap, i
 
 /**
  *	sata_scr_write - write SCR register of the specified port
- *	@ap: ATA port to write SCR for
+ *	@link: ATA link to write SCR for
  *	@reg: SCR to write
  *	@val: value to write
  *
- *	Write @val to SCR register @reg of @ap.  This function is
+ *	Write @val to SCR register @reg of @link.  This function is
  *	guaranteed to succeed if the cable type of the port is SATA
  *	and the port implements ->scr_read.
  *
@@ -4972,9 +4983,11 @@ int sata_scr_read(struct ata_port *ap, i
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
 {
-	if (sata_scr_valid(ap)) {
+	struct ata_port *ap = link->ap;
+
+	if (sata_scr_valid(link)) {
 		ap->ops->scr_write(ap, reg, val);
 		return 0;
 	}
@@ -4983,7 +4996,7 @@ int sata_scr_write(struct ata_port *ap, 
 
 /**
  *	sata_scr_write_flush - write SCR register of the specified port and flush
- *	@ap: ATA port to write SCR for
+ *	@link: ATA link to write SCR for
  *	@reg: SCR to write
  *	@val: value to write
  *
@@ -4996,9 +5009,11 @@ int sata_scr_write(struct ata_port *ap, 
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
 {
-	if (sata_scr_valid(ap)) {
+	struct ata_port *ap = link->ap;
+
+	if (sata_scr_valid(link)) {
 		ap->ops->scr_write(ap, reg, val);
 		ap->ops->scr_read(ap, reg);
 		return 0;
@@ -5007,12 +5022,12 @@ int sata_scr_write_flush(struct ata_port
 }
 
 /**
- *	ata_port_online - test whether the given port is online
- *	@ap: ATA port to test
+ *	ata_link_online - test whether the given link is online
+ *	@link: ATA link to test
  *
- *	Test whether @ap is online.  Note that this function returns 0
- *	if online status of @ap cannot be obtained, so
- *	ata_port_online(ap) != !ata_port_offline(ap).
+ *	Test whether @link is online.  Note that this function returns
+ *	0 if online status of @link cannot be obtained, so
+ *	ata_link_online(link) != !ata_link_offline(link).
  *
  *	LOCKING:
  *	None.
@@ -5020,22 +5035,23 @@ int sata_scr_write_flush(struct ata_port
  *	RETURNS:
  *	1 if the port online status is available and online.
  */
-int ata_port_online(struct ata_port *ap)
+int ata_link_online(struct ata_link *link)
 {
 	u32 sstatus;
 
-	if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+	    (sstatus & 0xf) == 0x3)
 		return 1;
 	return 0;
 }
 
 /**
- *	ata_port_offline - test whether the given port is offline
- *	@ap: ATA port to test
+ *	ata_link_offline - test whether the given link is offline
+ *	@link: ATA link to test
  *
- *	Test whether @ap is offline.  Note that this function returns
- *	0 if offline status of @ap cannot be obtained, so
- *	ata_port_online(ap) != !ata_port_offline(ap).
+ *	Test whether @link is offline.  Note that this function
+ *	returns 0 if offline status of @link cannot be obtained, so
+ *	ata_link_online(link) != !ata_link_offline(link).
  *
  *	LOCKING:
  *	None.
@@ -5043,11 +5059,12 @@ int ata_port_online(struct ata_port *ap)
  *	RETURNS:
  *	1 if the port offline status is available and offline.
  */
-int ata_port_offline(struct ata_port *ap)
+int ata_link_offline(struct ata_link *link)
 {
 	u32 sstatus;
 
-	if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+	    (sstatus & 0xf) != 0x3)
 		return 1;
 	return 0;
 }
@@ -5533,7 +5550,7 @@ int ata_device_add(const struct ata_prob
 		ap = host_set->ports[i];
 
 		/* init sata_spd_limit to the current value */
-		if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+		if (sata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) {
 			int spd = (scontrol >> 4) & 0xf;
 			ap->link.hw_sata_spd_limit &= (1 << spd) - 1;
 		}
@@ -6043,8 +6060,8 @@ EXPORT_SYMBOL_GPL(ata_bmdma_error_handle
 EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+EXPORT_SYMBOL_GPL(sata_link_resume);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
@@ -6073,8 +6090,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid);
 EXPORT_SYMBOL_GPL(sata_scr_read);
 EXPORT_SYMBOL_GPL(sata_scr_write);
 EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_link_online);
+EXPORT_SYMBOL_GPL(ata_link_offline);
 EXPORT_SYMBOL_GPL(ata_host_set_suspend);
 EXPORT_SYMBOL_GPL(ata_host_set_resume);
 EXPORT_SYMBOL_GPL(ata_id_string);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index fb6e3f8..22ca9a2 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1273,7 +1273,7 @@ static int ata_eh_speed_down(struct ata_
 		return 0;
 
 	/* speed down SATA link speed if possible */
-	if (sata_down_spd_limit(dev->link->ap) == 0)
+	if (sata_down_spd_limit(dev->link) == 0)
 		return ATA_EH_HARDRESET;
 
 	/* lower transfer mode */
@@ -1298,7 +1298,8 @@ static int ata_eh_speed_down(struct ata_
  */
 static void ata_eh_autopsy(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_link *link = &ap->link;
+	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned int action = ehc->i.action;
 	struct ata_device *failed_dev = NULL;
 	unsigned int all_err_mask = 0;
@@ -1312,7 +1313,7 @@ static void ata_eh_autopsy(struct ata_po
 		return;
 
 	/* obtain and analyze SError */
-	rc = sata_scr_read(ap, SCR_ERROR, &serror);
+	rc = sata_scr_read(link, SCR_ERROR, &serror);
 	if (rc == 0) {
 		ehc->i.serror |= serror;
 		ata_eh_analyze_serror(ap);
@@ -1501,7 +1502,8 @@ static int ata_eh_reset(struct ata_port 
 			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
 			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_link *link = &ap->link;
+	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
 	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
@@ -1515,7 +1517,7 @@ static int ata_eh_reset(struct ata_port 
 	 */
 	action = ehc->i.action;
 	ehc->i.action &= ~ATA_EH_RESET_MASK;
-	if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+	if (softreset && (!hardreset || (!sata_set_spd_needed(link) &&
 					 !(action & ATA_EH_HARDRESET))))
 		ehc->i.action |= ATA_EH_SOFTRESET;
 	else
@@ -1537,7 +1539,7 @@ static int ata_eh_reset(struct ata_port 
 		reset = softreset;
 	else {
 		/* prereset told us not to reset, bang classes and return */
-		ata_link_for_each_dev(dev, &ap->link)
+		ata_link_for_each_dev(dev, link)
 			classes[dev->devno] = ATA_DEV_NONE;
 		return 0;
 	}
@@ -1605,7 +1607,7 @@ static int ata_eh_reset(struct ata_port 
 		ssleep(5);
 
 		if (reset == hardreset)
-			sata_down_spd_limit(ap);
+			sata_down_spd_limit(link);
 		if (hardreset)
 			reset = hardreset;
 		goto retry;
@@ -1615,7 +1617,7 @@ static int ata_eh_reset(struct ata_port 
 		/* After the reset, the device state is PIO 0 and the
 		 * controller state is undefined.  Record the mode.
 		 */
-		ata_link_for_each_dev(dev, &ap->link)
+		ata_link_for_each_dev(dev, link)
 			dev->pio_mode = XFER_PIO_0;
 
 		if (postreset)
@@ -1643,7 +1645,7 @@ static int ata_eh_revalidate_and_attach(
 		unsigned int action = ata_eh_dev_action(dev);
 
 		if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
-			if (ata_port_offline(ap)) {
+			if (ata_link_offline(dev->link)) {
 				rc = -EIO;
 				break;
 			}
@@ -1899,7 +1901,7 @@ static void ata_eh_handle_dev_fail(struc
 		ehc->tries[dev->devno] = 0;
 		break;
 	case -EIO:
-		sata_down_spd_limit(ap);
+		sata_down_spd_limit(&ap->link);
 	default:
 		ehc->tries[dev->devno]--;
 		if (down_xfermask &&
@@ -1912,7 +1914,7 @@ static void ata_eh_handle_dev_fail(struc
 		ata_dev_disable(dev);
 
 		/* detach if offline */
-		if (ata_port_offline(ap))
+		if (ata_link_offline(&ap->link))
 			ata_eh_detach_dev(dev);
 
 		/* probe if requested */
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 3171dde..69b9b0e 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -54,8 +54,8 @@ extern unsigned int ata_do_simple_cmd(st
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 			   int post_reset, u16 *id);
 extern int ata_dev_configure(struct ata_device *dev, int print_info);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
+extern int sata_down_spd_limit(struct ata_link *link);
+extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
 extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 8c4d9be..608be65 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -1310,8 +1310,8 @@ static void mv_err_intr(struct ata_port 
 	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
 	if (EDMA_ERR_SERR & edma_err_cause) {
-		sata_scr_read(ap, SCR_ERROR, &serr);
-		sata_scr_write_flush(ap, SCR_ERROR, serr);
+		sata_scr_read(&ap->link, SCR_ERROR, &serr);
+		sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
 	}
 	if (EDMA_ERR_SELF_DIS & edma_err_cause) {
 		struct mv_port_priv *pp	= ap->private_data;
@@ -1952,15 +1952,15 @@ static void __mv_phy_reset(struct ata_po
 
 	/* Issue COMRESET via SControl */
 comreset_retry:
-	sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
 	__msleep(1, can_sleep);
 
-	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
 	__msleep(20, can_sleep);
 
 	timeout = jiffies + msecs_to_jiffies(200);
 	do {
-		sata_scr_read(ap, SCR_STATUS, &sstatus);
+		sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
 		sstatus &= 0x3;
 		if ((sstatus == 3) || (sstatus == 0))
 			break;
@@ -1978,10 +1978,10 @@ comreset_retry:
 		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
 		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
 
-	if (ata_port_online(ap)) {
+	if (ata_link_online(&ap->link)) {
 		ata_port_probe(ap);
 	} else {
-		sata_scr_read(ap, SCR_STATUS, &sstatus);
+		sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
 		ata_port_printk(ap, KERN_INFO,
 				"no device found (phy stat %08x)\n", sstatus);
 		ata_port_disable(ap);
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 298c1d8..be98dc3 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -546,7 +546,7 @@ static int sil24_softreset(struct ata_po
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(&ap->link)) {
 		DPRINTK("PHY reports no device\n");
 		*class = ATA_DEV_NONE;
 		goto out;
@@ -603,10 +603,10 @@ static int sil24_hardreset(struct ata_po
 	u32 tmp;
 
 	/* sil24 does the right thing(tm) without any protection */
-	sata_set_spd(ap);
+	sata_set_spd(&ap->link);
 
 	tout_msec = 100;
-	if (ata_port_online(ap))
+	if (ata_link_online(&ap->link))
 		tout_msec = 5000;
 
 	writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
@@ -616,14 +616,14 @@ static int sil24_hardreset(struct ata_po
 	/* SStatus oscillates between zero and valid status after
 	 * DEV_RST, debounce it.
 	 */
-	rc = sata_phy_debounce(ap, sata_deb_timing_long);
+	rc = sata_link_debounce(&ap->link, sata_deb_timing_long);
 	if (rc) {
 		reason = "PHY debouncing failed";
 		goto err;
 	}
 
 	if (tmp & PORT_CS_DEV_RST) {
-		if (ata_port_offline(ap))
+		if (ata_link_offline(&ap->link))
 			return 0;
 		reason = "link not ready";
 		goto err;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 990a555..8dfafc6 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -676,9 +676,10 @@ extern void ata_port_probe(struct ata_po
 extern void __sata_phy_reset(struct ata_port *ap);
 extern void sata_phy_reset(struct ata_port *ap);
 extern void ata_bus_reset(struct ata_port *ap);
-extern int sata_set_spd(struct ata_port *ap);
-extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param);
-extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param);
+extern int sata_set_spd(struct ata_link *link);
+extern int sata_link_debounce(struct ata_link *link,
+			      const unsigned long *params);
+extern int sata_link_resume(struct ata_link *link, const unsigned long *params);
 extern int ata_std_prereset(struct ata_port *ap);
 extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
 extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
@@ -706,12 +707,12 @@ extern int ata_scsi_ioctl(struct scsi_de
 extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
 extern int ata_scsi_release(struct Scsi_Host *host);
 extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
-extern int sata_scr_valid(struct ata_port *ap);
-extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
-extern int sata_scr_write(struct ata_port *ap, int reg, u32 val);
-extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
-extern int ata_port_online(struct ata_port *ap);
-extern int ata_port_offline(struct ata_port *ap);
+extern int sata_scr_valid(struct ata_link *link);
+extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
+extern int ata_link_online(struct ata_link *link);
+extern int ata_link_offline(struct ata_link *link);
 extern int ata_scsi_device_resume(struct scsi_device *);
 extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
 extern int ata_host_set_suspend(struct ata_host_set *host_set,
-- 
1.3.2



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

* [PATCH 07/17] libata-link: linkify reset
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (3 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 05/17] libata-link: linkify PHY-related functions Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 08/17] libata-link: linkify config/EH related functions Tejun Heo
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Make reset methods and related functions deal with ata_link instead of
ata_port.

* ata_do_reset()
* ata_eh_reset()
* all prereset/reset/postreset methods and related functions

This patch introduces no behavior change.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/ahci.c        |   31 +++++++++++++++++------------
 drivers/scsi/ata_piix.c    |   14 +++++++------
 drivers/scsi/libata-core.c |   47 ++++++++++++++++++++++----------------------
 drivers/scsi/libata-eh.c   |   35 ++++++++++++++++-----------------
 drivers/scsi/sata_nv.c     |    4 ++--
 drivers/scsi/sata_sil24.c  |   20 ++++++++++---------
 include/linux/libata.h     |   15 +++++++-------
 7 files changed, 87 insertions(+), 79 deletions(-)

f341ec269e499b6634b5de2fa0ee61bf69f246fd
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index d105cd1..f41db5d 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -596,19 +596,22 @@ static int ahci_clo(struct ata_port *ap)
 	return 0;
 }
 
-static int ahci_prereset(struct ata_port *ap)
+static int ahci_prereset(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
+
 	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
 	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
 		/* ATA_BUSY hasn't cleared, so send a CLO */
 		ahci_clo(ap);
 	}
 
-	return ata_std_prereset(ap);
+	return ata_std_prereset(link);
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class)
+static int ahci_softreset(struct ata_link *link, unsigned int *class)
 {
+	struct ata_port *ap = link->ap;
 	struct ahci_port_priv *pp = ap->private_data;
 	void __iomem *mmio = ap->host_set->mmio_base;
 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
@@ -621,7 +624,7 @@ static int ahci_softreset(struct ata_por
 
 	DPRINTK("ENTER\n");
 
-	if (ata_link_offline(&ap->link)) {
+	if (ata_link_offline(link)) {
 		DPRINTK("PHY reports no device\n");
 		*class = ATA_DEV_NONE;
 		return 0;
@@ -651,7 +654,7 @@ static int ahci_softreset(struct ata_por
 	/* restart engine */
 	ahci_start_engine(ap);
 
-	ata_tf_init(ap->link.device, &tf);
+	ata_tf_init(link->device, &tf);
 	fis = pp->cmd_tbl;
 
 	/* issue the first D2H Register FIS */
@@ -695,7 +698,7 @@ static int ahci_softreset(struct ata_por
 	msleep(150);
 
 	*class = ATA_DEV_NONE;
-	if (ata_link_online(&ap->link)) {
+	if (ata_link_online(link)) {
 		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
 			rc = -EIO;
 			reason = "device not ready";
@@ -710,12 +713,13 @@ static int ahci_softreset(struct ata_por
  fail_restart:
 	ahci_start_engine(ap);
  fail:
-	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
 	return rc;
 }
 
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
+static int ahci_hardreset(struct ata_link *link, unsigned int *class)
 {
+	struct ata_port *ap = link->ap;
 	struct ahci_port_priv *pp = ap->private_data;
 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 	struct ata_taskfile tf;
@@ -726,15 +730,15 @@ static int ahci_hardreset(struct ata_por
 	ahci_stop_engine(ap);
 
 	/* clear D2H reception area to properly wait for D2H FIS */
-	ata_tf_init(ap->link.device, &tf);
+	ata_tf_init(link->device, &tf);
 	tf.command = 0xff;
 	ata_tf_to_fis(&tf, d2h_fis, 0);
 
-	rc = sata_std_hardreset(ap, class);
+	rc = sata_std_hardreset(link, class);
 
 	ahci_start_engine(ap);
 
-	if (rc == 0 && ata_link_online(&ap->link))
+	if (rc == 0 && ata_link_online(link))
 		*class = ahci_dev_classify(ap);
 	if (*class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
@@ -743,12 +747,13 @@ static int ahci_hardreset(struct ata_por
 	return rc;
 }
 
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
 {
+	struct ata_port *ap = link->ap;
 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 	u32 new_tmp, tmp;
 
-	ata_std_postreset(ap, class);
+	ata_std_postreset(link, class);
 
 	/* Make sure port's ATAPI bit is set appropriately */
 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 9e24049..790dcf6 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -462,15 +462,16 @@ cbl40:
 
 /**
  *	piix_pata_prereset - prereset for PATA host controller
- *	@ap: Target port
+ *	@link: Target link
  *
  *	Prereset including cable detection.
  *
  *	LOCKING:
  *	None (inherited from caller).
  */
-static int piix_pata_prereset(struct ata_port *ap)
+static int piix_pata_prereset(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
 
 	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
@@ -481,7 +482,7 @@ static int piix_pata_prereset(struct ata
 
 	piix_pata_cbl_detect(ap);
 
-	return ata_std_prereset(ap);
+	return ata_std_prereset(link);
 }
 
 static void piix_pata_error_handler(struct ata_port *ap)
@@ -492,7 +493,7 @@ static void piix_pata_error_handler(stru
 
 /**
  *	piix_sata_prereset - prereset for SATA host controller
- *	@ap: Target port
+ *	@link: Target link
  *
  *	Reads and configures SATA PCI device's PCI config register
  *	Port Configuration and Status (PCS) to determine port and
@@ -505,8 +506,9 @@ static void piix_pata_error_handler(stru
  *	RETURNS:
  *	0 if device is present, -ENODEV otherwise.
  */
-static int piix_sata_prereset(struct ata_port *ap)
+static int piix_sata_prereset(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
 	const unsigned int *map = ap->host_set->private_data;
 	int base = 2 * ap->hard_port_no;
@@ -553,7 +555,7 @@ static int piix_sata_prereset(struct ata
 		return 0;
 	}
 
-	return ata_std_prereset(ap);
+	return ata_std_prereset(link);
 }
 
 static void piix_sata_error_handler(struct ata_port *ap)
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 2326843..9f6b905 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2576,19 +2576,18 @@ int sata_link_resume(struct ata_link *li
 	return sata_link_debounce(link, params);
 }
 
-static void ata_wait_spinup(struct ata_port *ap)
+static void ata_wait_spinup(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->link.eh_context;
+	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned long end, secs;
 	int rc;
 
 	/* first, debounce phy if SATA */
-	if (ap->cbl == ATA_CBL_SATA) {
-		rc = sata_link_debounce(&ap->link, sata_deb_timing_hotplug);
+	if (link->ap->cbl == ATA_CBL_SATA) {
+		rc = sata_link_debounce(link, sata_deb_timing_hotplug);
 
 		/* if debounced successfully and offline, no need to wait */
-		if ((rc == 0 || rc == -EOPNOTSUPP) &&
-		    ata_link_offline(&ap->link))
+		if ((rc == 0 || rc == -EOPNOTSUPP) && ata_link_offline(link))
 			return;
 	}
 
@@ -2600,17 +2599,17 @@ static void ata_wait_spinup(struct ata_p
 		return;
 
 	if (secs > 5)
-		ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
-				"(%lu secs)\n", secs);
+		ata_link_printk(link, KERN_INFO, "waiting for device to "
+				"spin up (%lu secs)\n", secs);
 
 	schedule_timeout_uninterruptible(end - jiffies);
 }
 
 /**
  *	ata_std_prereset - prepare for reset
- *	@ap: ATA port to be reset
+ *	@link: ATA link to be reset
  *
- *	@ap is about to be reset.  Initialize it.
+ *	@link is about to be reset.  Initialize it.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2618,9 +2617,9 @@ static void ata_wait_spinup(struct ata_p
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_prereset(struct ata_port *ap)
+int ata_std_prereset(struct ata_link *link)
 {
-	struct ata_link *link = &ap->link;
+	struct ata_port *ap = link->ap;
 	struct ata_eh_context *ehc = &link->eh_context;
 	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	int rc;
@@ -2632,7 +2631,7 @@ int ata_std_prereset(struct ata_port *ap
 
 	if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
 	    (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
-		ata_wait_spinup(ap);
+		ata_wait_spinup(link);
 
 	/* if we're about to do hardreset, nothing more to do */
 	if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2643,7 +2642,7 @@ int ata_std_prereset(struct ata_port *ap
 		rc = sata_link_resume(link, timing);
 		if (rc && rc != -EOPNOTSUPP) {
 			/* phy resume failed */
-			ata_port_printk(ap, KERN_WARNING, "failed to resume "
+			ata_link_printk(link, KERN_WARNING, "failed to resume "
 					"link for reset (errno=%d)\n", rc);
 			return rc;
 		}
@@ -2660,7 +2659,7 @@ int ata_std_prereset(struct ata_port *ap
 
 /**
  *	ata_std_softreset - reset host port via ATA SRST
- *	@ap: port to reset
+ *	@link: ATA link to reset
  *	@classes: resulting classes of attached devices
  *
  *	Reset host port using ATA SRST.
@@ -2671,9 +2670,9 @@ int ata_std_prereset(struct ata_port *ap
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
+int ata_std_softreset(struct ata_link *link, unsigned int *classes)
 {
-	struct ata_link *link = &ap->link;
+	struct ata_port *ap = link->ap;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	unsigned int devmask = 0, err_mask;
 	u8 err;
@@ -2698,7 +2697,7 @@ int ata_std_softreset(struct ata_port *a
 	DPRINTK("about to softreset, devmask=%x\n", devmask);
 	err_mask = ata_bus_softreset(ap, devmask);
 	if (err_mask) {
-		ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+		ata_link_printk(link, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
 				err_mask);
 		return -EIO;
 	}
@@ -2715,7 +2714,7 @@ int ata_std_softreset(struct ata_port *a
 
 /**
  *	sata_std_hardreset - reset host port via SATA phy reset
- *	@ap: port to reset
+ *	@link: link to reset
  *	@class: resulting class of attached device
  *
  *	SATA phy-reset host port using DET bits of SControl register.
@@ -2726,9 +2725,9 @@ int ata_std_softreset(struct ata_port *a
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
+int sata_std_hardreset(struct ata_link *link, unsigned int *class)
 {
-	struct ata_link *link = &ap->link;
+	struct ata_port *ap = link->ap;
 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
 	u32 scontrol;
 	int rc;
@@ -2792,7 +2791,7 @@ int sata_std_hardreset(struct ata_port *
 
 /**
  *	ata_std_postreset - standard postreset callback
- *	@ap: the target ata_port
+ *	@link: the target ata_link
  *	@classes: classes of attached devices
  *
  *	This function is invoked after a successful reset.  Note that
@@ -2802,9 +2801,9 @@ int sata_std_hardreset(struct ata_port *
  *	LOCKING:
  *	Kernel thread context (may sleep)
  */
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+void ata_std_postreset(struct ata_link *link, unsigned int *classes)
 {
-	struct ata_link *link = &ap->link;
+	struct ata_port *ap = link->ap;
 	u32 serror;
 
 	DPRINTK("ENTER\n");
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 62c75d4..5475e2f 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1456,16 +1456,16 @@ static void ata_eh_report(struct ata_por
 	}
 }
 
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
 			unsigned int *classes)
 {
 	struct ata_device *dev;
 	int rc;
 
-	ata_link_for_each_dev(dev, &ap->link)
+	ata_link_for_each_dev(dev, link)
 		classes[dev->devno] = ATA_DEV_UNKNOWN;
 
-	rc = reset(ap, classes);
+	rc = reset(link, classes);
 	if (rc)
 		return rc;
 
@@ -1473,12 +1473,12 @@ static int ata_do_reset(struct ata_port 
 	 * is complete and convert all ATA_DEV_UNKNOWN to
 	 * ATA_DEV_NONE.
 	 */
-	ata_link_for_each_dev(dev, &ap->link)
+	ata_link_for_each_dev(dev, link)
 		if (classes[dev->devno] != ATA_DEV_UNKNOWN)
 			break;
 
 	if (dev) {
-		ata_link_for_each_dev(dev, &ap->link) {
+		ata_link_for_each_dev(dev, link) {
 			if (classes[dev->devno] == ATA_DEV_UNKNOWN)
 				classes[dev->devno] = ATA_DEV_NONE;
 		}
@@ -1499,11 +1499,10 @@ static int ata_eh_followup_srst_needed(i
 	return 0;
 }
 
-static int ata_eh_reset(struct ata_port *ap, int classify,
+static int ata_eh_reset(struct ata_link *link, int classify,
 			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;
 	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
@@ -1525,9 +1524,9 @@ static int ata_eh_reset(struct ata_port 
 		ehc->i.action |= ATA_EH_HARDRESET;
 
 	if (prereset) {
-		rc = prereset(ap);
+		rc = prereset(link);
 		if (rc) {
-			ata_port_printk(ap, KERN_ERR,
+			ata_link_printk(link, KERN_ERR,
 					"prereset failed (errno=%d)\n", rc);
 			return rc;
 		}
@@ -1547,7 +1546,7 @@ static int ata_eh_reset(struct ata_port 
 
 	/* did prereset() screw up?  if so, fix up to avoid oopsing */
 	if (!reset) {
-		ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
+		ata_link_printk(link, KERN_ERR, "BUG: prereset() requested "
 				"invalid reset type\n");
 		if (softreset)
 			reset = softreset;
@@ -1558,14 +1557,14 @@ static int ata_eh_reset(struct ata_port 
  retry:
 	/* shut up during boot probing */
 	if (verbose)
-		ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+		ata_link_printk(link, KERN_INFO, "%s resetting port\n",
 				reset == softreset ? "soft" : "hard");
 
 	/* reset */
 	ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
 	ehc->i.flags |= ATA_EHI_DID_RESET;
 
-	rc = ata_do_reset(ap, reset, classes);
+	rc = ata_do_reset(link, reset, classes);
 
 	did_followup_srst = 0;
 	if (reset == hardreset &&
@@ -1575,18 +1574,18 @@ static int ata_eh_reset(struct ata_port 
 		reset = softreset;
 
 		if (!reset) {
-			ata_port_printk(ap, KERN_ERR,
+			ata_link_printk(link, KERN_ERR,
 					"follow-up softreset required "
 					"but no softreset avaliable\n");
 			return -EINVAL;
 		}
 
 		ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
-		rc = ata_do_reset(ap, reset, classes);
+		rc = ata_do_reset(link, reset, classes);
 
 		if (rc == 0 && classify &&
 		    classes[0] == ATA_DEV_UNKNOWN) {
-			ata_port_printk(ap, KERN_ERR,
+			ata_link_printk(link, KERN_ERR,
 					"classification failed\n");
 			return -EINVAL;
 		}
@@ -1603,7 +1602,7 @@ static int ata_eh_reset(struct ata_port 
 		} else
 			type = "hard";
 
-		ata_port_printk(ap, KERN_WARNING,
+		ata_link_printk(link, KERN_WARNING,
 				"%sreset failed, retrying in 5 secs\n", type);
 		ssleep(5);
 
@@ -1622,7 +1621,7 @@ static int ata_eh_reset(struct ata_port 
 			dev->pio_mode = XFER_PIO_0;
 
 		if (postreset)
-			postreset(ap, classes);
+			postreset(link, classes);
 
 		/* reset successful, schedule revalidation */
 		ata_eh_done(link, NULL, ATA_EH_RESET_MASK);
@@ -2008,7 +2007,7 @@ static int ata_eh_recover(struct ata_por
 	if (ehc->i.action & ATA_EH_RESET_MASK) {
 		ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
+		rc = ata_eh_reset(&ap->link, ata_port_nr_vacant(ap), prereset,
 				  softreset, hardreset, postreset);
 		if (rc) {
 			ata_port_printk(ap, KERN_ERR,
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 6659faa..929b567 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -471,7 +471,7 @@ static void nv_ck804_thaw(struct ata_por
 	writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
 }
 
-static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+static int nv_hardreset(struct ata_link *link, unsigned int *class)
 {
 	unsigned int dummy;
 
@@ -479,7 +479,7 @@ static int nv_hardreset(struct ata_port 
 	 * some controllers.  Don't classify on hardreset.  For more
 	 * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
 	 */
-	return sata_std_hardreset(ap, &dummy);
+	return sata_std_hardreset(link, &dummy);
 }
 
 static void nv_error_handler(struct ata_port *ap)
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index be98dc3..b2b8d13 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -535,8 +535,9 @@ static int sil24_init_port(struct ata_po
 	return 0;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class)
+static int sil24_softreset(struct ata_link *link, unsigned int *class)
 {
+	struct ata_port *ap = link->ap;
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
@@ -546,7 +547,7 @@ static int sil24_softreset(struct ata_po
 
 	DPRINTK("ENTER\n");
 
-	if (ata_link_offline(&ap->link)) {
+	if (ata_link_offline(link)) {
 		DPRINTK("PHY reports no device\n");
 		*class = ATA_DEV_NONE;
 		goto out;
@@ -591,22 +592,23 @@ static int sil24_softreset(struct ata_po
 	return 0;
 
  err:
-	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
 	return -EIO;
 }
 
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
+static int sil24_hardreset(struct ata_link *link, unsigned int *class)
 {
+	struct ata_port *ap = link->ap;
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
 	const char *reason;
 	int tout_msec, rc;
 	u32 tmp;
 
 	/* sil24 does the right thing(tm) without any protection */
-	sata_set_spd(&ap->link);
+	sata_set_spd(link);
 
 	tout_msec = 100;
-	if (ata_link_online(&ap->link))
+	if (ata_link_online(link))
 		tout_msec = 5000;
 
 	writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
@@ -616,14 +618,14 @@ static int sil24_hardreset(struct ata_po
 	/* SStatus oscillates between zero and valid status after
 	 * DEV_RST, debounce it.
 	 */
-	rc = sata_link_debounce(&ap->link, sata_deb_timing_long);
+	rc = sata_link_debounce(link, sata_deb_timing_long);
 	if (rc) {
 		reason = "PHY debouncing failed";
 		goto err;
 	}
 
 	if (tmp & PORT_CS_DEV_RST) {
-		if (ata_link_offline(&ap->link))
+		if (ata_link_offline(link))
 			return 0;
 		reason = "link not ready";
 		goto err;
@@ -638,7 +640,7 @@ static int sil24_hardreset(struct ata_po
 	return -EAGAIN;
 
  err:
-	ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+	ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
 	return -EIO;
 }
 
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 8dfafc6..506f72d 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -316,13 +316,14 @@ enum ata_completion_errors {
 struct scsi_device;
 struct ata_port_operations;
 struct ata_port;
+struct ata_link;
 struct ata_queued_cmd;
 
 /* typedefs */
 typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef int (*ata_prereset_fn_t)(struct ata_port *ap);
-typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
-typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef int (*ata_prereset_fn_t)(struct ata_link *link);
+typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes);
+typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes);
 
 struct ata_ioports {
 	unsigned long		cmd_addr;
@@ -680,10 +681,10 @@ extern int sata_set_spd(struct ata_link 
 extern int sata_link_debounce(struct ata_link *link,
 			      const unsigned long *params);
 extern int sata_link_resume(struct ata_link *link, const unsigned long *params);
-extern int ata_std_prereset(struct ata_port *ap);
-extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
-extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
-extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern int ata_std_prereset(struct ata_link *link);
+extern int ata_std_softreset(struct ata_link *link, unsigned int *classes);
+extern int sata_std_hardreset(struct ata_link *link, unsigned int *class);
+extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
 extern void sata_std_hp_poll_activate(struct ata_port *ap);
 extern int sata_std_hp_poll(struct ata_port *ap);
 extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
-- 
1.3.2



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

* [PATCH 09/17] libata-link: separate out link initialization functions
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (10 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 13/17] libata-link: update ata_scsi_error() to handle PMP links Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 12/17] libata-link: add PMP links Tejun Heo
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Separate out link initialization into ata_link_init() and
ata_link_init_sata_spd_limit().

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |   81 ++++++++++++++++++++++++++++++++++----------
 1 files changed, 63 insertions(+), 18 deletions(-)

f8af92d79249b584036d595b8e108d2c77f1b0bd
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index e8170e5..9a8c73e 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -69,6 +69,7 @@ static unsigned int ata_dev_init_params(
 					u16 heads, u16 sectors);
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
 static void ata_dev_xfermask(struct ata_device *dev);
+static int sata_link_init_spd_limit(struct ata_link *link);
 
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
@@ -5321,6 +5322,66 @@ void ata_dev_init(struct ata_device *dev
 }
 
 /**
+ *	ata_link_init - Initialize an ata_link structure
+ *	@ap: ATA port link is attached to
+ *	@link: Link structure to initialize
+ *
+ *	Initialize @link.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+static void ata_link_init(struct ata_port *ap, struct ata_link *link)
+{
+	struct ata_device *dev;
+
+	/* clear everything except for devices */
+	memset(link, 0, offsetof(struct ata_link, device[0]));
+
+	link->ap = ap;
+	link->active_tag = ATA_TAG_POISON;
+	link->hw_sata_spd_limit = UINT_MAX;
+
+	ata_link_for_each_dev(dev, link) {
+		dev->link = link;
+		dev->devno = dev - link->device;
+		ata_dev_init(dev);
+	}
+}
+
+/**
+ *	sata_link_init_spd_limit - Initialize link->sata_spd_limit
+ *	@link: Link to configure sata_spd_limit for
+ *
+ *	Initialize @link->[hw_]sata_spd_limit to the currently
+ *	configured value.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_link_init_spd_limit(struct ata_link *link)
+{
+
+	u32 scontrol, spd;
+	int rc;
+
+	rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+	if (rc)
+		return rc;
+
+	spd = (scontrol >> 4) & 0xf;
+	if (spd)
+		link->hw_sata_spd_limit &= (1 << spd) - 1;
+
+	link->sata_spd_limit = link->hw_sata_spd_limit;
+
+	return 0;
+}
+
+/**
  *	ata_host_init - Initialize an ata_port structure
  *	@ap: Structure to initialize
  *	@host: associated SCSI mid-layer structure
@@ -5338,8 +5399,6 @@ static void ata_host_init(struct ata_por
 			  struct ata_host_set *host_set,
 			  const struct ata_probe_ent *ent, unsigned int port_no)
 {
-	unsigned int i;
-
 	host->max_id = 16;
 	host->max_lun = 1;
 	host->max_channel = 1;
@@ -5361,8 +5420,6 @@ static void ata_host_init(struct ata_por
 	ap->udma_mask = ent->udma_mask;
 	ap->flags |= ent->host_flags;
 	ap->ops = ent->port_ops;
-	ap->link.hw_sata_spd_limit = UINT_MAX;
-	ap->link.active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
 #if defined(ATA_VERBOSE_DEBUG)
@@ -5386,14 +5443,7 @@ #endif
 	if (ap->flags & ATA_FLAG_SATA)
 		ap->cbl = ATA_CBL_SATA;
 
-	ap->link.ap = ap;
-
-	for (i = 0; i < ata_link_max_devices(&ap->link); i++) {
-		struct ata_device *dev = &ap->link.device[i];
-		dev->link = &ap->link;
-		dev->devno = i;
-		ata_dev_init(dev);
-	}
+	ata_link_init(ap, &ap->link);
 
 #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
@@ -5543,17 +5593,12 @@ int ata_device_add(const struct ata_prob
 	DPRINTK("probe begin\n");
 	for (i = 0; i < count; i++) {
 		struct ata_port *ap;
-		u32 scontrol;
 		int rc;
 
 		ap = host_set->ports[i];
 
 		/* init sata_spd_limit to the current value */
-		if (sata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) {
-			int spd = (scontrol >> 4) & 0xf;
-			ap->link.hw_sata_spd_limit &= (1 << spd) - 1;
-		}
-		ap->link.sata_spd_limit = ap->link.hw_sata_spd_limit;
+		sata_link_init_spd_limit(&ap->link);
 
 		rc = scsi_add_host(ap->host, dev);
 		if (rc) {
-- 
1.3.2



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

* [PATCH 10/17] libata-link: implement link->reset_tries
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (7 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 06/17] libata-link: linkify EH action helpers Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 11/17] libata-link: implement ata_link_abort() Tejun Heo
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Make reset_tries per-link property.  PMP links will use different
value from host links.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    1 +
 drivers/scsi/libata-eh.c   |    2 +-
 include/linux/libata.h     |    2 ++
 3 files changed, 4 insertions(+), 1 deletions(-)

1987fc0ec41d15c84201e07980cf55c2ccb06b4f
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9a8c73e..95488ea 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5341,6 +5341,7 @@ static void ata_link_init(struct ata_por
 	link->ap = ap;
 	link->active_tag = ATA_TAG_POISON;
 	link->hw_sata_spd_limit = UINT_MAX;
+	link->reset_tries = ATA_EH_RESET_TRIES;
 
 	ata_link_for_each_dev(dev, link) {
 		dev->link = link;
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index d574486..db6e132 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1508,7 +1508,7 @@ static int ata_eh_reset(struct ata_link 
 {
 	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned int *classes = ehc->classes;
-	int tries = ATA_EH_RESET_TRIES;
+	int tries = link->reset_tries;
 	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
 	struct ata_device *dev;
 	unsigned int action;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 506f72d..b24f21d 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -506,6 +506,8 @@ struct ata_link {
 	unsigned int		hw_sata_spd_limit;
 	unsigned int		sata_spd_limit;
 
+	int			reset_tries;
+
 	/* record runtime error info, protected by host_set lock */
 	struct ata_eh_info	eh_info;
 	/* EH context */
-- 
1.3.2



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

* [PATCH 11/17] libata-link: implement ata_link_abort()
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (8 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 10/17] libata-link: implement link->reset_tries Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 13/17] libata-link: update ata_scsi_error() to handle PMP links Tejun Heo
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Implement ata_link_abort().

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    1 +
 drivers/scsi/libata-eh.c   |   50 ++++++++++++++++++++++++++++++++------------
 include/linux/libata.h     |    1 +
 3 files changed, 38 insertions(+), 14 deletions(-)

1b09612fdc4030df0d6645b1307c5a144511d15b
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 95488ea..25bc6d7 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -6166,6 +6166,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_resume
 
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_link_abort);
 EXPORT_SYMBOL_GPL(ata_port_abort);
 EXPORT_SYMBOL_GPL(ata_port_freeze);
 EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index db6e132..7b4a7d8 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -539,19 +539,7 @@ void ata_port_schedule_eh(struct ata_por
 	DPRINTK("port EH scheduled\n");
 }
 
-/**
- *	ata_port_abort - abort all qc's on the port
- *	@ap: ATA port to abort qc's for
- *
- *	Abort all active qc's of @ap and schedule EH.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- *
- *	RETURNS:
- *	Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
+static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
 {
 	int tag, nr_aborted = 0;
 
@@ -560,7 +548,7 @@ int ata_port_abort(struct ata_port *ap)
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
 
-		if (qc) {
+		if (qc && (!link || qc->dev->link == link)) {
 			qc->flags |= ATA_QCFLAG_FAILED;
 			ata_qc_complete(qc);
 			nr_aborted++;
@@ -574,6 +562,40 @@ int ata_port_abort(struct ata_port *ap)
 }
 
 /**
+ *	ata_link_abort - abort all qc's on the link
+ *	@link: ATA link to abort qc's for
+ *
+ *	Abort all active qc's active on @link and schedule EH.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Number of aborted qc's.
+ */
+int ata_link_abort(struct ata_link *link)
+{
+	return ata_do_link_abort(link->ap, link);
+}
+
+/**
+ *	ata_port_abort - abort all qc's on the port
+ *	@ap: ATA port to abort qc's for
+ *
+ *	Abort all active qc's of @ap and schedule EH.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+	return ata_do_link_abort(ap, NULL);
+}
+
+/**
  *	__ata_port_freeze - freeze port
  *	@ap: ATA port to freeze
  *
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b24f21d..7d09ccc 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -844,6 +844,7 @@ #endif /* CONFIG_PCI */
 extern void ata_eng_timeout(struct ata_port *ap);
 
 extern void ata_port_schedule_eh(struct ata_port *ap);
+extern int ata_link_abort(struct ata_link *link);
 extern int ata_port_abort(struct ata_port *ap);
 extern int ata_port_freeze(struct ata_port *ap);
 
-- 
1.3.2



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

* [PATCH 12/17] libata-link: add PMP links
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (11 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 09/17] libata-link: separate out link initialization functions Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 16/17] libata-link: update hotplug to handle " Tejun Heo
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Add link->pmp, ap->nr_pmp_links, ap->pmp_link[], and implement/update
link helpers.

printk helpers are updated such that port and link are identifed as
'ataP:' if no PMP is attached, while device is identified as
'ataP.DD:'.  If PMP is attached, they become 'ataP:', 'ataP.LL:' and
'ataP.LL' - ie. link and device are identified their PMP number.

If PPM is attached (ap->nr_pmp_links != 0), ata_for_each_link()
iterates over PMP links, while __ata_for_each_link() iterates over the
host link + PMP links.  If PMP is not attached (ap->nr_pmp_links ==
0), both iterate over only the host link.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    6 +++--
 include/linux/libata.h     |   52 +++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 50 insertions(+), 8 deletions(-)

bbd82bc108860dff2c2f37de3bf4afaf42c2c6eb
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 25bc6d7..0cf2661 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5325,13 +5325,14 @@ void ata_dev_init(struct ata_device *dev
  *	ata_link_init - Initialize an ata_link structure
  *	@ap: ATA port link is attached to
  *	@link: Link structure to initialize
+ *	@pmp: Port multiplier port number
  *
  *	Initialize @link.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
  */
-static void ata_link_init(struct ata_port *ap, struct ata_link *link)
+static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
 {
 	struct ata_device *dev;
 
@@ -5339,6 +5340,7 @@ static void ata_link_init(struct ata_por
 	memset(link, 0, offsetof(struct ata_link, device[0]));
 
 	link->ap = ap;
+	link->pmp = pmp;
 	link->active_tag = ATA_TAG_POISON;
 	link->hw_sata_spd_limit = UINT_MAX;
 	link->reset_tries = ATA_EH_RESET_TRIES;
@@ -5444,7 +5446,7 @@ #endif
 	if (ap->flags & ATA_FLAG_SATA)
 		ap->cbl = ATA_CBL_SATA;
 
-	ata_link_init(ap, &ap->link);
+	ata_link_init(ap, &ap->link, 0);
 
 #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7d09ccc..b6715c1 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -499,6 +499,7 @@ struct ata_eh_context {
 
 struct ata_link {
 	struct ata_port		*ap;
+	int			pmp;		/* port multiplier port # */
 
 	unsigned int		active_tag;	/* active tag on this link */
 	u32			sactive;	/* active NCQ commands */
@@ -548,6 +549,9 @@ struct ata_port {
 	struct ata_link		link;	/* host default link */
 	struct ata_device	__dev1;	/* storage for link.device[1] */
 
+	int			nr_pmp_links;	/* nr of available PMP links */
+	struct ata_link		*pmp_link;	/* array of PMP links */
+
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
 	struct device 		*dev;
@@ -864,11 +868,16 @@ extern void ata_do_eh(struct ata_port *a
 #define ata_port_printk(ap, lv, fmt, args...) \
 	printk(lv"ata%u: "fmt, (ap)->id , ##args)
 
-#define ata_link_printk(link, lv, fmt, args...) \
-	printk(lv"ata%u: "fmt, (link)->ap->id , ##args)
+#define ata_link_printk(link, lv, fmt, args...) do { \
+	if ((link)->ap->nr_pmp_links) \
+		printk(lv"ata%u.%02u: "fmt, (link)->ap->id, (link)->pmp , ##args); \
+	else \
+		printk(lv"ata%u: "fmt, (link)->ap->id , ##args); \
+	} while(0)
 
 #define ata_dev_printk(dev, lv, fmt, args...) \
-	printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->id, (dev)->devno , ##args)
+	printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->id, \
+	       (dev)->link->pmp + (dev)->devno , ##args)
 
 /*
  * ata_eh_info helpers
@@ -993,15 +1002,46 @@ static inline unsigned int ata_dev_ready
 /*
  * link helpers
  */
+static inline int ata_is_host_link(const struct ata_link *link)
+{
+	return link == &link->ap->link;
+}
+
 static inline int ata_link_max_devices(const struct ata_link *link)
 {
-	if (link->ap->flags & ATA_FLAG_SLAVE_POSS)
+	if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS)
 		return 2;
 	return 1;
 }
 
-#define ata_port_for_each_link(lk, ap) \
-	for ((lk) = &(ap)->link; (lk); (lk) = NULL)
+static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
+{
+	if (ap->nr_pmp_links)
+		return ap->pmp_link;
+	return &ap->link;
+}
+
+static inline struct ata_link *ata_port_next_link(struct ata_link *link)
+{
+	struct ata_port *ap = link->ap;
+
+	if (link == &ap->link) {
+		if (!ap->nr_pmp_links)
+			return NULL;
+		return ap->pmp_link;
+	}
+
+	if (++link - ap->pmp_link < ap->nr_pmp_links)
+		return link;
+	return NULL;
+}
+
+#define __ata_port_for_each_link(lk, ap) \
+	for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk))
+
+#define ata_port_for_each_link(link, ap) \
+	for ((link) = ata_port_first_link(ap); (link); \
+	     (link) = ata_port_next_link(link))
 
 #define ata_link_for_each_dev(dev, link) \
 	for ((dev) = (link)->device; \
-- 
1.3.2



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

* [PATCH 13/17] libata-link: update ata_scsi_error() to handle PMP links
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (9 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 11/17] libata-link: implement ata_link_abort() Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 09/17] libata-link: separate out link initialization functions Tejun Heo
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Update ata_scsi_error() to handle PMP links.  As error conditions can
occur on both host and PMP links, __ata_port_for_each_link() is used.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-eh.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

b01c2d5a1be5b7b11edc375ac8477cf58993be00
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 7b4a7d8..6c473af 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -278,15 +278,19 @@ void ata_scsi_error(struct Scsi_Host *ho
  repeat:
 	/* invoke error handler */
 	if (ap->ops->error_handler) {
+		struct ata_link *link;
+
 		/* process port resume request */
 		ata_eh_handle_port_resume(ap);
 
 		/* fetch & clear EH info */
 		spin_lock_irqsave(ap->lock, flags);
 
-		memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context));
-		ap->link.eh_context.i = ap->link.eh_info;
-		memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info));
+		__ata_port_for_each_link(link, ap) {
+			memset(&link->eh_context, 0, sizeof(link->eh_context));
+			link->eh_context.i = link->eh_info;
+			memset(&link->eh_info, 0, sizeof(link->eh_info));
+		}
 
 		ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
 		ap->pflags &= ~ATA_PFLAG_EH_PENDING;
@@ -321,7 +325,8 @@ void ata_scsi_error(struct Scsi_Host *ho
 		}
 
 		/* this run is complete, make sure EH info is clear */
-		memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info));
+		__ata_port_for_each_link(link, ap)
+			memset(&link->eh_info, 0, sizeof(link->eh_info));
 
 		/* Clear host_eh_scheduled while holding ap->lock such
 		 * that if exception occurs after this point but
-- 
1.3.2



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

* [PATCH 14/17] libata-link: update ata_dev_configure() to deal with PMP links
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (14 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 17/17] libata-link: update Power Management " Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 15/17] libata-link: update EH " Tejun Heo
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Update ata_dev_configure() to deal with PMP links.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

6ed21e82bcfd8f7aa256f072fee6332682a4671f
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 0cf2661..3604fce 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1330,14 +1330,20 @@ static void ata_dev_config_ncq(struct at
 
 static void ata_set_port_max_cmd_len(struct ata_port *ap)
 {
-	struct ata_device *dev;
+	struct ata_link *link;
+
+	if (!ap->host)
+		return;
+
+	ap->host->max_cmd_len = 0;
 
-	if (ap->host) {
-		ap->host->max_cmd_len = 0;
-		ata_link_for_each_dev(dev, &ap->link)
+	ata_port_for_each_link(link, ap) {
+		struct ata_device *dev;
+		ata_link_for_each_dev(dev, link) {
 			ap->host->max_cmd_len = max_t(unsigned int,
 						      ap->host->max_cmd_len,
 						      dev->cdb_len);
+		}
 	}
 }
 
-- 
1.3.2



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

* [PATCH 16/17] libata-link: update hotplug to handle PMP links
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (12 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 12/17] libata-link: add PMP links Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-08  5:45 ` [PATCH 17/17] libata-link: update Power Management " Tejun Heo
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Update hotplug to handle PMP links.  When PMP is attached, the PMP
number corresponds to I of SCSI C:H:I:L.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    7 ++-
 drivers/scsi/libata-scsi.c |  109 +++++++++++++++++++++++++++++++-------------
 2 files changed, 81 insertions(+), 35 deletions(-)

ca948d6e6db6fa8c27ea7f8bd72ff276b9a7f774
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 3604fce..4088498 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5694,6 +5694,7 @@ err_free_ret:
 void ata_port_detach(struct ata_port *ap)
 {
 	unsigned long flags;
+	struct ata_link *link;
 	struct ata_device *dev;
 
 	if (!ap->ops->error_handler)
@@ -5711,8 +5712,10 @@ void ata_port_detach(struct ata_port *ap
 	 */
 	spin_lock_irqsave(ap->lock, flags);
 
-	ata_link_for_each_dev(dev, &ap->link)
-		ata_dev_disable(dev);
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link)
+			ata_dev_disable(dev);
+	}
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 8c0229b..7e33506 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2466,8 +2466,14 @@ static unsigned int atapi_xlat(struct at
 
 static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
 {
-	if (likely(id < ata_link_max_devices(&ap->link)))
-		return &ap->link.device[id];
+	if (ap->nr_pmp_links == 0) {
+		if (likely(id < ata_link_max_devices(&ap->link)))
+			return &ap->link.device[id];
+	} else {
+		if (likely(id < ap->nr_pmp_links))
+			return &ap->pmp_link[id].device[0];
+	}
+
 	return NULL;
 }
 
@@ -2920,21 +2926,30 @@ void ata_scsi_simulate(struct ata_device
 
 void ata_scsi_scan_host(struct ata_port *ap)
 {
+	struct ata_link *link;
 	struct ata_device *dev;
 
 	if (ap->flags & ATA_FLAG_DISABLED)
 		return;
 
-	ata_link_for_each_dev(dev, &ap->link) {
-		struct scsi_device *sdev;
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			struct scsi_device *sdev;
+			int devno;
 
-		if (!ata_dev_enabled(dev) || dev->sdev)
-			continue;
+			if (!ata_dev_enabled(dev) || dev->sdev)
+				continue;
+
+			if (ata_is_host_link(link))
+				devno = dev->devno;
+			else
+				devno = link->pmp;
 
-		sdev = __scsi_add_device(ap->host, 0, dev->devno, 0, NULL);
-		if (!IS_ERR(sdev)) {
-			dev->sdev = sdev;
-			scsi_device_put(sdev);
+			sdev = __scsi_add_device(ap->host, 0, devno, 0, NULL);
+			if (!IS_ERR(sdev)) {
+				dev->sdev = sdev;
+				scsi_device_put(sdev);
+			}
 		}
 	}
 }
@@ -3022,6 +3037,25 @@ static void ata_scsi_remove_dev(struct a
 	}
 }
 
+static void ata_scsi_handle_link_detach(struct ata_link *link)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *dev;
+
+	ata_link_for_each_dev(dev, link) {
+		unsigned long flags;
+
+		if (!(dev->flags & ATA_DFLAG_DETACHED))
+			continue;
+
+		spin_lock_irqsave(ap->lock, flags);
+		dev->flags &= ~ATA_DFLAG_DETACHED;
+		spin_unlock_irqrestore(ap->lock, flags);
+
+		ata_scsi_remove_dev(dev);
+	}
+}
+
 /**
  *	ata_scsi_hotplug - SCSI part of hotplug
  *	@data: Pointer to ATA port to perform SCSI hotplug on
@@ -3037,7 +3071,9 @@ static void ata_scsi_remove_dev(struct a
 void ata_scsi_hotplug(void *data)
 {
 	struct ata_port *ap = data;
+	struct ata_link *link;
 	struct ata_device *dev;
+	int i;
 
 	if (ap->pflags & ATA_PFLAG_UNLOADING) {
 		DPRINTK("ENTER/EXIT - unloading\n");
@@ -3046,19 +3082,14 @@ void ata_scsi_hotplug(void *data)
 
 	DPRINTK("ENTER\n");
 
-	/* unplug detached devices */
-	ata_link_for_each_dev(dev, &ap->link) {
-		unsigned long flags;
-
-		if (!(dev->flags & ATA_DFLAG_DETACHED))
-			continue;
-
-		spin_lock_irqsave(ap->lock, flags);
-		dev->flags &= ~ATA_DFLAG_DETACHED;
-		spin_unlock_irqrestore(ap->lock, flags);
-
-		ata_scsi_remove_dev(dev);
-	}
+	/* Unplug detached devices.  We cannot use link iterator here
+	 * because PMP links have to be scanned even if PMP is
+	 * currently not attached.  Iterate manually.
+	 */
+	ata_scsi_handle_link_detach(&ap->link);
+	if (ap->pmp_link)
+		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+			ata_scsi_handle_link_detach(&ap->pmp_link[i]);
 
 	/* scan for new ones */
 	ata_scsi_scan_host(ap);
@@ -3067,12 +3098,16 @@ void ata_scsi_hotplug(void *data)
 	 * failed silently.  Requeue if there are enabled but
 	 * unattached devices.
 	 */
-	ata_link_for_each_dev(dev, &ap->link) {
-		if (ata_dev_enabled(dev) && !dev->sdev) {
-			queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
-			break;
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			if (ata_dev_enabled(dev) && !dev->sdev) {
+				queue_delayed_work(ata_aux_wq,
+						   &ap->hotplug_task, HZ);
+				goto exit_loop;
+			}
 		}
 	}
+ exit_loop:
 
 	DPRINTK("EXIT\n");
 }
@@ -3097,7 +3132,6 @@ static int ata_scsi_user_scan(struct Scs
 			      unsigned int id, unsigned int lun)
 {
 	struct ata_port *ap = ata_shost_to_port(shost);
-	struct ata_eh_info *ehi = &ap->link.eh_info;
 	unsigned long flags;
 	int rc = 0;
 
@@ -3111,12 +3145,18 @@ static int ata_scsi_user_scan(struct Scs
 	spin_lock_irqsave(ap->lock, flags);
 
 	if (id == SCAN_WILD_CARD) {
-		ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
-		ehi->action |= ATA_EH_SOFTRESET;
+		struct ata_link *link;
+
+		ata_port_for_each_link(link, ap) {
+			struct ata_eh_info *ehi = &link->eh_info;
+			ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+			ehi->action |= ATA_EH_SOFTRESET;
+		}
 	} else {
 		struct ata_device *dev = ata_find_dev(ap, id);
 
 		if (dev) {
+			struct ata_eh_info *ehi = &dev->link->eh_info;
 			ehi->probe_mask |= 1 << dev->devno;
 			ehi->action |= ATA_EH_SOFTRESET;
 			ehi->flags |= ATA_EHI_RESUME_LINK;
@@ -3147,10 +3187,13 @@ static int ata_scsi_user_scan(struct Scs
 void ata_scsi_dev_rescan(void *data)
 {
 	struct ata_port *ap = data;
+	struct ata_link *link;
 	struct ata_device *dev;
 
-	ata_link_for_each_dev(dev, &ap->link) {
-		if (ata_dev_enabled(dev) && dev->sdev)
-			scsi_rescan_device(&(dev->sdev->sdev_gendev));
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			if (ata_dev_enabled(dev) && dev->sdev)
+				scsi_rescan_device(&(dev->sdev->sdev_gendev));
+		}
 	}
 }
-- 
1.3.2



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

* [PATCH 15/17] libata-link: update EH to deal with PMP links
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (15 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 14/17] libata-link: update ata_dev_configure() to deal with " Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  16 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Update ata_eh_autopsy(), ata_eh_report() and ata_eh_recover() to deal
with PMP links.  ata_eh_autopsy() and ata_eh_report() updates are
straightforward.  They just repeat the same operation over all
configured links.

ata_eh_recover() update is more complex as it first processes all
resets and then performs the rest.  This is necessary as thawing with
some links in unknown state can be dangerous.  ehi->action is cleared
on successful recovery of a link to avoid repeating recovery due to
failures in other links.

ata_eh_recover() iterates over only PMP links if PMP is attached, and,
on failure, the failing link is returned in @failed_link instead of
disabling devices directly.  These are to integrate ata_eh_recover()
into PMP EH later.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-eh.c |  248 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 170 insertions(+), 78 deletions(-)

fe716b0b5e94af07f10f1d07397c5e7ebf4d4e5b
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 6c473af..1805769 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1315,8 +1315,8 @@ static int ata_eh_speed_down(struct ata_
 }
 
 /**
- *	ata_eh_autopsy - analyze error and determine recovery action
- *	@link: ATA link to perform autopsy on
+ *	ata_eh_link_autopsy - analyze error and determine recovery action
+ *	@link: host link to perform autopsy on
  *
  *	Analyze why @link failed and determine which recovery actions
  *	are needed.  This function also sets more detailed AC_ERR_*
@@ -1325,7 +1325,7 @@ static int ata_eh_speed_down(struct ata_
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_autopsy(struct ata_link *link)
+static void ata_eh_link_autopsy(struct ata_link *link)
 {
 	struct ata_port *ap = link->ap;
 	struct ata_eh_context *ehc = &link->eh_context;
@@ -1418,7 +1418,25 @@ static void ata_eh_autopsy(struct ata_li
 }
 
 /**
- *	ata_eh_report - report error handling to user
+ *	ata_eh_autopsy - analyze error and determine recovery action
+ *	@ap: host port to perform autopsy on
+ *
+ *	Analyze all links of @ap and determine why they failed and
+ *	which recovery actions are needed.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+static void ata_eh_autopsy(struct ata_port *ap)
+{
+	struct ata_link *link;
+
+	__ata_port_for_each_link(link, ap)
+		ata_eh_link_autopsy(link);
+}
+
+/**
+ *	ata_eh_link_report - report error handling to user
  *	@link: ATA link EH is going on
  *
  *	Report EH to user.
@@ -1426,7 +1444,7 @@ static void ata_eh_autopsy(struct ata_li
  *	LOCKING:
  *	None.
  */
-static void ata_eh_report(struct ata_link *link)
+static void ata_eh_link_report(struct ata_link *link)
 {
 	struct ata_port *ap = link->ap;
 	struct ata_eh_context *ehc = &link->eh_context;
@@ -1486,6 +1504,23 @@ static void ata_eh_report(struct ata_lin
 	}
 }
 
+/**
+ *	ata_eh_report - report error handling to user
+ *	@ap: ATA port to report EH about
+ *
+ *	Report EH to user.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void ata_eh_report(struct ata_port *ap)
+{
+	struct ata_link *link;
+
+	__ata_port_for_each_link(link, ap)
+		ata_eh_link_report(link);
+}
+
 static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
 			unsigned int *classes)
 {
@@ -1883,6 +1918,17 @@ static int ata_link_nr_enabled(struct at
 	return cnt;
 }
 
+static int ata_port_nr_enabled(struct ata_port *ap)
+{
+	struct ata_link *link;
+	int cnt = 0;
+
+	ata_port_for_each_link(link, ap)
+		cnt += ata_link_nr_enabled(link);
+
+	return cnt;
+}
+
 static int ata_link_nr_vacant(struct ata_link *link)
 {
 	struct ata_device *dev;
@@ -1978,12 +2024,13 @@ static void ata_eh_handle_dev_fail(struc
  *	@softreset: softreset method (can be NULL)
  *	@hardreset: hardreset method (can be NULL)
  *	@postreset: postreset method (can be NULL)
+ *	@r_failed_link: out parameter for failed link
  *
  *	This is the alpha and omega, eum and yang, heart and soul of
  *	libata exception handling.  On entry, actions required to
- *	recover the port and hotplug requests are recorded in
- *	eh_context.  This function executes all the operations with
- *	appropriate retrials and fallbacks to resurrect failed
+ *	recover each link and hotplug requests are recorded in the
+ *	link's eh_context.  This function executes all the operations
+ *	with appropriate retrials and fallbacks to resurrect failed
  *	devices, detach goners and greet newcomers.
  *
  *	LOCKING:
@@ -1994,115 +2041,147 @@ static void ata_eh_handle_dev_fail(struc
  */
 static int ata_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_postreset_fn_t postreset,
+			  struct ata_link **r_failed_link)
 {
-	struct ata_link *link = &ap->link;
-	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_link *link;
 	struct ata_device *dev;
-	int down_xfermask, rc;
+	int nr_failed_devs;
+	int reset, rc;
 
 	DPRINTK("ENTER\n");
 
 	/* prep for recovery */
-	ata_link_for_each_dev(dev, link) {
-		ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+	ata_port_for_each_link(link, ap) {
+		struct ata_eh_context *ehc = &link->eh_context;
 
-		/* process hotplug request */
-		if (dev->flags & ATA_DFLAG_DETACH)
-			ata_eh_detach_dev(dev);
+		ata_link_for_each_dev(dev, link) {
+			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
-		if (!ata_dev_enabled(dev) &&
-		    ((ehc->i.probe_mask & (1 << dev->devno)) &&
-		     !(ehc->did_probe_mask & (1 << dev->devno)))) {
-			ata_eh_detach_dev(dev);
-			ata_dev_init(dev);
-			ehc->did_probe_mask |= (1 << dev->devno);
-			ehc->i.action |= ATA_EH_SOFTRESET;
+			/* process hotplug request */
+			if (dev->flags & ATA_DFLAG_DETACH)
+				ata_eh_detach_dev(dev);
+
+			if (!ata_dev_enabled(dev) &&
+			    (ehc->i.probe_mask & (1 << dev->devno) &&
+			     !(ehc->did_probe_mask & (1 << dev->devno)))) {
+				ata_eh_detach_dev(dev);
+				ata_dev_init(dev);
+				ehc->did_probe_mask |= (1 << dev->devno);
+				ehc->i.action |= ATA_EH_SOFTRESET;
+			}
 		}
 	}
 
  retry:
-	down_xfermask = 0;
 	rc = 0;
+	nr_failed_devs = 0;
+	reset = 0;
 
 	/* if UNLOADING, finish immediately */
 	if (ap->pflags & ATA_PFLAG_UNLOADING)
 		goto out;
 
-	/* prep for resume */
-	ata_eh_prep_resume(link);
+	/* prep for EH */
+	ata_port_for_each_link(link, ap) {
+		struct ata_eh_context *ehc = &link->eh_context;
 
-	/* skip EH if possible. */
-	if (ata_eh_skip_recovery(link))
-		ehc->i.action = 0;
+		/* prep for resume */
+		ata_eh_prep_resume(link);
 
-	ata_link_for_each_dev(dev, link)
-		ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+		/* skip EH if possible. */
+		if (ata_eh_skip_recovery(link))
+			ehc->i.action = 0;
+
+		/* do we need to reset? */
+		if (ehc->i.action & ATA_EH_RESET_MASK)
+			reset = 1;
+
+		ata_link_for_each_dev(dev, link)
+			ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+	}
 
 	/* reset */
-	if (ehc->i.action & ATA_EH_RESET_MASK) {
+	if (reset) {
 		ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset,
-				  softreset, hardreset, postreset);
-		if (rc) {
-			ata_link_printk(link, KERN_ERR,
-					"reset failed, giving up\n");
-			goto out;
+		ata_port_for_each_link(link, ap) {
+			struct ata_eh_context *ehc = &link->eh_context;
+
+			if (!(ehc->i.action & ATA_EH_RESET_MASK))
+				continue;
+
+			rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+					  prereset, softreset, hardreset,
+					  postreset);
+			if (rc) {
+				ata_link_printk(link, KERN_ERR,
+						"reset failed, giving up\n");
+				goto out;
+			}
 		}
 
 		ata_eh_thaw_port(ap);
 	}
 
-	/* revalidate existing devices and attach new ones */
-	rc = ata_eh_revalidate_and_attach(link, &dev);
-	if (rc)
-		goto dev_fail;
+	/* the rest */
+	ata_port_for_each_link(link, ap) {
+		struct ata_eh_context *ehc = &link->eh_context;
+		int down_xfermask = 0;
 
-	/* resume devices */
-	rc = ata_eh_resume(link, &dev);
-	if (rc)
-		goto dev_fail;
+		/* revalidate existing devices and attach new ones */
+		rc = ata_eh_revalidate_and_attach(link, &dev);
+		if (rc)
+			goto dev_fail;
 
-	/* configure transfer mode if the port has been reset */
-	if (ehc->i.flags & ATA_EHI_DID_RESET) {
-		rc = ata_set_mode(link, &dev);
-		if (rc) {
-			down_xfermask = 1;
+		/* resume devices */
+		rc = ata_eh_resume(link, &dev);
+		if (rc)
 			goto dev_fail;
+
+		/* configure transfer mode if the port has been reset */
+		if (ehc->i.flags & ATA_EHI_DID_RESET) {
+			rc = ata_set_mode(link, &dev);
+			if (rc) {
+				down_xfermask = 1;
+				goto dev_fail;
+			}
 		}
-	}
 
-	/* suspend devices */
-	rc = ata_eh_suspend(link, &dev);
-	if (rc)
-		goto dev_fail;
+		/* suspend devices */
+		rc = ata_eh_suspend(link, &dev);
+		if (rc)
+			goto dev_fail;
 
-	goto out;
+		/* this link is okay now */
+		ehc->i.flags &= ~ATA_EHI_DID_RESET;
+		continue;
 
- dev_fail:
-	ata_eh_handle_dev_fail(dev, rc, down_xfermask);
+	dev_fail:
+		ata_eh_handle_dev_fail(dev, rc, down_xfermask);
+		nr_failed_devs++;
 
-	if (ata_link_nr_enabled(link)) {
-		ata_link_printk(link, KERN_WARNING, "failed to recover some "
-				"devices, retrying in 5 secs\n");
-		ssleep(5);
-	} else {
-		/* no device left, repeat fast */
-		msleep(500);
+		if (ap->pflags & ATA_PFLAG_FROZEN)
+			break;
 	}
 
-	goto retry;
-
- out:
-	if (rc) {
-		/* recovery failed, activate hp-poll */
-		ata_hp_poll_activate(ap);
+	if (nr_failed_devs) {
+		if (ata_port_nr_enabled(ap)) {
+			ata_port_printk(ap, KERN_WARNING, "failed to recover "
+					"some devices, retrying in 5 secs\n");
+			ssleep(5);
+		} else {
+			/* no device left, repeat fast */
+			msleep(500);
+		}
 
-		ata_link_for_each_dev(dev, link);
-			ata_dev_disable(dev);
+		goto retry;
 	}
 
+ out:
+	if (rc && r_failed_link)
+		*r_failed_link = link;
+
 	DPRINTK("EXIT, rc=%d\n", rc);
 	return rc;
 }
@@ -2166,9 +2245,22 @@ void ata_do_eh(struct ata_port *ap, ata_
 	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 {
-	ata_eh_autopsy(&ap->link);
-	ata_eh_report(&ap->link);
-	ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+	struct ata_device *dev;
+	int rc;
+
+	ata_eh_autopsy(ap);
+	ata_eh_report(ap);
+
+	rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+			    NULL);
+	if (rc) {
+		/* recovery failed, activate hp-poll */
+		ata_hp_poll_activate(ap);
+
+		ata_link_for_each_dev(dev, &ap->link)
+			ata_dev_disable(dev);
+	}
+
 	ata_eh_finish(ap);
 }
 
-- 
1.3.2



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

* [PATCH 17/17] libata-link: update Power Management to handle PMP links
  2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
                   ` (13 preceding siblings ...)
  2006-07-08  5:45 ` [PATCH 16/17] libata-link: update hotplug to handle " Tejun Heo
@ 2006-07-08  5:45 ` Tejun Heo
  2006-07-19 20:29   ` Jeff Garzik
  2006-07-08  5:45 ` [PATCH 14/17] libata-link: update ata_dev_configure() to deal with " Tejun Heo
  2006-07-08  5:45 ` [PATCH 15/17] libata-link: update EH " Tejun Heo
  16 siblings, 1 reply; 22+ messages in thread
From: Tejun Heo @ 2006-07-08  5:45 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Update Power Management to consider PMP links.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |   20 +++++++++++++-------
 drivers/scsi/libata-eh.c   |   16 ++++++++++------
 2 files changed, 23 insertions(+), 13 deletions(-)

e65868d12527ea6e764aed3b996d103df352dac1
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 4088498..a887522 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5106,6 +5106,7 @@ static int ata_host_set_request_pm(struc
 
 	for (i = 0; i < host_set->n_ports; i++) {
 		struct ata_port *ap = host_set->ports[i];
+		struct ata_link *link;
 
 		/* Previous resume operation might still be in
 		 * progress.  Wait for PM_PENDING to clear.
@@ -5125,8 +5126,10 @@ static int ata_host_set_request_pm(struc
 		}
 
 		ap->pflags |= ATA_PFLAG_PM_PENDING;
-		ap->link.eh_info.action |= action;
-		ap->link.eh_info.flags |= ehi_flags;
+		__ata_port_for_each_link(link, ap) {
+			link->eh_info.action |= action;
+			link->eh_info.flags |= ehi_flags;
+		}
 
 		ata_port_schedule_eh(ap);
 
@@ -5173,15 +5176,18 @@ int ata_host_set_suspend(struct ata_host
 	 */
 	for (i = 0; i < host_set->n_ports; i++) {
 		struct ata_port *ap = host_set->ports[i];
+		struct ata_link *link;
 		struct ata_device *dev;
 
-		ata_link_for_each_dev(dev, &ap->link) {
-			if (ata_dev_ready(dev)) {
-				ata_port_printk(ap, KERN_WARNING,
+		ata_port_for_each_link(link, ap) {
+			ata_link_for_each_dev(dev, link) {
+				if (ata_dev_ready(dev)) {
+					ata_port_printk(ap, KERN_WARNING,
 						"suspend failed, device %d "
 						"still active\n", dev->devno);
-				rc = -EBUSY;
-				goto fail;
+					rc = -EBUSY;
+					goto fail;
+				}
 			}
 		}
 	}
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 1805769..076badd 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -2356,17 +2356,21 @@ static void ata_eh_handle_port_resume(st
 	/* give devices time to request EH */
 	timeout = jiffies + HZ; /* 1s max */
 	while (1) {
+		struct ata_link *link;
 		struct ata_device *dev;
 
-		ata_link_for_each_dev(dev, &ap->link) {
-			unsigned int action = ata_eh_dev_action(dev);
+		ata_port_for_each_link(link, ap) {
+			ata_link_for_each_dev(dev, link) {
+				unsigned int action = ata_eh_dev_action(dev);
 
-			if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
-			    !(action & ATA_EH_RESUME))
-				break;
+				if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+				    !(action & ATA_EH_RESUME))
+					goto out_of_loop;
+			}
 		}
+	out_of_loop:
 
-		if (dev == NULL || time_after(jiffies, timeout))
+		if (link == NULL || time_after(jiffies, timeout))
 			break;
 		msleep(10);
 	}
-- 
1.3.2



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

* Re: [PATCH 02/17] libata-link: add PMP related ATA constants
  2006-07-08  5:45 ` [PATCH 02/17] libata-link: add PMP related ATA constants Tejun Heo
@ 2006-07-19 20:24   ` Jeff Garzik
  0 siblings, 0 replies; 22+ messages in thread
From: Jeff Garzik @ 2006-07-19 20:24 UTC (permalink / raw)
  To: Tejun Heo; +Cc: alan, lkml, forrest.zhao, linux-ide

ACK 1-2


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

* Re: [PATCH 03/17] libata-link: introduce ata_link
  2006-07-08  5:45 ` [PATCH 03/17] libata-link: introduce ata_link Tejun Heo
@ 2006-07-19 20:26   ` Jeff Garzik
  2006-07-24  6:19     ` Tejun Heo
  0 siblings, 1 reply; 22+ messages in thread
From: Jeff Garzik @ 2006-07-19 20:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: alan, lkml, forrest.zhao, linux-ide

Tejun Heo wrote:
> @@ -496,6 +496,23 @@ struct ata_eh_context {
>  	unsigned int		did_probe_mask;
>  };
>  
> +struct ata_link {
> +	struct ata_port		*ap;
> +
> +	unsigned int		active_tag;	/* active tag on this link */
> +	u32			sactive;	/* active NCQ commands */
> +
> +	unsigned int		hw_sata_spd_limit;
> +	unsigned int		sata_spd_limit;
> +
> +	/* record runtime error info, protected by host_set lock */
> +	struct ata_eh_info	eh_info;
> +	/* EH context */
> +	struct ata_eh_context	eh_context;
> +
> +	struct ata_device	device[1];
> +};
> +
>  struct ata_port {
>  	struct Scsi_Host	*host;	/* our co-allocated scsi host */
>  	const struct ata_port_operations *ops;
> @@ -520,22 +537,13 @@ struct ata_port {
>  	unsigned int		mwdma_mask;
>  	unsigned int		udma_mask;
>  	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
> -	unsigned int		hw_sata_spd_limit;
> -	unsigned int		sata_spd_limit;	/* SATA PHY speed limit */
> -
> -	/* record runtime error info, protected by host_set lock */
> -	struct ata_eh_info	eh_info;
> -	/* EH context owned by EH */
> -	struct ata_eh_context	eh_context;
> -
> -	struct ata_device	device[ATA_MAX_DEVICES];
>  
>  	struct ata_queued_cmd	qcmd[ATA_MAX_QUEUE];
>  	unsigned long		qc_allocated;
>  	unsigned int		qc_active;
>  
> -	unsigned int		active_tag;
> -	u32			sactive;
> +	struct ata_link		link;	/* host default link */
> +	struct ata_device	__dev1;	/* storage for link.device[1] */

This storage mess for link.device[] is NAK'd.

This patch overall looks good, but it should really be entirely an 
equivalent-transformation patch, one that is easy to review and prove 
correct.

As such, this patch should move 'struct ata_device 
device[ATA_MAX_DEVICES]' into struct ata_link, rather than the strange 
arrangement you have above.  If you want to do something unusual like 
this, it's better to do it in a separate patch.

	Jeff



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

* Re: [PATCH 17/17] libata-link: update Power Management to handle PMP links
  2006-07-08  5:45 ` [PATCH 17/17] libata-link: update Power Management " Tejun Heo
@ 2006-07-19 20:29   ` Jeff Garzik
  0 siblings, 0 replies; 22+ messages in thread
From: Jeff Garzik @ 2006-07-19 20:29 UTC (permalink / raw)
  To: Tejun Heo; +Cc: alan, lkml, forrest.zhao, linux-ide

mostly ACK the read of the patches.  I skimmed some of the linkify 
patches, but they all look pretty sane to me.


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

* Re: [PATCH 03/17] libata-link: introduce ata_link
  2006-07-19 20:26   ` Jeff Garzik
@ 2006-07-24  6:19     ` Tejun Heo
  0 siblings, 0 replies; 22+ messages in thread
From: Tejun Heo @ 2006-07-24  6:19 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: alan, lkml, forrest.zhao, linux-ide

Jeff Garzik wrote:
> Tejun Heo wrote:
>> @@ -496,6 +496,23 @@ struct ata_eh_context {
>>      unsigned int        did_probe_mask;
>>  };
>>  
>> +struct ata_link {
>> +    struct ata_port        *ap;
>> +
>> +    unsigned int        active_tag;    /* active tag on this link */
>> +    u32            sactive;    /* active NCQ commands */
>> +
>> +    unsigned int        hw_sata_spd_limit;
>> +    unsigned int        sata_spd_limit;
>> +
>> +    /* record runtime error info, protected by host_set lock */
>> +    struct ata_eh_info    eh_info;
>> +    /* EH context */
>> +    struct ata_eh_context    eh_context;
>> +
>> +    struct ata_device    device[1];
>> +};
>> +
>>  struct ata_port {
>>      struct Scsi_Host    *host;    /* our co-allocated scsi host */
>>      const struct ata_port_operations *ops;
>> @@ -520,22 +537,13 @@ struct ata_port {
>>      unsigned int        mwdma_mask;
>>      unsigned int        udma_mask;
>>      unsigned int        cbl;    /* cable type; ATA_CBL_xxx */
>> -    unsigned int        hw_sata_spd_limit;
>> -    unsigned int        sata_spd_limit;    /* SATA PHY speed limit */
>> -
>> -    /* record runtime error info, protected by host_set lock */
>> -    struct ata_eh_info    eh_info;
>> -    /* EH context owned by EH */
>> -    struct ata_eh_context    eh_context;
>> -
>> -    struct ata_device    device[ATA_MAX_DEVICES];
>>  
>>      struct ata_queued_cmd    qcmd[ATA_MAX_QUEUE];
>>      unsigned long        qc_allocated;
>>      unsigned int        qc_active;
>>  
>> -    unsigned int        active_tag;
>> -    u32            sactive;
>> +    struct ata_link        link;    /* host default link */
>> +    struct ata_device    __dev1;    /* storage for link.device[1] */
> 
> This storage mess for link.device[] is NAK'd.
> 
> This patch overall looks good, but it should really be entirely an 
> equivalent-transformation patch, one that is easy to review and prove 
> correct.
> 
> As such, this patch should move 'struct ata_device 
> device[ATA_MAX_DEVICES]' into struct ata_link, rather than the strange 
> arrangement you have above.  If you want to do something unusual like 
> this, it's better to do it in a separate patch.

Okay, will separate out __dev1 thing.

-- 
tejun


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

end of thread, other threads:[~2006-07-24  9:56 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-07-08  5:45 [PATCHSET 1/3] implement ata_link, take 2 Tejun Heo
2006-07-08  5:45 ` [PATCH 01/17] libata-link: separate out ata_eh_handle_dev_fail() Tejun Heo
2006-07-08  5:45 ` [PATCH 02/17] libata-link: add PMP related ATA constants Tejun Heo
2006-07-19 20:24   ` Jeff Garzik
2006-07-08  5:45 ` [PATCH 03/17] libata-link: introduce ata_link Tejun Heo
2006-07-19 20:26   ` Jeff Garzik
2006-07-24  6:19     ` Tejun Heo
2006-07-08  5:45 ` [PATCH 05/17] libata-link: linkify PHY-related functions Tejun Heo
2006-07-08  5:45 ` [PATCH 07/17] libata-link: linkify reset Tejun Heo
2006-07-08  5:45 ` [PATCH 08/17] libata-link: linkify config/EH related functions Tejun Heo
2006-07-08  5:45 ` [PATCH 04/17] libata-link: implement and use link/device iterators Tejun Heo
2006-07-08  5:45 ` [PATCH 06/17] libata-link: linkify EH action helpers Tejun Heo
2006-07-08  5:45 ` [PATCH 10/17] libata-link: implement link->reset_tries Tejun Heo
2006-07-08  5:45 ` [PATCH 11/17] libata-link: implement ata_link_abort() Tejun Heo
2006-07-08  5:45 ` [PATCH 13/17] libata-link: update ata_scsi_error() to handle PMP links Tejun Heo
2006-07-08  5:45 ` [PATCH 09/17] libata-link: separate out link initialization functions Tejun Heo
2006-07-08  5:45 ` [PATCH 12/17] libata-link: add PMP links Tejun Heo
2006-07-08  5:45 ` [PATCH 16/17] libata-link: update hotplug to handle " Tejun Heo
2006-07-08  5:45 ` [PATCH 17/17] libata-link: update Power Management " Tejun Heo
2006-07-19 20:29   ` Jeff Garzik
2006-07-08  5:45 ` [PATCH 14/17] libata-link: update ata_dev_configure() to deal with " Tejun Heo
2006-07-08  5:45 ` [PATCH 15/17] libata-link: update EH " Tejun Heo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.