linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/14] libata-link: add PM related ATA constants
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 02/14] libata-link: introduce ata_link Tejun Heo
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

---

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

51b532b3a54ccca372762a5f3cad55e65807df27
diff --git a/include/linux/ata.h b/include/linux/ata.h
index c494e1c..41ea837 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_PM_READ		= 0xE4,
+	ATA_CMD_PM_WRITE	= 0xE8,
 
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
@@ -187,6 +189,28 @@ enum {
 						   0=to device, 1=to host */
 	ATAPI_CDB_LEN		= 16,
 
+	/* PM stuff */
+	ATA_PM_MAX_PORTS	= 15,
+	ATA_PM_CTRL_PORT	= 15,
+
+	ATA_PM_GSCR_DWORDS	= 128,
+	ATA_PM_GSCR_PROD_ID	= 0,
+	ATA_PM_GSCR_REV		= 1,
+	ATA_PM_GSCR_PORT_INFO	= 2,
+	ATA_PM_GSCR_ERROR	= 32,
+	ATA_PM_GSCR_ERROR_EN	= 33,
+	ATA_PM_GSCR_FEAT	= 64,
+	ATA_PM_GSCR_FEAT_EN	= 96,
+
+	ATA_PM_PSCR_STATUS	= 0,
+	ATA_PM_PSCR_ERROR	= 1,
+	ATA_PM_PSCR_CONTROL	= 2,
+
+	ATA_PM_FEAT_BIST	= (1 << 0),
+	ATA_PM_FEAT_PMREQ	= (1 << 1),
+	ATA_PM_FEAT_DYNSSC	= (1 << 2),
+	ATA_PM_FEAT_NOTIFY	= (1 << 3),
+
 	/* cable types */
 	ATA_CBL_NONE		= 0,
 	ATA_CBL_PATA40		= 1,
@@ -363,4 +387,9 @@ static inline int lba_48_ok(u64 block, u
 	return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
 }
 
+#define ata_pm_gscr_vendor(gscr)	((gscr)[ATA_PM_GSCR_PROD_ID] & 0xffff)
+#define ata_pm_gscr_devid(gscr)		((gscr)[ATA_PM_GSCR_PROD_ID] >> 16)
+#define ata_pm_gscr_rev(gscr)		(((gscr)[ATA_PM_GSCR_REV] >> 8) & 0xff)
+#define ata_pm_gscr_ports(gscr)		((gscr)[ATA_PM_GSCR_PORT_INFO] & 0xf)
+
 #endif /* __LINUX_ATA_H__ */
-- 
1.2.4



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

* [PATCH 02/14] libata-link: introduce ata_link
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
  2006-05-11 16:30 ` [PATCH 01/14] libata-link: add PM related ATA constants Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 12/14] libata-link: update ata_dev_configure() to deal with PM links Tejun Heo
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, 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.

---

 drivers/scsi/ahci.c         |   20 +++---
 drivers/scsi/libata-bmdma.c |    4 +
 drivers/scsi/libata-core.c  |  134 +++++++++++++++++++++++--------------------
 drivers/scsi/libata-eh.c    |   68 +++++++++++-----------
 drivers/scsi/libata-scsi.c  |   20 +++---
 drivers/scsi/pdc_adma.c     |    4 +
 drivers/scsi/sata_mv.c      |    6 +-
 drivers/scsi/sata_nv.c      |    2 -
 drivers/scsi/sata_promise.c |    4 +
 drivers/scsi/sata_qstor.c   |    4 +
 drivers/scsi/sata_sil.c     |    4 +
 drivers/scsi/sata_sil24.c   |   10 ++-
 drivers/scsi/sata_sx4.c     |    4 +
 drivers/scsi/sata_vsc.c     |    2 -
 include/linux/libata.h      |   40 ++++++++-----
 15 files changed, 174 insertions(+), 152 deletions(-)

14834a330b2a065a120bc776be561f3be32831c1
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index ce8b00a..e3b4fd5 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -617,7 +617,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 */
@@ -709,7 +709,7 @@ static void ahci_postreset(struct ata_po
 
 	/* clear stored SError */
 	spin_lock_irqsave(&ap->host_set->lock, flags);
-	ap->eh_info.serror = 0;
+	ap->link.eh_info.serror = 0;
 	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
 	/* Make sure port's ATAPI bit is set appropriately */
@@ -807,7 +807,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;
@@ -855,7 +855,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
@@ -871,7 +871,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, serror, qc_active;
 	int rc;
 
@@ -897,7 +897,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);
@@ -915,13 +915,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))
@@ -931,7 +931,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/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index db5a975..b3a4642 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -716,12 +716,12 @@ void ata_bmdma_drive_eh(struct ata_port 
 			ata_postreset_fn_t postreset)
 {
 	struct ata_host_set *host_set = ap->host_set;
-	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 defc6c9..e132e47 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -799,7 +799,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);
 	}
@@ -997,7 +997,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;
@@ -1037,11 +1038,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 */
@@ -1106,8 +1107,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.
@@ -1185,7 +1186,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;
@@ -1268,13 +1269,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)) {
@@ -1309,7 +1311,7 @@ static void ata_dev_config_ncq(struct at
  */
 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 i, rc;
@@ -1436,7 +1438,7 @@ int ata_dev_configure(struct ata_device 
 	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);
 
 	/* limit bridge transfers to udma5, 200 sectors */
 	if (ata_dev_knobble(dev)) {
@@ -1492,7 +1494,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)
@@ -1507,7 +1509,7 @@ static int ata_bus_probe(struct ata_port
 
 	/* 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];
@@ -1532,7 +1534,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 */
@@ -1693,8 +1695,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;
@@ -1715,8 +1717,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;
 }
 
@@ -1743,7 +1745,7 @@ int ata_down_sata_spd_limit(struct ata_p
 	if (rc)
 		return rc;
 
-	mask = ap->sata_spd_limit;
+	mask = ap->link.sata_spd_limit;
 	if (mask <= 1)
 		return -EINVAL;
 	highbit = fls(mask) - 1;
@@ -1757,7 +1759,7 @@ int ata_down_sata_spd_limit(struct ata_p
 	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)));
@@ -1769,10 +1771,10 @@ static int __ata_set_sata_spd_needed(str
 {
 	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);
@@ -1785,7 +1787,7 @@ static int __ata_set_sata_spd_needed(str
  *	@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.
  *
@@ -2084,7 +2086,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_enabled(&ap->device[i])) {
+			if (ata_dev_enabled(&ap->link.device[i])) {
 				ap->ops->set_mode(ap);
 				break;
 			}
@@ -2096,7 +2098,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;
@@ -2117,7 +2119,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;
 
@@ -2135,7 +2137,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;
@@ -2148,7 +2150,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];
 
 		if (!ata_dev_enabled(dev))
 			continue;
@@ -2356,6 +2358,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;
@@ -2388,23 +2391,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)) {
@@ -2540,7 +2543,7 @@ int ata_std_prereset(struct ata_port *ap
 	int rc;
 
 	/* if we're about to do hardreset, don't bother */
-	if (ap->eh_context.i.action & ATA_EH_HARDRESET)
+	if (ap->link.eh_context.i.action & ATA_EH_HARDRESET)
 		return 0;
 
 	/* resume port */
@@ -2822,7 +2825,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)) {
@@ -2941,7 +2944,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;
@@ -2957,7 +2961,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;
@@ -4199,7 +4203,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);
@@ -4242,6 +4246,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));
@@ -4251,9 +4256,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
@@ -4416,19 +4421,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;
@@ -4719,7 +4725,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);
@@ -4928,7 +4934,7 @@ static int ata_start_drive(struct ata_de
  */
 int ata_device_resume(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 
 	if (ap->flags & ATA_FLAG_SUSPENDED) {
 		struct ata_device *failed_dev;
@@ -4953,7 +4959,7 @@ int ata_device_resume(struct ata_device 
  */
 int ata_device_suspend(struct ata_device *dev, pm_message_t state)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 
 	if (!ata_dev_enabled(dev))
 		return 0;
@@ -5059,11 +5065,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
@@ -5121,8 +5128,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;
 
 	INIT_WORK(&ap->port_task, NULL, NULL);
@@ -5134,9 +5141,11 @@ static void ata_host_init(struct ata_por
 	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);
 	}
@@ -5298,9 +5307,9 @@ int ata_device_add(const struct ata_prob
 		/* init sata_spd_limit to the current value */
 		if (ata_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) {
@@ -5320,8 +5329,9 @@ int ata_device_add(const struct ata_prob
 
 			spin_lock_irqsave(&ap->host_set->lock, flags);
 
-			ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
-			ap->eh_info.action |= ATA_EH_SOFTRESET;
+			ap->link.eh_info.probe_mask =
+				(1 << ATA_MAX_DEVICES) - 1;
+			ap->link.eh_info.action |= ATA_EH_SOFTRESET;
 
 			set_bit(bit, &ap->flags);
 			ata_port_schedule_eh(ap);
@@ -5396,7 +5406,7 @@ void ata_port_detach(struct ata_port *ap
 
 	ap->flags |= ATA_FLAG_UNLOADING;
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ap->device[i].flags |= ATA_DFLAG_DETACH;
+		ap->link.device[i].flags |= ATA_DFLAG_DETACH;
 
 	ata_port_schedule_eh(ap);
 
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 88f8bc7..cde769f 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -133,7 +133,7 @@ enum scsi_eh_timer_return ata_scsi_timed
 
 	ret = EH_HANDLED;
 	spin_lock_irqsave(&ap->host_set->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;
@@ -238,10 +238,10 @@ void ata_scsi_error(struct Scsi_Host *ho
 		/* fetch & clear EH info */
 		spin_lock_irqsave(hs_lock, flags);
 
-		memset(&ap->eh_context, 0, sizeof(ap->eh_context));
+		memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context));
 		if (!(ap->flags & ATA_FLAG_UNLOADING))
-			ap->eh_context.i = ap->eh_info;
-		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+			ap->link.eh_context.i = ap->link.eh_info;
+		memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info));
 
 		ap->flags &= ~ATA_FLAG_EH_PENDING;
 
@@ -269,7 +269,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 hs_lock such
 		 * that if exception occurs after this point but
@@ -280,7 +280,7 @@ void ata_scsi_error(struct Scsi_Host *ho
 
 		spin_unlock_irqrestore(hs_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);
 	}
 
@@ -401,7 +401,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");
 }
@@ -654,7 +654,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);
@@ -688,7 +688,7 @@ static void ata_eh_about_to_do(struct at
 	unsigned long flags;
 
 	spin_lock_irqsave(&ap->host_set->lock, flags);
-	ap->eh_info.action &= ~action;
+	ap->link.eh_info.action &= ~action;
 	ap->flags |= ATA_FLAG_RECOVERED;
 	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 }
@@ -784,7 +784,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;
@@ -837,7 +837,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];
 
@@ -889,7 +889,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;
 
@@ -934,8 +934,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;
@@ -945,7 +945,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? */
@@ -967,7 +967,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;
@@ -1154,7 +1154,7 @@ static int ata_eh_speed_down(struct ata_
 		return 0;
 
 	/* speed down SATA link speed if possible */
-	if (ata_down_sata_spd_limit(dev->ap) == 0)
+	if (ata_down_sata_spd_limit(dev->link->ap) == 0)
 		return ATA_EH_HARDRESET;
 
 	/* lower transfer mode */
@@ -1179,7 +1179,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;
@@ -1267,7 +1267,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;
 
@@ -1296,15 +1296,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);
 	}
@@ -1367,7 +1367,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 = !(ap->flags & ATA_FLAG_LOADING);
@@ -1484,7 +1484,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;
@@ -1492,7 +1492,7 @@ static int ata_eh_revalidate_and_attach(
 	DPRINTK("ENTER\n");
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+		dev = &ap->link.device[i];
 
 		if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) &&
 		    (!ehc->i.dev || ehc->i.dev == dev)) {
@@ -1540,7 +1540,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;
 }
@@ -1550,14 +1550,14 @@ 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;
 
 	if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
@@ -1565,7 +1565,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)
@@ -1600,7 +1600,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;
 
@@ -1608,7 +1608,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;
 
@@ -1725,7 +1725,7 @@ static int ata_eh_recover(struct ata_por
  out:
 	if (rc) {
 		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);
@@ -1812,7 +1812,7 @@ void ata_eh_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))
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index f5ded5b..6d9384a 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1356,16 +1356,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;
@@ -2348,7 +2348,7 @@ static unsigned int atapi_xlat(struct at
 static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
 {
 	if (likely(id == 0 || (id == 1 && ap->flags & ATA_FLAG_SLAVE_POSS)))
-		return &ap->device[id];
+		return &ap->link.device[id];
 	return NULL;
 }
 
@@ -2781,7 +2781,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)
@@ -2831,7 +2831,7 @@ int ata_scsi_offline_dev(struct ata_devi
  */
 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;
 
@@ -2911,14 +2911,14 @@ static int ata_scsi_user_scan(struct Scs
 	spin_lock_irqsave(&ap->host_set->lock, flags);
 
 	if (id == SCAN_WILD_CARD) {
-		ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
-		ap->eh_info.action |= ATA_EH_SOFTRESET;
+		ap->link.eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+		ap->link.eh_info.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->link.eh_info.probe_mask |= 1 << dev->devno;
+			ap->link.eh_info.action |= ATA_EH_SOFTRESET;
 		} else
 			rc = -EINVAL;
 	}
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index eb910e4..f771359 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -461,7 +461,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;
@@ -486,7 +486,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 4e6388f..af4b1f8 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -1413,7 +1413,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);
@@ -1922,7 +1922,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;
@@ -2029,7 +2029,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 2a840f5..58e5658 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -283,7 +283,7 @@ static irqreturn_t nv_interrupt (int irq
 		    !(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
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 9c70018..6f598ea 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -432,7 +432,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:
@@ -539,7 +539,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 3fc1003..fe2a6cf 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -400,7 +400,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 */
@@ -433,7 +433,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 59c49d3..84756af 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -285,7 +285,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)
@@ -339,7 +339,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 || !qc || qc->tf.ctl & ATA_NIEN))
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 8bbcf69..6e0b74b 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -735,7 +735,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;
 
@@ -794,7 +794,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_read_tf(ap, sil24_tag(qc->tag), &qc->result_tf);
 			qc->err_mask |= err_mask;
@@ -838,7 +838,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);
@@ -848,7 +848,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)
@@ -890,7 +890,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 fb69fc2..6432cf0 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -837,7 +837,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);
@@ -864,7 +864,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 d51c8d6..96700ec 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 db9e84c..fbb3f4c 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -417,7 +417,7 @@ struct ata_ering {
 	struct ata_ering_entry	name_entries[size];
 
 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 */
@@ -468,6 +468,24 @@ 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		flags;		/* ATA_LFLAG_* */
+	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;
@@ -490,22 +508,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;
@@ -782,8 +791,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
@@ -984,7 +996,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.2.4



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

* [PATCHSET 09/11] implement ata_link
@ 2006-05-11 16:30 Tejun Heo
  2006-05-11 16:30 ` [PATCH 01/14] libata-link: add PM related ATA constants Tejun Heo
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide,
	htejun

Hellooo.

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

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

#01   : prep
#02-03: implement ata_link
#04-06: make parts of libata deal with link instead of port
#07-09: misc link stuff (link init, reset_tries, ata_link_abort())
#10-14: add ap->pm_link[] and update parts of 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.

This patchset is against

  upstream (acc696d93dcf993dec123d69d599979e1456ffec)
  + [1] prep-for-new-EH patchset
  + [2] new-EH-framework patchset, take 3
  + [3] new-EH-implementation patchset, take 3
  + [4] merge-irq-pio patchset
  + [5] add-NCQ-support patchset, take 3
  + [6] prep-for-hotplug support, take 2
  + [7] prep-LLDDs-for-hotplug-support, take 1
  + [8] add-hotplug-support, take 2

--
tejun

[T] http://article.gmane.org/gmane.linux.ide/9957
[1] http://article.gmane.org/gmane.linux.ide/9959
[2] http://article.gmane.org/gmane.linux.ide/9984
[3] http://article.gmane.org/gmane.linux.ide/9995
[4] http://article.gmane.org/gmane.linux.ide/10005
[5] http://article.gmane.org/gmane.linux.ide/10011
[6] http://article.gmane.org/gmane.linux.ide/10028
[7] http://article.gmane.org/gmane.linux.ide/10063
[8] http://article.gmane.org/gmane.linux.ide/10073



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

* [PATCH 08/14] libata-link: implement link->reset_tries
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (4 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 09/14] libata-link: implement ata_link_abort() Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 13/14] libata-link: update EH to deal with PM links Tejun Heo
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

---

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

c7399562f682d7f2684a5f8fa95fc74583907031
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index de0f56f..11405a4 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5116,6 +5116,7 @@ static void ata_link_init(struct ata_por
 	link->pmp = pmp;
 	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 06e6523..97a1b4d 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1375,7 +1375,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 = !(link->ap->flags & ATA_FLAG_LOADING);
 	unsigned int action;
 	ata_reset_fn_t reset;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 61fddbf..8feaf04 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -479,6 +479,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.2.4



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

* [PATCH 03/14] libata-link: implement and use link/device iterators
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (2 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 12/14] libata-link: update ata_dev_configure() to deal with PM links Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 09/14] libata-link: implement ata_link_abort() Tejun Heo
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, 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.

---

 drivers/scsi/libata-core.c |   71 +++++++++++++++++++------------------------
 drivers/scsi/libata-eh.c   |   72 +++++++++++++++++++++-----------------------
 drivers/scsi/libata-scsi.c |   10 +++---
 include/linux/libata.h     |   22 +++++++++++++
 4 files changed, 93 insertions(+), 82 deletions(-)

c3d11a19666ed32115710146ec33e24cb9336b7e
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index e132e47..501a752 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1313,8 +1313,9 @@ int ata_dev_configure(struct ata_device 
 {
 	struct ata_port *ap = dev->link->ap;
 	const u16 *id = dev->id;
+	struct ata_device *tdev;
 	unsigned int xfer_mask;
-	int i, rc;
+	int rc;
 
 	if (!ata_dev_enabled(dev)) {
 		DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
@@ -1435,10 +1436,11 @@ int ata_dev_configure(struct ata_device 
 	}
 
 	ap->host->max_cmd_len = 0;
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
+	ata_link_for_each_dev(tdev, dev->link) {
 		ap->host->max_cmd_len = max_t(unsigned int,
 					      ap->host->max_cmd_len,
-					      ap->link.device[i].cdb_len);
+					      tdev->cdb_len);
+	}
 
 	/* limit bridge transfers to udma5, 200 sectors */
 	if (ata_dev_knobble(dev)) {
@@ -1479,13 +1481,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;
@@ -1493,9 +1495,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;
@@ -1508,11 +1508,9 @@ static int ata_bus_probe(struct ata_port
 	ata_port_probe(ap);
 
 	/* 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;
@@ -1533,9 +1531,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);
@@ -2077,16 +2076,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_enabled(&ap->link.device[i])) {
+		ata_link_for_each_dev(dev, link) {
+			if (ata_dev_enabled(dev)) {
 				ap->ops->set_mode(ap);
 				break;
 			}
@@ -2095,11 +2095,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;
 
@@ -2118,8 +2116,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;
 
@@ -2136,9 +2133,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;
 
@@ -2149,9 +2144,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) {
 		if (!ata_dev_enabled(dev))
 			continue;
 
@@ -2947,8 +2940,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);
@@ -2959,10 +2952,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;
 
@@ -5143,7 +5134,7 @@ static void ata_host_init(struct ata_por
 
 	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;
@@ -5330,7 +5321,7 @@ int ata_device_add(const struct ata_prob
 			spin_lock_irqsave(&ap->host_set->lock, flags);
 
 			ap->link.eh_info.probe_mask =
-				(1 << ATA_MAX_DEVICES) - 1;
+				(1 << ata_link_max_devices(&ap->link)) - 1;
 			ap->link.eh_info.action |= ATA_EH_SOFTRESET;
 
 			set_bit(bit, &ap->flags);
@@ -5396,7 +5387,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;
@@ -5405,8 +5396,8 @@ void ata_port_detach(struct ata_port *ap
 	spin_lock_irqsave(&ap->host_set->lock, flags);
 
 	ap->flags |= ATA_FLAG_UNLOADING;
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ap->link.device[i].flags |= ATA_DFLAG_DETACH;
+	ata_link_for_each_dev(dev, &ap->link)
+		dev->flags |= ATA_DFLAG_DETACH;
 
 	ata_port_schedule_eh(ap);
 
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index cde769f..4026886 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1326,10 +1326,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)
@@ -1339,14 +1340,14 @@ 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;
 }
@@ -1373,7 +1374,7 @@ static int ata_eh_reset(struct ata_port 
 	int verbose = !(ap->flags & ATA_FLAG_LOADING);
 	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 it to determine what kind of
@@ -1397,8 +1398,9 @@ static int ata_eh_reset(struct ata_port 
 		 * -ENODEV.
 		 */
 		if (rc == -ENODEV) {
-			for (i = 0; i < ATA_MAX_DEVICES; i++)
-				classes[i] = ATA_DEV_NONE;
+			struct ata_device *dev;
+			ata_link_for_each_dev(dev, &ap->link)
+				classes[dev->devno] = ATA_DEV_NONE;
 			return 0;
 		}
 
@@ -1487,13 +1489,11 @@ 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++) {
-		dev = &ap->link.device[i];
-
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) &&
 		    (!ehc->i.dev || ehc->i.dev == dev)) {
 			if (ata_port_offline(ap)) {
@@ -1537,20 +1537,22 @@ static int ata_eh_revalidate_and_attach(
 
 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;
 }
@@ -1558,15 +1560,13 @@ 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;
 
 	if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
 		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;
@@ -1602,14 +1602,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 */
@@ -1634,8 +1632,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) {
@@ -1724,8 +1722,8 @@ static int ata_eh_recover(struct ata_por
 
  out:
 	if (rc) {
-		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);
@@ -1790,7 +1788,8 @@ void ata_eh_scsi_hotplug(void *data)
 {
 	struct ata_port *ap = data;
 	unsigned long timeout;
-	int i, requeue = 0;
+	struct ata_device *dev;
+	int requeue = 0;
 
 	DPRINTK("ENTER\n");
 
@@ -1811,8 +1810,7 @@ void ata_eh_scsi_hotplug(void *data)
 		requeue = 1;
 
 	/* 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))
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 6d9384a..facde9e 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2775,19 +2775,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);
@@ -2911,7 +2910,8 @@ static int ata_scsi_user_scan(struct Scs
 	spin_lock_irqsave(&ap->host_set->lock, flags);
 
 	if (id == SCAN_WILD_CARD) {
-		ap->link.eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+		ap->link.eh_info.probe_mask |=
+			(1 << ata_link_max_devices(&ap->link)) - 1;
 		ap->link.eh_info.action |= ATA_EH_SOFTRESET;
 	} else {
 		struct ata_device *dev = ata_find_dev(ap, id);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index fbb3f4c..c7c904f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -861,6 +861,9 @@ static inline unsigned int ata_tag_inter
 	return tag == ATA_MAX_QUEUE - 1;
 }
 
+/*
+ * device helpers
+ */
 static inline unsigned int ata_class_enabled(unsigned int class)
 {
 	return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
@@ -891,6 +894,25 @@ static inline unsigned int ata_dev_absen
 	return ata_class_absent(dev->class);
 }
 
+/*
+ * link helpers
+ */
+static inline int ata_link_max_devices(const struct ata_link *link)
+{
+	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)
 {
 	return ap->ops->check_status(ap);
-- 
1.2.4



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

* [PATCH 06/14] libata-link: linkify config/EH related functions
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (11 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 10/14] libata-link: add PM links Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 14/14] libata-link: update hotplug to handle PM links Tejun Heo
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Make the following functions deal with ata_link instead of ata_port.

* ata_set_mode()
* ata_eh_analyze_ncq_error()
* ata_eh_analyze_serror()
* ata_eh_autopsy()
* ata_eh_report()
* ata_eh_attach_and_revalidate()

---

 drivers/scsi/libata-core.c |   13 +++--
 drivers/scsi/libata-eh.c   |  113 +++++++++++++++++++++++---------------------
 drivers/scsi/libata.h      |    3 +
 3 files changed, 68 insertions(+), 61 deletions(-)

222e799fb2ba9ac4c8e0437d5418d6a89fa515b9
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 6dc370f..dd40909 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1525,7 +1525,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;
@@ -2062,7 +2062,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
@@ -2075,9 +2075,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;
 
@@ -4938,12 +4938,13 @@ static int ata_start_drive(struct ata_de
  */
 int ata_device_resume(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->link->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 
 	if (ap->flags & ATA_FLAG_SUSPENDED) {
 		struct ata_device *failed_dev;
 		ap->flags &= ~ATA_FLAG_SUSPENDED;
-		while (ata_set_mode(ap, &failed_dev))
+		while (ata_set_mode(link, &failed_dev))
 			ata_dev_disable(failed_dev);
 	}
 	if (!ata_dev_enabled(dev))
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 7e5a03a..06e6523 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -880,7 +880,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.
@@ -888,9 +888,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;
 
@@ -923,7 +923,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
@@ -933,10 +933,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;
@@ -946,7 +947,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? */
@@ -963,13 +964,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;
 	}
@@ -1169,18 +1170,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;
@@ -1195,12 +1196,12 @@ static void ata_eh_autopsy(struct ata_po
 	rc = ata_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)
@@ -1211,7 +1212,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 */
@@ -1260,16 +1261,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;
 
@@ -1280,7 +1282,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;
@@ -1298,23 +1300,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 "
@@ -1485,17 +1488,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) {
 		if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) &&
 		    (!ehc->i.dev || ehc->i.dev == dev)) {
 			if (ata_link_offline(dev->link)) {
@@ -1503,7 +1507,7 @@ static int ata_eh_revalidate_and_attach(
 				break;
 			}
 
-			ata_eh_about_to_do(&ap->link, ATA_EH_REVALIDATE);
+			ata_eh_about_to_do(link, ATA_EH_REVALIDATE);
 			rc = ata_dev_revalidate(dev,
 						ehc->flags & ATA_EHC_DID_RESET);
 			if (rc)
@@ -1537,38 +1541,38 @@ static int ata_eh_revalidate_and_attach(
 	return rc;
 }
 
-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;
 
-	if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+	if (link->ap->flags & ATA_FLAG_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;
@@ -1602,14 +1606,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 */
@@ -1631,17 +1636,17 @@ static int ata_eh_recover(struct ata_por
 	rc = 0;
 
 	/* 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(ap), prereset,
 				  softreset, hardreset, postreset);
 		if (rc) {
 			ata_port_printk(ap, KERN_ERR,
@@ -1653,13 +1658,13 @@ 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;
 
 	/* configure transfer mode if the port has been reset */
 	if (ehc->flags & ATA_EHC_DID_RESET) {
-		rc = ata_set_mode(ap, &dev);
+		rc = ata_set_mode(link, &dev);
 		if (rc) {
 			down_xfermask = 1;
 			goto dev_fail;
@@ -1677,7 +1682,7 @@ static int ata_eh_recover(struct ata_por
 		ehc->tries[dev->devno] = 0;
 		break;
 	case -EIO:
-		ata_down_sata_spd_limit(&ap->link);
+		ata_down_sata_spd_limit(link);
 	default:
 		ehc->tries[dev->devno]--;
 		if (down_xfermask &&
@@ -1690,7 +1695,7 @@ static int ata_eh_recover(struct ata_por
 		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 */
@@ -1711,7 +1716,7 @@ static int ata_eh_recover(struct ata_por
 			ehc->i.action |= ATA_EH_SOFTRESET;
 	}
 
-	if (ata_port_nr_enabled(ap)) {
+	if (ata_link_nr_enabled(ap)) {
 		ata_port_printk(ap, KERN_WARNING, "failed to recover some "
 				"devices, retrying in 5 secs\n");
 		ssleep(5);
@@ -1724,7 +1729,7 @@ static int ata_eh_recover(struct ata_por
 
  out:
 	if (rc) {
-		ata_link_for_each_dev(dev, &ap->link)
+		ata_link_for_each_dev(dev, link)
 			ata_dev_disable(dev);
 	}
 
@@ -1856,8 +1861,8 @@ void ata_do_eh(struct ata_port *ap, ata_
 	       ata_postreset_fn_t postreset)
 {
 	if (!(ap->flags & (ATA_FLAG_LOADING | ATA_FLAG_UNLOADING))) {
-		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);
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index bd2e399..f09c23e 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -56,7 +56,8 @@ extern int ata_dev_configure(struct ata_
 extern int ata_down_sata_spd_limit(struct ata_link *link);
 extern int ata_set_sata_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.2.4



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

* [PATCH 04/14] libata-link: linkify PHY-related functions
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (6 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 13/14] libata-link: update EH to deal with PM links Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 11/14] libata-link: update ata_scsi_error() to handle PM links Tejun Heo
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

* sata_print_link_status()
* ata_down_sata_spd_limit()
* ata_set_sata_spd_limit() and friends
* sata_link_debounce/resume()
* ata_scr_valid/read/write/write_flush()
* ata_link_on/offline()

This patch introduces no behavior change.

---

 drivers/scsi/ahci.c         |    6 +
 drivers/scsi/libata-bmdma.c |    2 
 drivers/scsi/libata-core.c  |  217 +++++++++++++++++++++++--------------------
 drivers/scsi/libata-eh.c    |   22 ++--
 drivers/scsi/libata.h       |    4 -
 drivers/scsi/sata_mv.c      |   14 +--
 drivers/scsi/sata_sil24.c   |   12 +-
 include/linux/libata.h      |   23 ++---
 8 files changed, 157 insertions(+), 143 deletions(-)

e99ffedfb16c0fae395568f367561a930118e4d1
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index e3b4fd5..d4420ac 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -587,7 +587,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;
@@ -661,7 +661,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";
@@ -690,7 +690,7 @@ static int ahci_hardreset(struct ata_por
 	rc = sata_std_hardreset(ap, class);
 	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 b3a4642..7805f79 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -778,7 +778,7 @@ void ata_bmdma_error_handler(struct ata_
 	ata_reset_fn_t hardreset;
 
 	hardreset = NULL;
-	if (ata_scr_valid(ap))
+	if (ata_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 501a752..9680359 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1548,7 +1548,7 @@ static int ata_bus_probe(struct ata_port
 		tries[dev->devno] = 0;
 		break;
 	case -EIO:
-		ata_down_sata_spd_limit(ap);
+		ata_down_sata_spd_limit(&ap->link);
 		/* fall through */
 	default:
 		tries[dev->devno]--;
@@ -1583,28 +1583,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 (ata_scr_read(ap, SCR_STATUS, &sstatus))
+	if (ata_scr_read(link, SCR_STATUS, &sstatus))
 		return;
-	ata_scr_read(ap, SCR_CONTROL, &scontrol);
+	ata_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);
 	}
@@ -1624,32 +1624,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 */
-		ata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+		ata_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 */
-	ata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+	ata_scr_write_flush(link, SCR_CONTROL, 0x300);
 
 	/* wait for phy to become ready, if necessary */
 	do {
 		msleep(200);
-		ata_scr_read(ap, SCR_STATUS, &sstatus);
+		ata_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);
@@ -1723,9 +1724,9 @@ void ata_port_disable(struct ata_port *a
 
 /**
  *	ata_down_sata_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 ata_set_sata_spd().
  *
@@ -1735,16 +1736,16 @@ void ata_port_disable(struct ata_port *a
  *	RETURNS:
  *	0 on success, negative errno on failure
  */
-int ata_down_sata_spd_limit(struct ata_port *ap)
+int ata_down_sata_spd_limit(struct ata_link *link)
 {
 	u32 sstatus, spd, mask;
 	int rc, highbit;
 
-	rc = ata_scr_read(ap, SCR_STATUS, &sstatus);
+	rc = ata_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;
@@ -1758,22 +1759,22 @@ int ata_down_sata_spd_limit(struct ata_p
 	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 __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __ata_set_sata_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);
@@ -1783,10 +1784,10 @@ static int __ata_set_sata_spd_needed(str
 
 /**
  *	ata_set_sata_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.
  *
@@ -1796,21 +1797,21 @@ static int __ata_set_sata_spd_needed(str
  *	RETURNS:
  *	1 if SATA spd configuration is needed, 0 otherwise.
  */
-int ata_set_sata_spd_needed(struct ata_port *ap)
+int ata_set_sata_spd_needed(struct ata_link *link)
 {
 	u32 scontrol;
 
-	if (ata_scr_read(ap, SCR_CONTROL, &scontrol))
+	if (ata_scr_read(link, SCR_CONTROL, &scontrol))
 		return 0;
 
-	return __ata_set_sata_spd_needed(ap, &scontrol);
+	return __ata_set_sata_spd_needed(link, &scontrol);
 }
 
 /**
  *	ata_set_sata_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.
@@ -1819,18 +1820,18 @@ int ata_set_sata_spd_needed(struct ata_p
  *	0 if spd doesn't need to be changed, 1 if spd has been
  *	changed.  Negative errno if SCR registers are inaccessible.
  */
-int ata_set_sata_spd(struct ata_port *ap)
+int ata_set_sata_spd(struct ata_link *link)
 {
 	u32 scontrol;
 	int rc;
 
-	if ((rc = ata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = ata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
-	if (!__ata_set_sata_spd_needed(ap, &scontrol))
+	if (!__ata_set_sata_spd_needed(link, &scontrol))
 		return 0;
 
-	if ((rc = ata_scr_write(ap, SCR_CONTROL, scontrol)))
+	if ((rc = ata_scr_write(link, SCR_CONTROL, scontrol)))
 		return rc;
 	return 1;
 }
@@ -2422,13 +2423,13 @@ 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
  *	@interval_msec: polling interval in millisecs
  *	@duration_msec: debounce duration in millisecs
  *	@timeout_msec: timeout in millisecs
  *
- *	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_msec
  *	polled every @interval_msec, before @timeout_msec.  Timeout
  *	constraints the beginning of the stable state.  Because, after
@@ -2442,8 +2443,8 @@ err_out:
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_debounce(struct ata_port *ap, unsigned long interval_msec,
-		      unsigned long duration_msec, unsigned long timeout_msec)
+int sata_link_debounce(struct ata_link *link, unsigned long interval_msec,
+		       unsigned long duration_msec, unsigned long timeout_msec)
 {
 	unsigned long duration = duration_msec * HZ / 1000;
 	unsigned long timeout = jiffies + timeout_msec * HZ / 1000;
@@ -2451,7 +2452,7 @@ int sata_phy_debounce(struct ata_port *a
 	u32 last, cur;
 	int rc;
 
-	if ((rc = ata_scr_read(ap, SCR_STATUS, &cur)))
+	if ((rc = ata_scr_read(link, SCR_STATUS, &cur)))
 		return rc;
 	cur &= 0xf;
 
@@ -2460,7 +2461,7 @@ int sata_phy_debounce(struct ata_port *a
 
 	while (1) {
 		msleep(interval_msec);
-		if ((rc = ata_scr_read(ap, SCR_STATUS, &cur)))
+		if ((rc = ata_scr_read(link, SCR_STATUS, &cur)))
 			return rc;
 		cur &= 0xf;
 
@@ -2484,10 +2485,10 @@ 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
  *
- *	Resume SATA phy of @ap and debounce it.
+ *	Resume SATA phy of @link and debounce it.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2495,27 +2496,27 @@ int sata_phy_debounce(struct ata_port *a
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_resume(struct ata_port *ap, int quick)
+int sata_link_resume(struct ata_link *link, int quick)
 {
 	u32 scontrol;
 	int rc;
 
-	if ((rc = ata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = ata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
 	scontrol = (scontrol & 0x0f0) | 0x300;
 
-	if ((rc = ata_scr_write(ap, SCR_CONTROL, scontrol)))
+	if ((rc = ata_scr_write(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	if (quick)
-		return sata_phy_debounce(ap, ATA_DEBOUNCE_QUICK_INTERVAL,
-					 ATA_DEBOUNCE_QUICK_DURATION,
-					 ATA_DEBOUNCE_QUICK_TIMEOUT);
+		return sata_link_debounce(link, ATA_DEBOUNCE_QUICK_INTERVAL,
+					  ATA_DEBOUNCE_QUICK_DURATION,
+					  ATA_DEBOUNCE_QUICK_TIMEOUT);
 	else
-		return sata_phy_debounce(ap, ATA_DEBOUNCE_INTERVAL,
-					 ATA_DEBOUNCE_DURATION,
-					 ATA_DEBOUNCE_TIMEOUT);
+		return sata_link_debounce(link, ATA_DEBOUNCE_INTERVAL,
+					  ATA_DEBOUNCE_DURATION,
+					  ATA_DEBOUNCE_TIMEOUT);
 }
 
 /**
@@ -2539,8 +2540,8 @@ int ata_std_prereset(struct ata_port *ap
 	if (ap->link.eh_context.i.action & ATA_EH_HARDRESET)
 		return 0;
 
-	/* resume port */
-	rc = sata_phy_resume(ap, boot_probe);
+	/* resume link */
+	rc = sata_link_resume(&ap->link, boot_probe);
 	if (rc && rc != -EOPNOTSUPP) {
 		/* phy resume failed, whine but continue */
 		ata_port_printk(ap, KERN_WARNING, "failed to resume link "
@@ -2553,7 +2554,7 @@ int ata_std_prereset(struct ata_port *ap
 	 * cases.  As we wait for !BSY after resets, this should be
 	 * safe.
 	 */
-	if (boot_probe && !ata_port_offline(ap))
+	if (boot_probe && !ata_link_offline(&ap->link))
 		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
 
 	return 0;
@@ -2580,7 +2581,7 @@ int ata_std_softreset(struct ata_port *a
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(&ap->link)) {
 		classes[0] = ATA_DEV_NONE;
 		goto out;
 	}
@@ -2628,35 +2629,36 @@ int ata_std_softreset(struct ata_port *a
  */
 int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
 {
+	struct ata_link *link = &ap->link;
 	u32 scontrol;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	if (ata_set_sata_spd_needed(ap)) {
+	if (ata_set_sata_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 = ata_scr_read(ap, SCR_CONTROL, &scontrol)))
+		if ((rc = ata_scr_read(link, SCR_CONTROL, &scontrol)))
 			return rc;
 
 		scontrol = (scontrol & 0x0f0) | 0x302;
 
-		if ((rc = ata_scr_write(ap, SCR_CONTROL, scontrol)))
+		if ((rc = ata_scr_write(link, SCR_CONTROL, scontrol)))
 			return rc;
 
-		ata_set_sata_spd(ap);
+		ata_set_sata_spd(link);
 	}
 
 	/* issue phy wake/reset */
-	if ((rc = ata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = ata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
 	scontrol = (scontrol & 0x0f0) | 0x301;
 
-	if ((rc = ata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+	if ((rc = ata_scr_write_flush(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -2665,17 +2667,17 @@ int sata_std_hardreset(struct ata_port *
 	msleep(1);
 
 	/* bring phy back */
-	sata_phy_resume(ap, 0);
+	sata_link_resume(link, 0);
 
 	/* 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;
 	}
 
 	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
-		ata_port_printk(ap, KERN_ERR,
+		ata_link_printk(link, KERN_ERR,
 				"COMRESET failed (device not ready)\n");
 		return -EIO;
 	}
@@ -2702,16 +2704,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 (ata_scr_read(ap, SCR_ERROR, &serror) == 0)
-		ata_scr_write(ap, SCR_ERROR, serror);
+	if (ata_scr_read(link, SCR_ERROR, &serror) == 0)
+		ata_scr_write(link, SCR_ERROR, serror);
 
 	/* re-enable interrupts */
 	if (!ap->ops->error_handler) {
@@ -4730,9 +4733,9 @@ irqreturn_t ata_interrupt (int irq, void
 
 /**
  *	ata_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.
@@ -4740,18 +4743,20 @@ irqreturn_t ata_interrupt (int irq, void
  *	RETURNS:
  *	1 if SCRs are accessible, 0 otherwise.
  */
-int ata_scr_valid(struct ata_port *ap)
+int ata_scr_valid(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
+
 	return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
 }
 
 /**
  *	ata_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.
  *
@@ -4761,9 +4766,11 @@ int ata_scr_valid(struct ata_port *ap)
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int ata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int ata_scr_read(struct ata_link *link, int reg, u32 *val)
 {
-	if (ata_scr_valid(ap)) {
+	struct ata_port *ap = link->ap;
+
+	if (ata_scr_valid(link)) {
 		*val = ap->ops->scr_read(ap, reg);
 		return 0;
 	}
@@ -4772,11 +4779,11 @@ int ata_scr_read(struct ata_port *ap, in
 
 /**
  *	ata_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.
  *
@@ -4786,9 +4793,11 @@ int ata_scr_read(struct ata_port *ap, in
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int ata_scr_write(struct ata_port *ap, int reg, u32 val)
+int ata_scr_write(struct ata_link *link, int reg, u32 val)
 {
-	if (ata_scr_valid(ap)) {
+	struct ata_port *ap = link->ap;
+
+	if (ata_scr_valid(link)) {
 		ap->ops->scr_write(ap, reg, val);
 		return 0;
 	}
@@ -4797,7 +4806,7 @@ int ata_scr_write(struct ata_port *ap, i
 
 /**
  *	ata_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
  *
@@ -4810,9 +4819,11 @@ int ata_scr_write(struct ata_port *ap, i
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int ata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int ata_scr_write_flush(struct ata_link *link, int reg, u32 val)
 {
-	if (ata_scr_valid(ap)) {
+	struct ata_port *ap = link->ap;
+
+	if (ata_scr_valid(link)) {
 		ap->ops->scr_write(ap, reg, val);
 		ap->ops->scr_read(ap, reg);
 		return 0;
@@ -4821,12 +4832,12 @@ int ata_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.
@@ -4834,22 +4845,22 @@ int ata_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 (!ata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+	if (!ata_scr_read(link, SCR_STATUS, &sstatus) && (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.
@@ -4857,11 +4868,11 @@ 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 (!ata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+	if (!ata_scr_read(link, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
 		return 1;
 	return 0;
 }
@@ -5296,7 +5307,7 @@ int ata_device_add(const struct ata_prob
 		ap = host_set->ports[i];
 
 		/* init sata_spd_limit to the current value */
-		if (ata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+		if (ata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) {
 			int spd = (scontrol >> 4) & 0xf;
 			ap->link.hw_sata_spd_limit &= (1 << spd) - 1;
 		}
@@ -5748,8 +5759,8 @@ EXPORT_SYMBOL_GPL(ata_set_sata_spd);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
-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(ata_std_prereset);
 EXPORT_SYMBOL_GPL(ata_std_softreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
@@ -5773,8 +5784,8 @@ EXPORT_SYMBOL_GPL(ata_scr_valid);
 EXPORT_SYMBOL_GPL(ata_scr_read);
 EXPORT_SYMBOL_GPL(ata_scr_write);
 EXPORT_SYMBOL_GPL(ata_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_id_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 4026886..7ade712 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1154,7 +1154,7 @@ static int ata_eh_speed_down(struct ata_
 		return 0;
 
 	/* speed down SATA link speed if possible */
-	if (ata_down_sata_spd_limit(dev->link->ap) == 0)
+	if (ata_down_sata_spd_limit(dev->link) == 0)
 		return ATA_EH_HARDRESET;
 
 	/* lower transfer mode */
@@ -1179,7 +1179,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;
@@ -1190,7 +1191,7 @@ static void ata_eh_autopsy(struct ata_po
 	DPRINTK("ENTER\n");
 
 	/* obtain and analyze SError */
-	rc = ata_scr_read(ap, SCR_ERROR, &serror);
+	rc = ata_scr_read(link, SCR_ERROR, &serror);
 	if (rc == 0) {
 		ehc->i.serror |= serror;
 		ata_eh_analyze_serror(ap);
@@ -1368,7 +1369,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 = !(ap->flags & ATA_FLAG_LOADING);
@@ -1382,7 +1384,7 @@ static int ata_eh_reset(struct ata_port 
 	 */
 	action = ehc->i.action;
 	ehc->i.action &= ~ATA_EH_RESET_MASK;
-	if (softreset && (!hardreset || (!ata_set_sata_spd_needed(ap) &&
+	if (softreset && (!hardreset || (!ata_set_sata_spd_needed(link) &&
 					 !(action & ATA_EH_HARDRESET)))) {
 		ehc->i.action |= ATA_EH_SOFTRESET;
 		reset = softreset;
@@ -1399,7 +1401,7 @@ static int ata_eh_reset(struct ata_port 
 		 */
 		if (rc == -ENODEV) {
 			struct ata_device *dev;
-			ata_link_for_each_dev(dev, &ap->link)
+			ata_link_for_each_dev(dev, link)
 				classes[dev->devno] = ATA_DEV_NONE;
 			return 0;
 		}
@@ -1464,7 +1466,7 @@ static int ata_eh_reset(struct ata_port 
 		ssleep(5);
 
 		if (reset == hardreset)
-			ata_down_sata_spd_limit(ap);
+			ata_down_sata_spd_limit(link);
 		if (hardreset)
 			reset = hardreset;
 		goto retry;
@@ -1496,7 +1498,7 @@ static int ata_eh_revalidate_and_attach(
 	ata_link_for_each_dev(dev, &ap->link) {
 		if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) &&
 		    (!ehc->i.dev || ehc->i.dev == dev)) {
-			if (ata_port_offline(ap)) {
+			if (ata_link_offline(dev->link)) {
 				rc = -EIO;
 				break;
 			}
@@ -1675,7 +1677,7 @@ static int ata_eh_recover(struct ata_por
 		ehc->tries[dev->devno] = 0;
 		break;
 	case -EIO:
-		ata_down_sata_spd_limit(ap);
+		ata_down_sata_spd_limit(&ap->link);
 	default:
 		ehc->tries[dev->devno]--;
 		if (down_xfermask &&
@@ -1688,7 +1690,7 @@ static int ata_eh_recover(struct ata_por
 		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 aee6552..bd2e399 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -53,8 +53,8 @@ extern unsigned ata_exec_internal(struct
 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 ata_down_sata_spd_limit(struct ata_port *ap);
-extern int ata_set_sata_spd_needed(struct ata_port *ap);
+extern int ata_down_sata_spd_limit(struct ata_link *link);
+extern int ata_set_sata_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 af4b1f8..1979fee 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) {
-		ata_scr_read(ap, SCR_ERROR, &serr);
-		ata_scr_write_flush(ap, SCR_ERROR, serr);
+		ata_scr_read(&ap->link, SCR_ERROR, &serr);
+		ata_scr_write_flush(&ap->link, SCR_ERROR, serr);
 	}
 	if (EDMA_ERR_SELF_DIS & edma_err_cause) {
 		struct mv_port_priv *pp	= ap->private_data;
@@ -1935,15 +1935,15 @@ static void __mv_phy_reset(struct ata_po
 
 	/* Issue COMRESET via SControl */
 comreset_retry:
-	ata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+	ata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
 	__msleep(1, can_sleep);
 
-	ata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+	ata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
 	__msleep(20, can_sleep);
 
 	timeout = jiffies + msecs_to_jiffies(200);
 	do {
-		ata_scr_read(ap, SCR_STATUS, &sstatus);
+		ata_scr_read(&ap->link, SCR_STATUS, &sstatus);
 		sstatus &= 0x3;
 		if ((sstatus == 3) || (sstatus == 0))
 			break;
@@ -1961,10 +1961,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 {
-		ata_scr_read(ap, SCR_STATUS, &sstatus);
+		ata_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 6e0b74b..51fceac 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -521,7 +521,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;
@@ -578,10 +578,10 @@ static int sil24_hardreset(struct ata_po
 	u32 tmp;
 
 	/* sil24 does the right thing(tm) without any protection */
-	ata_set_sata_spd(ap);
+	ata_set_sata_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);
@@ -591,15 +591,15 @@ static int sil24_hardreset(struct ata_po
 	/* SStatus oscillates between zero and valid status after
 	 * DEV_RST, debounce it.
 	 */
-	rc = sata_phy_debounce(ap, ATA_DEBOUNCE_INTERVAL,
-			       ATA_DEBOUNCE_DURATION, ATA_DEBOUNCE_TIMEOUT);
+	rc = sata_link_debounce(&ap->link, ATA_DEBOUNCE_INTERVAL,
+				ATA_DEBOUNCE_DURATION, ATA_DEBOUNCE_TIMEOUT);
 	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 c7c904f..67a9054 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -616,11 +616,12 @@ 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 ata_set_sata_spd(struct ata_port *ap);
-extern int sata_phy_debounce(struct ata_port *ap, unsigned long interval_msec,
-			     unsigned long duration_msec,
-			     unsigned long timeout_msec);
-extern int sata_phy_resume(struct ata_port *ap, int quick);
+extern int ata_set_sata_spd(struct ata_link *link);
+extern int sata_link_debounce(struct ata_link *link,
+			      unsigned long interval_msec,
+			      unsigned long duration_msec,
+			      unsigned long timeout_msec);
+extern int sata_link_resume(struct ata_link *link, int quick);
 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);
@@ -644,12 +645,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 ata_scr_valid(struct ata_port *ap);
-extern int ata_scr_read(struct ata_port *ap, int reg, u32 *val);
-extern int ata_scr_write(struct ata_port *ap, int reg, u32 val);
-extern int ata_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 ata_scr_valid(struct ata_link *link);
+extern int ata_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int ata_scr_write(struct ata_link *link, int reg, u32 val);
+extern int ata_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_device_resume(struct ata_device *);
-- 
1.2.4



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

* [PATCH 09/14] libata-link: implement ata_link_abort()
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (3 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 03/14] libata-link: implement and use link/device iterators Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 08/14] libata-link: implement link->reset_tries Tejun Heo
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Implement ata_link_abort().

---

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

77f07c1fd4a3c534664d3591e941489d20d51b85
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 11405a4..740e831 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5864,6 +5864,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 97a1b4d..1bd7d1e 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -453,19 +453,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;
 
@@ -474,7 +462,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++;
@@ -488,6 +476,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 8feaf04..f31c979 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -776,6 +776,7 @@ extern unsigned long ata_pci_default_fil
 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.2.4



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

* [PATCH 10/14] libata-link: add PM links
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (10 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 07/14] libata-link: separate out link initialization functions Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 06/14] libata-link: linkify config/EH related functions Tejun Heo
  2006-05-11 16:30 ` [PATCH 14/14] libata-link: update hotplug to handle PM links Tejun Heo
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Add link->pmp, ap->nr_pm_links, ap->pm_link[], and implement/update
printk helpers and iterators.

printk helpers are updated such that each component is identified as
follows.

if PM is not attached,

	port	'ataP:'
	link	'ataP:'
	dev	'ataP.DD:'

If PM is attached

	port	'ataP:'
	dev	'ataP.LL:'
	link	'ataP.LL'

ie. link and device are identified their PMP number.

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

---

 include/linux/libata.h |   52 ++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 46 insertions(+), 6 deletions(-)

1b7ba4a43a2a50e0732a8fbcfe99fc64ba2cdffe
diff --git a/include/linux/libata.h b/include/linux/libata.h
index f31c979..7db9b80 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -471,6 +471,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 */
@@ -519,6 +520,9 @@ struct ata_port {
 	struct ata_link		link;	/* host default link */
 	struct ata_device	__dev1;	/* storage for link.device[1] */
 
+	int			nr_pm_links;	/* nr of available PM links */
+	struct ata_link		*pm_link;	/* array of PM links */
+
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
 	struct device 		*dev;
@@ -796,11 +800,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_pm_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
@@ -902,15 +911,46 @@ static inline unsigned int ata_dev_absen
 /*
  * 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_pm_links)
+		return ap->pm_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_pm_links)
+			return NULL;
+		return ap->pm_link;
+	}
+
+	if (++link - ap->pm_link < ap->nr_pm_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.2.4



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

* [PATCH 12/14] libata-link: update ata_dev_configure() to deal with PM links
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
  2006-05-11 16:30 ` [PATCH 01/14] libata-link: add PM related ATA constants Tejun Heo
  2006-05-11 16:30 ` [PATCH 02/14] libata-link: introduce ata_link Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 03/14] libata-link: implement and use link/device iterators Tejun Heo
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Update ata_dev_configure() to deal with PM links.

---

 drivers/scsi/libata-core.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)

17a1cd83a17e3c44a2732ff2e77320f79b8565cd
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 740e831..32ea394 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1314,7 +1314,7 @@ int ata_dev_configure(struct ata_device 
 {
 	struct ata_port *ap = dev->link->ap;
 	const u16 *id = dev->id;
-	struct ata_device *tdev;
+	struct ata_link *tlink;
 	unsigned int xfer_mask;
 	int rc;
 
@@ -1437,10 +1437,13 @@ int ata_dev_configure(struct ata_device 
 	}
 
 	ap->host->max_cmd_len = 0;
-	ata_link_for_each_dev(tdev, dev->link) {
-		ap->host->max_cmd_len = max_t(unsigned int,
-					      ap->host->max_cmd_len,
-					      tdev->cdb_len);
+	ata_port_for_each_link(tlink, ap) {
+		struct ata_device *tdev;
+		ata_link_for_each_dev(tdev, tlink) {
+			ap->host->max_cmd_len = max_t(unsigned int,
+						      ap->host->max_cmd_len,
+						      tdev->cdb_len);
+		}
 	}
 
 	/* limit bridge transfers to udma5, 200 sectors */
-- 
1.2.4



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

* [PATCH 05/14] libata-link: linkify reset
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (8 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 11/14] libata-link: update ata_scsi_error() to handle PM links Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 07/14] libata-link: separate out link initialization functions Tejun Heo
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

* ata_eh_about_to_do()
* ata_do_reset()
* ata_eh_reset()
* all prereset/reset/postreset methods

This patch introduces no behavior change.

---

 drivers/scsi/ahci.c        |   31 ++++++++++++++++-----------
 drivers/scsi/ata_piix.c    |   14 +++++++-----
 drivers/scsi/libata-core.c |   36 +++++++++++++++++---------------
 drivers/scsi/libata-eh.c   |   50 ++++++++++++++++++++++----------------------
 drivers/scsi/sata_sil24.c  |   20 ++++++++++--------
 include/linux/libata.h     |   15 +++++++------
 6 files changed, 89 insertions(+), 77 deletions(-)

d3d6129dc940ccbb72c4bb834482456776342b84
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index d4420ac..3254cd2 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -562,19 +562,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);
@@ -587,7 +590,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;
@@ -617,7 +620,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 */
@@ -661,7 +664,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";
@@ -676,21 +679,22 @@ 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;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
 	ahci_stop_engine(ap);
-	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;
@@ -699,17 +703,18 @@ 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;
 	unsigned long flags;
 	u32 new_tmp, tmp;
 
-	ata_std_postreset(ap, class);
+	ata_std_postreset(link, class);
 
 	/* clear stored SError */
 	spin_lock_irqsave(&ap->host_set->lock, flags);
-	ap->link.eh_info.serror = 0;
+	link->eh_info.serror = 0;
 	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
 	/* Make sure port's ATAPI bit is set appropriately */
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 47d3fec..11c44ec 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -458,15 +458,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])) {
@@ -476,7 +477,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)
@@ -487,7 +488,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
@@ -500,8 +501,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;
@@ -547,7 +549,7 @@ static int piix_sata_prereset(struct ata
 		return -ENODEV;
 	}
 
-	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 9680359..6dc370f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2521,9 +2521,9 @@ int sata_link_resume(struct ata_link *li
 
 /**
  *	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)
@@ -2531,20 +2531,21 @@ int sata_link_resume(struct ata_link *li
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_prereset(struct ata_port *ap)
+int ata_std_prereset(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
 	int boot_probe = ap->flags & ATA_FLAG_LOADING;
 	int rc;
 
 	/* if we're about to do hardreset, don't bother */
-	if (ap->link.eh_context.i.action & ATA_EH_HARDRESET)
+	if (link->eh_context.i.action & ATA_EH_HARDRESET)
 		return 0;
 
 	/* resume link */
-	rc = sata_link_resume(&ap->link, boot_probe);
+	rc = sata_link_resume(link, boot_probe);
 	if (rc && rc != -EOPNOTSUPP) {
 		/* phy resume failed, whine but continue */
-		ata_port_printk(ap, KERN_WARNING, "failed to resume link "
+		ata_link_printk(link, KERN_WARNING, "failed to resume link "
 				"for reset (errno=%d)\n", rc);
 	}
 
@@ -2554,7 +2555,7 @@ int ata_std_prereset(struct ata_port *ap
 	 * cases.  As we wait for !BSY after resets, this should be
 	 * safe.
 	 */
-	if (boot_probe && !ata_link_offline(&ap->link))
+	if (boot_probe && !ata_link_offline(link))
 		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
 
 	return 0;
@@ -2562,7 +2563,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.
@@ -2573,15 +2574,16 @@ 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_port *ap = link->ap;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	unsigned int devmask = 0, err_mask;
 	u8 err;
 
 	DPRINTK("ENTER\n");
 
-	if (ata_link_offline(&ap->link)) {
+	if (ata_link_offline(link)) {
 		classes[0] = ATA_DEV_NONE;
 		goto out;
 	}
@@ -2599,7 +2601,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;
 	}
@@ -2616,7 +2618,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.
@@ -2627,9 +2629,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;
 	u32 scontrol;
 	int rc;
 
@@ -2692,7 +2694,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
@@ -2702,9 +2704,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 7ade712..7e5a03a 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -673,22 +673,23 @@ 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
  *	@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
+ *	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, unsigned int action)
+static void ata_eh_about_to_do(struct ata_link *link, unsigned int action)
 {
+	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ap->host_set->lock, flags);
-	ap->link.eh_info.action &= ~action;
+	link->eh_info.action &= ~action;
 	ap->flags |= ATA_FLAG_RECOVERED;
 	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 }
@@ -1324,16 +1325,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;
 
@@ -1341,12 +1342,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;
 
@@ -1365,15 +1366,14 @@ 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;
-	int verbose = !(ap->flags & ATA_FLAG_LOADING);
+	int verbose = !(link->ap->flags & ATA_FLAG_LOADING);
 	unsigned int action;
 	ata_reset_fn_t reset;
 	int did_followup_srst, rc;
@@ -1394,7 +1394,7 @@ static int ata_eh_reset(struct ata_port 
 	}
 
 	if (prereset) {
-		rc = prereset(ap);
+		rc = prereset(link);
 
 		/* prereset can short-circuit resetting by returning
 		 * -ENODEV.
@@ -1407,7 +1407,7 @@ static int ata_eh_reset(struct ata_port 
 		}
 
 		if (rc) {
-			ata_port_printk(ap, KERN_ERR,
+			ata_link_printk(link, KERN_ERR,
 					"prereset failed (errno=%d)\n", rc);
 			return rc;
 		}
@@ -1416,14 +1416,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(ap, ATA_EH_RESET_MASK);
+	ata_eh_about_to_do(link, ATA_EH_RESET_MASK);
 	ehc->flags |= ATA_EHC_DID_RESET;
 
-	rc = ata_do_reset(ap, reset, classes);
+	rc = ata_do_reset(link, reset, classes);
 
 	did_followup_srst = 0;
 	if (reset == hardreset &&
@@ -1433,18 +1433,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(ap, ATA_EH_RESET_MASK);
-		rc = ata_do_reset(ap, reset, classes);
+		ata_eh_about_to_do(link, ATA_EH_RESET_MASK);
+		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;
 		}
@@ -1461,7 +1461,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);
 
@@ -1474,7 +1474,7 @@ static int ata_eh_reset(struct ata_port 
 
 	if (rc == 0) {
 		if (postreset)
-			postreset(ap, classes);
+			postreset(link, classes);
 
 		/* reset successful, schedule revalidation */
 		ehc->i.dev = NULL;
@@ -1503,7 +1503,7 @@ static int ata_eh_revalidate_and_attach(
 				break;
 			}
 
-			ata_eh_about_to_do(ap, ATA_EH_REVALIDATE);
+			ata_eh_about_to_do(&ap->link, ATA_EH_REVALIDATE);
 			rc = ata_dev_revalidate(dev,
 						ehc->flags & ATA_EHC_DID_RESET);
 			if (rc)
@@ -1641,7 +1641,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_sil24.c b/drivers/scsi/sata_sil24.c
index 51fceac..103e5d3 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -509,8 +509,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;
@@ -521,7 +522,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;
@@ -566,22 +567,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 */
-	ata_set_sata_spd(&ap->link);
+	ata_set_sata_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);
@@ -591,7 +593,7 @@ 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, ATA_DEBOUNCE_INTERVAL,
+	rc = sata_link_debounce(link, ATA_DEBOUNCE_INTERVAL,
 				ATA_DEBOUNCE_DURATION, ATA_DEBOUNCE_TIMEOUT);
 	if (rc) {
 		reason = "PHY debouncing failed";
@@ -599,7 +601,7 @@ static int sil24_hardreset(struct ata_po
 	}
 
 	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;
@@ -614,7 +616,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 67a9054..61fddbf 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -292,13 +292,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;
@@ -622,10 +623,10 @@ extern int sata_link_debounce(struct ata
 			      unsigned long duration_msec,
 			      unsigned long timeout_msec);
 extern int sata_link_resume(struct ata_link *link, int quick);
-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 int ata_dev_revalidate(struct ata_device *dev, int post_reset);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
-- 
1.2.4



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

* [PATCH 13/14] libata-link: update EH to deal with PM links
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (5 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 08/14] libata-link: implement link->reset_tries Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 04/14] libata-link: linkify PHY-related functions Tejun Heo
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Update ata_eh_autopsy(), ata_eh_report() and ata_eh_recover() to deal
with PM 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 PM links if PM 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 PM EH later.

---

 drivers/scsi/libata-eh.c |  192 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 135 insertions(+), 57 deletions(-)

e76a448cb0f33855cd17ee65f4a5f5b83e6962af
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 8e89379..24b5dc8 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1196,8 +1196,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_*
@@ -1206,7 +1206,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;
@@ -1287,7 +1287,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.
@@ -1295,7 +1313,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;
@@ -1355,6 +1373,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)
 {
@@ -1615,12 +1650,13 @@ static int ata_eh_skip_recovery(struct a
  *	@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:
@@ -1631,71 +1667,106 @@ static int ata_eh_skip_recovery(struct a
  */
 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_eh_context *ehc;
 	struct ata_device *dev;
-	int down_xfermask, rc;
+	int down_xfermask, 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) {
+		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;
+	reset = 0;
 
-	/* skip EH if possible. */
-	if (ata_eh_skip_recovery(link))
-		ehc->i.action = 0;
+	/* do we need to reset? */
+	ata_port_for_each_link(link, ap) {
+		ehc = &link->eh_context;
 
-	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;
+
+		if (ehc->i.action & ATA_EH_RESET_MASK)
+			reset = 1;
+	}
+
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			ehc = &link->eh_context;
+			ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+		}
+	}
 
 	/* reset */
-	if (ehc->i.action & ATA_EH_RESET_MASK) {
-		ata_eh_freeze_port(ap);
+	if (reset) {
+		__ata_port_freeze(ap);
 
-		rc = ata_eh_reset(link, ata_link_nr_vacant(ap), prereset,
-				  softreset, hardreset, postreset);
-		if (rc) {
-			ata_port_printk(ap, KERN_ERR,
-					"reset failed, giving up\n");
-			goto out;
+		ata_port_for_each_link(link, ap) {
+			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;
-
-	/* configure transfer mode if the port has been reset */
-	if (ehc->flags & ATA_EHC_DID_RESET) {
-		rc = ata_set_mode(link, &dev);
-		if (rc) {
-			down_xfermask = 1;
+	/* the rest */
+	ata_port_for_each_link(link, ap) {
+		ehc = &link->eh_context;
+
+		/* 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->flags & ATA_EHC_DID_RESET) {
+			rc = ata_set_mode(link, &dev);
+			if (rc) {
+				down_xfermask = 1;
+				goto dev_fail;
+			}
 		}
+
+		/* this link is okay now */
+		ehc->flags &= ~ATA_EHC_DID_RESET;
+		ehc->i.action = 0;
 	}
 
 	goto out;
@@ -1718,7 +1789,7 @@ static int ata_eh_recover(struct ata_por
 	}
 
 	if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
-		/* disable device if it has used up all its chances */
+		/* the device has used all its chances, disable */
 		ata_dev_disable(dev);
 
 		/* detach if offline */
@@ -1743,8 +1814,8 @@ static int ata_eh_recover(struct ata_por
 			ehc->i.action |= ATA_EH_SOFTRESET;
 	}
 
-	if (ata_link_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 {
@@ -1755,10 +1826,8 @@ static int ata_eh_recover(struct ata_por
 	goto retry;
 
  out:
-	if (rc) {
-		ata_link_for_each_dev(dev, link)
-			ata_dev_disable(dev);
-	}
+	if (rc && r_failed_link)
+		*r_failed_link = link;
 
 	DPRINTK("EXIT, rc=%d\n", rc);
 	return rc;
@@ -1887,11 +1956,20 @@ void ata_do_eh(struct ata_port *ap, ata_
 	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 {
+	struct ata_device *dev;
+	int rc;
+
 	if (!(ap->flags & (ATA_FLAG_LOADING | ATA_FLAG_UNLOADING))) {
-		ata_eh_autopsy(&ap->link);
-		ata_eh_report(&ap->link);
+		ata_eh_autopsy(ap);
+		ata_eh_report(ap);
+	}
+
+	rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+			    NULL);
+	if (rc) {
+		ata_link_for_each_dev(dev, &ap->link)
+			ata_dev_disable(dev);
 	}
 
-	ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
 	ata_eh_finish(ap);
 }
-- 
1.2.4



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

* [PATCH 11/14] libata-link: update ata_scsi_error() to handle PM links
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (7 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 04/14] libata-link: linkify PHY-related functions Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 05/14] libata-link: linkify reset Tejun Heo
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

---

 drivers/scsi/libata-eh.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

48be52e2b9a5f5ec81af8e3da1e784a63f1cde47
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 1bd7d1e..8e89379 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -235,13 +235,17 @@ void ata_scsi_error(struct Scsi_Host *ho
  repeat:
 	/* invoke error handler */
 	if (ap->ops->error_handler) {
+		struct ata_link *link;
+
 		/* fetch & clear EH info */
 		spin_lock_irqsave(hs_lock, flags);
 
-		memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context));
-		if (!(ap->flags & ATA_FLAG_UNLOADING))
-			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));
+			if (!(ap->flags & ATA_FLAG_UNLOADING))
+				link->eh_context.i = link->eh_info;
+			memset(&link->eh_info, 0, sizeof(link->eh_info));
+		}
 
 		ap->flags &= ~ATA_FLAG_EH_PENDING;
 
@@ -269,7 +273,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 hs_lock such
 		 * that if exception occurs after this point but
-- 
1.2.4



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

* [PATCH 07/14] libata-link: separate out link initialization functions
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (9 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 05/14] libata-link: linkify reset Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  2006-05-11 16:30 ` [PATCH 10/14] libata-link: add PM links Tejun Heo
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

---

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

b1520dbca5c449c69ccb6eb54a6449801d044b87
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index dd40909..de0f56f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -65,6 +65,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 ata_link_init_sata_spd_limit(struct ata_link *link);
 
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
@@ -5094,6 +5095,68 @@ 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, int pmp)
+{
+	struct ata_device *dev;
+
+	/* clear everything except for devices */
+	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;
+
+	ata_link_for_each_dev(dev, link) {
+		dev->link = link;
+		dev->devno = dev - link->device;
+		ata_dev_init(dev);
+	}
+}
+
+/**
+ *	ata_link_init_sata_spd_limit - Initialize link->sata_spd_limit
+ *	@link: Link to configure sata_spd_limit for
+ *
+ *	Initialize @link->[orig_]sata_spd_limit to the currently
+ *	configured value.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int ata_link_init_sata_spd_limit(struct ata_link *link)
+{
+
+	u32 scontrol, spd;
+	int rc;
+
+	rc = ata_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
@@ -5111,8 +5174,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;
@@ -5133,8 +5194,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;
 
 	INIT_WORK(&ap->port_task, NULL, NULL);
@@ -5146,14 +5205,7 @@ static void ata_host_init(struct ata_por
 	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, 0);
 
 #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
@@ -5304,17 +5356,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 (ata_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;
+		ata_link_init_sata_spd_limit(&ap->link);
 
 		rc = scsi_add_host(ap->host, dev);
 		if (rc) {
-- 
1.2.4



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

* [PATCH 14/14] libata-link: update hotplug to handle PM links
  2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
                   ` (12 preceding siblings ...)
  2006-05-11 16:30 ` [PATCH 06/14] libata-link: linkify config/EH related functions Tejun Heo
@ 2006-05-11 16:30 ` Tejun Heo
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-05-11 16:30 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

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

---

 drivers/scsi/libata-eh.c   |   43 +++++++++++++++++++++++++--------------
 drivers/scsi/libata-scsi.c |   49 +++++++++++++++++++++++++++++++-------------
 2 files changed, 62 insertions(+), 30 deletions(-)

314e603ad221c11cea7e123706d8c4c492466ab0
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 24b5dc8..ecfb9c5 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1875,6 +1875,25 @@ static void ata_eh_finish(struct ata_por
 	}
 }
 
+static void ata_eh_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->host_set->lock, flags);
+		dev->flags &= ~ATA_DFLAG_DETACHED;
+		spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+		ata_scsi_remove_dev(dev);
+	}
+}
+
 /**
  *	ata_eh_scsi_hotplug - SCSI part of hotplug
  *	@data: Pointer to ATA port to perform SCSI hotplug on
@@ -1891,8 +1910,7 @@ void ata_eh_scsi_hotplug(void *data)
 {
 	struct ata_port *ap = data;
 	unsigned long timeout;
-	struct ata_device *dev;
-	int requeue = 0;
+	int i, requeue = 0;
 
 	DPRINTK("ENTER\n");
 
@@ -1912,19 +1930,14 @@ void ata_eh_scsi_hotplug(void *data)
 	if (scsi_host_in_recovery(ap->host))
 		requeue = 1;
 
-	/* 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->host_set->lock, flags);
-		dev->flags &= ~ATA_DFLAG_DETACHED;
-		spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
-		ata_scsi_remove_dev(dev);
-	}
+	/* Unplug detached devices.  We cannot use link iterator here
+	 * because PM links have to be scanned even if PM is currently
+	 * not attached.  Iterate manually.
+	 */
+	ata_eh_scsi_handle_link_detach(&ap->link);
+	if (ap->pm_link)
+		for (i = 0; i < ATA_PM_MAX_PORTS; i++)
+			ata_eh_scsi_handle_link_detach(&ap->pm_link[i]);
 
 	/* scan for new ones */
 	ata_scsi_scan_host(ap);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index facde9e..021e4a3 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2347,8 +2347,14 @@ static unsigned int atapi_xlat(struct at
 
 static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
 {
-	if (likely(id == 0 || (id == 1 && ap->flags & ATA_FLAG_SLAVE_POSS)))
-		return &ap->link.device[id];
+	if (ap->nr_pm_links == 0) {
+		if (likely(id < ata_link_max_devices(&ap->link)))
+			return &ap->link.device[id];
+	} else {
+		if (likely(id < ap->nr_pm_links))
+			return &ap->pm_link[id].device[0];
+	}
+
 	return NULL;
 }
 
@@ -2775,21 +2781,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;
 
-		sdev = __scsi_add_device(ap->host, 0, dev->devno, 0, NULL);
-		if (!IS_ERR(sdev)) {
-			dev->sdev = sdev;
-			scsi_device_put(sdev);
+			if (ata_is_host_link(link))
+				devno = dev->devno;
+			else
+				devno = link->pmp;
+
+			sdev = __scsi_add_device(ap->host, 0, devno, 0, NULL);
+			if (!IS_ERR(sdev)) {
+				dev->sdev = sdev;
+				scsi_device_put(sdev);
+			}
 		}
 	}
 }
@@ -2897,6 +2912,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_link *link;
 	unsigned long flags;
 	int rc = 0;
 
@@ -2910,15 +2926,18 @@ static int ata_scsi_user_scan(struct Scs
 	spin_lock_irqsave(&ap->host_set->lock, flags);
 
 	if (id == SCAN_WILD_CARD) {
-		ap->link.eh_info.probe_mask |=
-			(1 << ata_link_max_devices(&ap->link)) - 1;
-		ap->link.eh_info.action |= ATA_EH_SOFTRESET;
+		ata_port_for_each_link(link, ap) {
+			link->eh_info.probe_mask |=
+				(1 << ata_link_max_devices(link)) - 1;
+			link->eh_info.action |= ATA_EH_SOFTRESET;
+		}
 	} else {
 		struct ata_device *dev = ata_find_dev(ap, id);
 
 		if (dev) {
-			ap->link.eh_info.probe_mask |= 1 << dev->devno;
-			ap->link.eh_info.action |= ATA_EH_SOFTRESET;
+			link = dev->link;
+			link->eh_info.probe_mask |= 1 << dev->devno;
+			link->eh_info.action |= ATA_EH_SOFTRESET;
 		} else
 			rc = -EINVAL;
 	}
-- 
1.2.4



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

end of thread, other threads:[~2006-05-11 16:30 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-11 16:30 [PATCHSET 09/11] implement ata_link Tejun Heo
2006-05-11 16:30 ` [PATCH 01/14] libata-link: add PM related ATA constants Tejun Heo
2006-05-11 16:30 ` [PATCH 02/14] libata-link: introduce ata_link Tejun Heo
2006-05-11 16:30 ` [PATCH 12/14] libata-link: update ata_dev_configure() to deal with PM links Tejun Heo
2006-05-11 16:30 ` [PATCH 03/14] libata-link: implement and use link/device iterators Tejun Heo
2006-05-11 16:30 ` [PATCH 09/14] libata-link: implement ata_link_abort() Tejun Heo
2006-05-11 16:30 ` [PATCH 08/14] libata-link: implement link->reset_tries Tejun Heo
2006-05-11 16:30 ` [PATCH 13/14] libata-link: update EH to deal with PM links Tejun Heo
2006-05-11 16:30 ` [PATCH 04/14] libata-link: linkify PHY-related functions Tejun Heo
2006-05-11 16:30 ` [PATCH 11/14] libata-link: update ata_scsi_error() to handle PM links Tejun Heo
2006-05-11 16:30 ` [PATCH 05/14] libata-link: linkify reset Tejun Heo
2006-05-11 16:30 ` [PATCH 07/14] libata-link: separate out link initialization functions Tejun Heo
2006-05-11 16:30 ` [PATCH 10/14] libata-link: add PM links Tejun Heo
2006-05-11 16:30 ` [PATCH 06/14] libata-link: linkify config/EH related functions Tejun Heo
2006-05-11 16:30 ` [PATCH 14/14] libata-link: update hotplug to handle PM links Tejun Heo

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