linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/7] libata-pm-prep: separate out sata_link_hardreset()
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
                   ` (2 preceding siblings ...)
  2006-05-11 16:37 ` [PATCH 2/7] libata-pm-prep: make a number of functions global to libata Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  2006-05-11 16:37 ` [PATCH 7/7] libata-pm-prep: add HRST_TO_RESUME and implement resume action helpers Tejun Heo
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Separate out sata_link_hardreset() from sata_std_hardreset().  This
will be used by PM.

---

 drivers/scsi/libata-core.c |   54 ++++++++++++++++++++++++++++++++++----------
 drivers/scsi/libata.h      |    1 +
 2 files changed, 43 insertions(+), 12 deletions(-)

618a80782b3044ecbfff23f978aa0066942332d0
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d4e3b37..53b5ed0 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2620,11 +2620,10 @@ int ata_std_softreset(struct ata_link *l
 }
 
 /**
- *	sata_std_hardreset - reset host port via SATA phy reset
+ *	sata_link_hardreset - reset link via SATA phy reset
  *	@link: link to reset
- *	@class: resulting class of attached device
  *
- *	SATA phy-reset host port using DET bits of SControl register.
+ *	SATA phy-reset @link using DET bits of SControl register.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2632,11 +2631,10 @@ int ata_std_softreset(struct ata_link *l
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int sata_std_hardreset(struct ata_link *link, unsigned int *class)
+int sata_link_hardreset(struct ata_link *link)
 {
-	struct ata_port *ap = link->ap;
 	u32 scontrol;
-	int rc;
+	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
@@ -2647,24 +2645,24 @@ int sata_std_hardreset(struct ata_link *
 		 * and Sil3124.
 		 */
 		if ((rc = ata_scr_read(link, SCR_CONTROL, &scontrol)))
-			return rc;
+			goto out;
 
 		scontrol = (scontrol & 0x0f0) | 0x302;
 
 		if ((rc = ata_scr_write(link, SCR_CONTROL, scontrol)))
-			return rc;
+			goto out;
 
 		ata_set_sata_spd(link);
 	}
 
 	/* issue phy wake/reset */
 	if ((rc = ata_scr_read(link, SCR_CONTROL, &scontrol)))
-		return rc;
+		goto out;
 
 	scontrol = (scontrol & 0x0f0) | 0x301;
 
 	if ((rc = ata_scr_write_flush(link, SCR_CONTROL, scontrol)))
-		return rc;
+		goto out;
 
 	/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
 	 * 10.4.2 says at least 1 ms.
@@ -2672,9 +2670,41 @@ int sata_std_hardreset(struct ata_link *
 	msleep(1);
 
 	/* bring phy back */
-	sata_link_resume(link, 0);
+	rc = sata_link_resume(link, 0);
+ out:
+	if (rc)
+		ata_link_printk(link, KERN_ERR,
+				"COMRESET failed (errno=%d)\n", rc);
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+/**
+ *	sata_std_hardreset - reset host port via SATA phy reset
+ *	@link: link to reset
+ *	@class: resulting class of attached device
+ *
+ *	SATA phy-reset host port using DET bits of SControl register,
+ *	wait for !BSY and classify the attached device.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int sata_std_hardreset(struct ata_link *link, unsigned int *class)
+{
+	struct ata_port *ap = link->ap;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	/* do hardreset */
+	rc = sata_link_hardreset(link);
+	if (rc)
+		return rc;
 
-	/* TODO: phy layer with polling, timeouts, etc. */
 	if (ata_link_offline(link)) {
 		*class = ATA_DEV_NONE;
 		DPRINTK("EXIT, link offline\n");
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index e4d21aa..0f3cefe 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -54,6 +54,7 @@ extern int ata_dev_read_id(struct ata_de
 			   int post_reset, u16 *id);
 extern int ata_dev_configure(struct ata_device *dev, int print_info);
 extern void sata_print_link_status(struct ata_link *link);
+extern int sata_link_hardreset(struct ata_link *link);
 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);
-- 
1.2.4



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

* [PATCHSET 10/11] prep for PM support
@ 2006-05-11 16:37 Tejun Heo
  2006-05-11 16:37 ` [PATCH 1/7] libata-pm-prep: add @new_class to ata_dev_revalidate() Tejun Heo
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide,
	htejun

Howdy,

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

This is the first take of prep-for-PM-support patchset.  This patchset
contains 7 patches and implements various stuff needed for PM.

One of important updates is the addition of ops->qc_defer().  This is
to let LLDDs determine which commands they can accept at the moment.
This is necessary for PM and controllers have wildely different
capabilities regarding how many/different commands can be issued to
how many devices concurrently.  More info is in the message [T].

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
  + [9] implement-ata_link, take 1

--
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
[9] http://article.gmane.org/gmane.linux.ide/10106



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

* [PATCH 4/7] libata-pm-prep: add @is_cmd to ata_tf_to_fis()
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
  2006-05-11 16:37 ` [PATCH 1/7] libata-pm-prep: add @new_class to ata_dev_revalidate() Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  2006-05-11 16:37 ` [PATCH 2/7] libata-pm-prep: make a number of functions global to libata Tejun Heo
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Add @is_cmd to ata_tf_to_fis().  This controls bit 7 of the second
byte of the constructed FIS which tells the device whether it is for a
command or not.  This cleans up ahci a bit and will be used by PM.

---

 drivers/scsi/ahci.c        |    8 +++-----
 drivers/scsi/libata-core.c |   14 ++++++++------
 drivers/scsi/sata_qstor.c  |    2 +-
 drivers/scsi/sata_sil24.c  |    2 +-
 include/linux/libata.h     |    3 ++-
 5 files changed, 15 insertions(+), 14 deletions(-)

b3b89cc12158046907c50b2112e6bb4e87c5b8cc
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 3254cd2..526150b 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -628,8 +628,7 @@ static int ahci_softreset(struct ata_lin
 			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
 
 	tf.ctl |= ATA_SRST;
-	ata_tf_to_fis(&tf, fis, 0);
-	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
+	ata_tf_to_fis(&tf, 0, 0, fis);
 
 	writel(1, port_mmio + PORT_CMD_ISSUE);
 
@@ -647,8 +646,7 @@ static int ahci_softreset(struct ata_lin
 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
 
 	tf.ctl &= ~ATA_SRST;
-	ata_tf_to_fis(&tf, fis, 0);
-	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
+	ata_tf_to_fis(&tf, 0, 0, fis);
 
 	writel(1, port_mmio + PORT_CMD_ISSUE);
 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
@@ -787,7 +785,7 @@ static void ahci_qc_prep(struct ata_queu
 	 */
 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+	ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
 	if (is_atapi) {
 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 53b5ed0..b9feefb 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -92,8 +92,9 @@ MODULE_VERSION(DRV_VERSION);
 /**
  *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
  *	@tf: Taskfile to convert
- *	@fis: Buffer into which data will output
  *	@pmp: Port multiplier port
+ *	@is_cmd: This FIS is for command
+ *	@fis: Buffer into which data will output
  *
  *	Converts a standard ATA taskfile to a Serial ATA
  *	FIS structure (Register - Host to Device).
@@ -101,12 +102,13 @@ MODULE_VERSION(DRV_VERSION);
  *	LOCKING:
  *	Inherited from caller.
  */
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
 {
-	fis[0] = 0x27;	/* Register - Host to Device FIS */
-	fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
-					    bit 7 indicates Command FIS */
+	fis[0] = 0x27;			/* Register - Host to Device FIS */
+	fis[1] = pmp & 0xf;		/* Port multiplier number*/
+	if (is_cmd)
+		fis[1] |= (1 << 7);	/* bit 7 indicates Command FIS */
+
 	fis[2] = tf->command;
 	fis[3] = tf->feature;
 
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index fe2a6cf..d1877e0 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -335,7 +335,7 @@ static void qs_qc_prep(struct ata_queued
 	buf[28] = dflags;
 
 	/* frame information structure (FIS) */
-	ata_tf_to_fis(&qc->tf, &buf[32], 0);
+	ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
 }
 
 static inline void qs_packet_start(struct ata_queued_cmd *qc)
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 103e5d3..a952513 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -682,7 +682,7 @@ static void sil24_qc_prep(struct ata_que
 	}
 
 	prb->ctrl = cpu_to_le16(ctrl);
-	ata_tf_to_fis(&qc->tf, prb->fis, 0);
+	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
 
 	if (qc->flags & ATA_QCFLAG_DMAMAP)
 		sil24_fill_sg(qc, sge);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 1fec322..17a4af4 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -678,7 +678,8 @@ extern u32 ata_wait_register(void __iome
  */
 extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+			  u8 pmp, int is_cmd, u8 *fis);
 extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern u8 ata_noop_check_status(struct ata_port *ap);
 extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
-- 
1.2.4



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

* [PATCH 1/7] libata-pm-prep: add @new_class to ata_dev_revalidate()
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  2006-05-11 16:37 ` [PATCH 4/7] libata-pm-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Consider newly found class code while revalidating.  PM resetting
always results in valid class code and issuing PM commands to
ATA/ATAPI devices isn't a very attractive idea.  Add @new_class to
ata_dev_revalidate() and check class during revalidation.

---

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

e9ad06f7ef8413f1027baad8b64bc860b85fa85e
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 32ea394..71f9ea7 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2052,7 +2052,7 @@ static int ata_dev_set_mode(struct ata_d
 		return -EIO;
 	}
 
-	rc = ata_dev_revalidate(dev, 0);
+	rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
 	if (rc)
 		return rc;
 
@@ -2813,6 +2813,7 @@ static int ata_dev_same_device(struct at
 /**
  *	ata_dev_revalidate - Revalidate ATA device
  *	@dev: device to revalidate
+ *	@new_class: new class code
  *	@post_reset: is this revalidation after reset?
  *
  *	Re-read IDENTIFY page and make sure @dev is still attached to
@@ -2824,9 +2825,9 @@ static int ata_dev_same_device(struct at
  *	RETURNS:
  *	0 on success, negative errno otherwise
  */
-int ata_dev_revalidate(struct ata_device *dev, int post_reset)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+		       int post_reset)
 {
-	unsigned int class = dev->class;
 	u16 *id = (void *)dev->link->ap->sector_buf;
 	int rc;
 
@@ -2835,13 +2836,22 @@ int ata_dev_revalidate(struct ata_device
 		goto fail;
 	}
 
+	if (ata_class_enabled(new_class)) {
+		/* sometimes wrong class is reported, let it retry */
+		if (new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+			rc = -EIO;
+			goto fail;
+		}
+	} else
+		new_class = dev->class;
+
 	/* read ID data */
-	rc = ata_dev_read_id(dev, &class, post_reset, id);
+	rc = ata_dev_read_id(dev, &new_class, post_reset, id);
 	if (rc)
 		goto fail;
 
 	/* is the device still there? */
-	if (!ata_dev_same_device(dev, class, id)) {
+	if (!ata_dev_same_device(dev, new_class, id)) {
 		rc = -ENODEV;
 		goto fail;
 	}
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index ecfb9c5..7abeb11 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1570,7 +1570,7 @@ static int ata_eh_revalidate_and_attach(
 			}
 
 			ata_eh_about_to_do(link, ATA_EH_REVALIDATE);
-			rc = ata_dev_revalidate(dev,
+			rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
 						ehc->flags & ATA_EHC_DID_RESET);
 			if (rc)
 				break;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7db9b80..1fec322 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -633,7 +633,8 @@ extern int ata_std_prereset(struct ata_l
 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 int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+			      int post_reset);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
 #ifdef CONFIG_PCI
-- 
1.2.4



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

* [PATCH 2/7] libata-pm-prep: make a number of functions global to libata
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
  2006-05-11 16:37 ` [PATCH 1/7] libata-pm-prep: add @new_class to ata_dev_revalidate() Tejun Heo
  2006-05-11 16:37 ` [PATCH 4/7] libata-pm-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  2006-05-11 16:37 ` [PATCH 3/7] libata-pm-prep: separate out sata_link_hardreset() Tejun Heo
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Make a number of functions from libata-core.c and libata-eh.c global
to libata (drivers/scsi/libata.h).  These will be used by PM.

---

 drivers/scsi/libata-core.c |    7 +++----
 drivers/scsi/libata-eh.c   |   24 ++++++++++++------------
 drivers/scsi/libata.h      |   15 +++++++++++++++
 3 files changed, 30 insertions(+), 16 deletions(-)

9827f37046db8165d763573523d3cd864966a1be
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 71f9ea7..d4e3b37 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -65,7 +65,6 @@ 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;
@@ -1594,7 +1593,7 @@ void ata_port_probe(struct ata_port *ap)
  *	LOCKING:
  *	None.
  */
-static void sata_print_link_status(struct ata_link *link)
+void sata_print_link_status(struct ata_link *link)
 {
 	u32 sstatus, scontrol, tmp;
 
@@ -5118,7 +5117,7 @@ void ata_dev_init(struct ata_device *dev
  *	LOCKING:
  *	Kernel thread context (may sleep)
  */
-static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
 {
 	struct ata_device *dev;
 
@@ -5151,7 +5150,7 @@ static void ata_link_init(struct ata_por
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-static int ata_link_init_sata_spd_limit(struct ata_link *link)
+int ata_link_init_sata_spd_limit(struct ata_link *link)
 {
 
 	u32 scontrol, spd;
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 7abeb11..3764e21 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -679,7 +679,7 @@ void ata_eh_qc_retry(struct ata_queued_c
  *	LOCKING:
  *	None.
  */
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
 {
 	struct ata_port *ap = dev->link->ap;
 	unsigned long flags;
@@ -710,7 +710,7 @@ static void ata_eh_detach_dev(struct ata
  *	LOCKING:
  *	None.
  */
-static void ata_eh_about_to_do(struct ata_link *link, unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, unsigned int action)
 {
 	struct ata_port *ap = link->ap;
 	unsigned long flags;
@@ -1296,7 +1296,7 @@ static void ata_eh_link_autopsy(struct a
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_autopsy(struct ata_port *ap)
+void ata_eh_autopsy(struct ata_port *ap)
 {
 	struct ata_link *link;
 
@@ -1382,7 +1382,7 @@ static void ata_eh_link_report(struct at
  *	LOCKING:
  *	None.
  */
-static void ata_eh_report(struct ata_port *ap)
+void ata_eh_report(struct ata_port *ap)
 {
 	struct ata_link *link;
 
@@ -1431,9 +1431,9 @@ static int ata_eh_followup_srst_needed(i
 	return 0;
 }
 
-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)
+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_eh_context *ehc = &link->eh_context;
 	unsigned int *classes = ehc->classes;
@@ -1665,10 +1665,10 @@ static int ata_eh_skip_recovery(struct a
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-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,
-			  struct ata_link **r_failed_link)
+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,
+		   struct ata_link **r_failed_link)
 {
 	struct ata_link *link;
 	struct ata_eh_context *ehc;
@@ -1843,7 +1843,7 @@ static int ata_eh_recover(struct ata_por
  *	LOCKING:
  *	None.
  */
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
 {
 	int tag;
 
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index f09c23e..e4d21aa 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -53,6 +53,7 @@ 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 void sata_print_link_status(struct ata_link *link);
 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);
@@ -66,6 +67,8 @@ extern void ata_dev_select(struct ata_po
                            unsigned int wait, unsigned int can_sleep);
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
 extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int ata_link_init_sata_spd_limit(struct ata_link *link);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
 
@@ -111,6 +114,18 @@ extern void ata_ering_init(struct ata_er
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern 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);
+extern 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,
+			  struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
 extern void ata_eh_scsi_hotplug(void *data);
 
 #endif /* __LIBATA_H__ */
-- 
1.2.4



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

* [PATCH 6/7] libata-pm-prep: implement qc_defer helpers
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
                   ` (5 preceding siblings ...)
  2006-05-11 16:37 ` [PATCH 5/7] libata-pm-prep: implement ops->qc_defer() Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Implement ap->nr_active_links (the number of links with active qcs),
ap->excl_link (pointer to link which can be used by ->qc_defer and is
cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and
ata_link_active().

These can be used by ->qc_defer() to implement proper command
exclusion.  This set of helpers seem enough for both sil24 (ATAPI
exclusion needed) and cmd-switching PM.

---

 drivers/scsi/libata-core.c |   22 +++++++++++++++++++---
 drivers/scsi/libata-eh.c   |    5 +++++
 include/linux/libata.h     |    8 ++++++++
 3 files changed, 32 insertions(+), 3 deletions(-)

7deb1fc49ea4e26d9f1bc4258094086e0bcb27f2
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 5dd5a28..fb64a0f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -994,7 +994,6 @@ void ata_qc_complete_internal(struct ata
  *	LOCKING:
  *	None.  Should be called with kernel context, might sleep.
  */
-
 unsigned ata_exec_internal(struct ata_device *dev,
 			   struct ata_taskfile *tf, const u8 *cdb,
 			   int dma_dir, void *buf, unsigned int buflen)
@@ -1005,6 +1004,7 @@ unsigned ata_exec_internal(struct ata_de
 	struct ata_queued_cmd *qc;
 	unsigned int tag, preempted_tag;
 	u32 preempted_sactive, preempted_qc_active;
+	int preempted_nr_active_links;
 	DECLARE_COMPLETION(wait);
 	unsigned long flags;
 	unsigned int err_mask;
@@ -1043,9 +1043,11 @@ unsigned ata_exec_internal(struct ata_de
 	preempted_tag = link->active_tag;
 	preempted_sactive = link->sactive;
 	preempted_qc_active = ap->qc_active;
+	preempted_nr_active_links = ap->nr_active_links;
 	link->active_tag = ATA_TAG_POISON;
 	link->sactive = 0;
 	ap->qc_active = 0;
+	ap->nr_active_links = 0;
 
 	/* prepare & issue qc */
 	qc->tf = *tf;
@@ -1112,6 +1114,7 @@ unsigned ata_exec_internal(struct ata_de
 	link->active_tag = preempted_tag;
 	link->sactive = preempted_sactive;
 	ap->qc_active = preempted_qc_active;
+	ap->nr_active_links = preempted_nr_active_links;
 
 	/* XXX - Some LLDDs (sata_mv) disable port on command failure.
 	 * Until those drivers are fixed, we detect the condition
@@ -4327,10 +4330,18 @@ void __ata_qc_complete(struct ata_queued
 		ata_sg_clean(qc);
 
 	/* command should be marked inactive atomically with qc completion */
-	if (qc->tf.protocol == ATA_PROT_NCQ)
+	if (qc->tf.protocol == ATA_PROT_NCQ) {
 		link->sactive &= ~(1 << qc->tag);
-	else
+		if (!link->sactive)
+			ap->nr_active_links--;
+	} else {
 		link->active_tag = ATA_TAG_POISON;
+		ap->nr_active_links--;
+	}
+
+	/* clear exclusive status */
+	if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL))
+		ap->excl_link = NULL;
 
 	/* atapi: mark qc as inactive to prevent the interrupt handler
 	 * from completing the command twice later, before the error handler
@@ -4503,9 +4514,14 @@ void ata_qc_issue(struct ata_queued_cmd 
 
 	if (qc->tf.protocol == ATA_PROT_NCQ) {
 		WARN_ON(link->sactive & (1 << qc->tag));
+
+		if (!link->sactive)
+			ap->nr_active_links++;
 		link->sactive |= 1 << qc->tag;
 	} else {
 		WARN_ON(link->sactive);
+
+		ap->nr_active_links++;
 		link->active_tag = qc->tag;
 	}
 
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 3764e21..ffbd028 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -248,6 +248,7 @@ void ata_scsi_error(struct Scsi_Host *ho
 		}
 
 		ap->flags &= ~ATA_FLAG_EH_PENDING;
+		ap->excl_link = NULL;	/* don't maintain exclusion over EH */
 
 		spin_unlock_irqrestore(hs_lock, flags);
 
@@ -1873,6 +1874,10 @@ void ata_eh_finish(struct ata_port *ap)
 			}
 		}
 	}
+
+	/* make sure nr_active_links is zero after EH */
+	WARN_ON(ap->nr_active_links);
+	ap->nr_active_links = 0;
 }
 
 static void ata_eh_scsi_handle_link_detach(struct ata_link *link)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index a26b6a6..df78f3e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -181,6 +181,7 @@ enum {
 	ATA_QCFLAG_DMAMAP	= ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
 	ATA_QCFLAG_IO		= (1 << 3), /* standard IO command */
 	ATA_QCFLAG_RESULT_TF	= (1 << 4), /* result TF requested */
+	ATA_QCFLAG_CLEAR_EXCL	= (1 << 5), /* clear excl_link on completion */
 
 	ATA_QCFLAG_FAILED	= (1 << 16), /* cmd failed and is owned by EH */
 	ATA_QCFLAG_SENSE_VALID	= (1 << 17), /* sense data valid */
@@ -520,12 +521,14 @@ struct ata_port {
 	struct ata_queued_cmd	qcmd[ATA_MAX_QUEUE];
 	unsigned long		qc_allocated;
 	unsigned int		qc_active;
+	int			nr_active_links; /* #links with active qcs */
 
 	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_link		*excl_link;	/* for PM qc exclusion */
 
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
@@ -931,6 +934,11 @@ static inline int ata_link_max_devices(c
 	return 1;
 }
 
+static inline int ata_link_active(struct ata_link *link)
+{
+	return ata_tag_valid(link->active_tag) || link->sactive;
+}
+
 static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
 {
 	if (ap->nr_pm_links)
-- 
1.2.4



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

* [PATCH 5/7] libata-pm-prep: implement ops->qc_defer()
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
                   ` (4 preceding siblings ...)
  2006-05-11 16:37 ` [PATCH 7/7] libata-pm-prep: add HRST_TO_RESUME and implement resume action helpers Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  2006-05-11 16:37 ` [PATCH 6/7] libata-pm-prep: implement qc_defer helpers Tejun Heo
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Controllers which support PM have various restrictions on which
combinations of commands are allowed to what number of devices
concurrently.  This patch implements ops->qc_defer() which determines
whether a qc can be issued at the moment or should be deferred.

If the function returns ATA_DEFER_LINK, the qc will be deferred until
a qc completes on the link.  If ATA_DEFER_PORT, until a qc completes
on any link.  The defer types are advisory and in general
ATA_DEFER_LINK can simply be considered as having lower priority than
ATA_DEFER_PORT.

ops->qc_defer() replaces fixed ata_scmd_need_defer().  For standard
NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented.  ahci and
sata_sil24 are converted to use ata_std_qc_defer().

ops->qc_defer() is heavier than the original mechanism because full qc
is prepped before determining to defer it, but various information is
needed to determine defer conditinos and fully translating a qc is the
only way to supply such information in generic manner.

IMHO, this shouldn't cause any noticeable performance issues as

* for most cases deferring occurs rarely (except for NCQ-aware
  cmd-switching PM)
* translation itself isn't that expensive
* once deferred, the command won't be repeated until another command
  completes which usually is a very long time cpu-wise.

---

 drivers/scsi/ahci.c        |    1 +
 drivers/scsi/libata-core.c |   32 ++++++++++++++++++++++++++++
 drivers/scsi/libata-scsi.c |   50 +++++++++++---------------------------------
 drivers/scsi/sata_sil24.c  |    1 +
 include/linux/libata.h     |    6 +++++
 5 files changed, 52 insertions(+), 38 deletions(-)

6f73e35cbbea07d45cc5fb153d74c273517b5b57
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 526150b..c95309c 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -239,6 +239,7 @@ static const struct ata_port_operations 
 
 	.tf_read		= ahci_tf_read,
 
+	.qc_defer		= ata_std_qc_defer,
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index b9feefb..5dd5a28 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -3253,6 +3253,37 @@ int ata_check_atapi_dma(struct ata_queue
 
 	return rc;
 }
+
+/**
+ *	ata_std_qc_defer - Check whether a qc needs to be deferred
+ *	@qc: ATA command in question
+ *
+ *	Non-NCQ commands cannot run with any other command, NCQ or
+ *	not.  As upper layer only knows the queue depth, we are
+ *	responsible for maintaining exclusion.  This function checks
+ *	whether a new command @qc can be issued.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+	struct ata_link *link = qc->dev->link;
+
+	if (qc->tf.protocol == ATA_PROT_NCQ) {
+		if (!ata_tag_valid(link->active_tag))
+			return 0;
+	} else {
+		if (!ata_tag_valid(link->active_tag) && !link->sactive)
+			return 0;
+	}
+
+	return ATA_DEFER_LINK;
+}
+
 /**
  *	ata_qc_prep - Prepare taskfile for submission
  *	@qc: Metadata associated with taskfile to be prepared
@@ -5837,6 +5868,7 @@ EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_port_stop);
 EXPORT_SYMBOL_GPL(ata_host_stop);
 EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
 EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
 EXPORT_SYMBOL_GPL(ata_bmdma_setup);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 021e4a3..9589013 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1339,39 +1339,6 @@ static void ata_scsi_qc_complete(struct 
 }
 
 /**
- *	ata_scmd_need_defer - Check whether we need to defer scmd
- *	@dev: ATA device to which the command is addressed
- *	@is_io: Is the command IO (and thus possibly NCQ)?
- *
- *	NCQ and non-NCQ commands cannot run together.  As upper layer
- *	only knows the queue depth, we are responsible for maintaining
- *	exclusion.  This function checks whether a new command can be
- *	issued to @dev.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- *
- *	RETURNS:
- *	1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
-	struct ata_link *link = dev->link;
-
-	if (!(dev->flags & ATA_DFLAG_NCQ))
-		return 0;
-
-	if (is_io) {
-		if (!ata_tag_valid(link->active_tag))
-			return 0;
-	} else {
-		if (!ata_tag_valid(link->active_tag) && !link->sactive)
-			return 0;
-	}
-	return 1;
-}
-
-/**
  *	ata_scsi_translate - Translate then issue SCSI command to ATA device
  *	@dev: ATA device to which the command is addressed
  *	@cmd: SCSI command to execute
@@ -1402,15 +1369,13 @@ static int ata_scsi_translate(struct ata
 			      void (*done)(struct scsi_cmnd *),
 			      ata_xlat_func_t xlat_func)
 {
+	struct ata_port *ap = dev->link->ap;
 	struct ata_queued_cmd *qc;
 	u8 *scsicmd = cmd->cmnd;
-	int is_io = xlat_func == ata_scsi_rw_xlat;
+	int rc;
 
 	VPRINTK("ENTER\n");
 
-	if (unlikely(ata_scmd_need_defer(dev, is_io)))
-		goto defer;
-
 	qc = ata_scsi_qc_new(dev, cmd, done);
 	if (!qc)
 		goto err_mem;
@@ -1438,6 +1403,11 @@ static int ata_scsi_translate(struct ata
 	if (xlat_func(qc, scsicmd))
 		goto early_finish;
 
+	if (ap->ops->qc_defer) {
+		if ((rc = ap->ops->qc_defer(qc)))
+			goto defer;
+	}
+
 	/* select device, send command to hardware */
 	ata_qc_issue(qc);
 
@@ -1459,8 +1429,12 @@ err_mem:
 	return 0;
 
 defer:
+	ata_qc_free(qc);
 	DPRINTK("EXIT - defer\n");
-	return SCSI_MLQUEUE_DEVICE_BUSY;
+	if (rc == ATA_DEFER_LINK)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	else
+		return SCSI_MLQUEUE_HOST_BUSY;
 }
 
 /**
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index a952513..e3d13d6 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -380,6 +380,7 @@ static const struct ata_port_operations 
 	.check_altstatus	= ata_noop_check_status,
 	.dev_select		= ata_noop_dev_select,
 
+	.qc_defer		= ata_std_qc_defer,
 	.qc_prep		= sil24_qc_prep,
 	.qc_issue		= sil24_qc_issue,
 
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 17a4af4..a26b6a6 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -235,6 +235,10 @@ enum {
 	ATA_PORT_PRIMARY	= (1 << 0),
 	ATA_PORT_SECONDARY	= (1 << 1),
 
+	/* return values for ->qc_defer */
+	ATA_DEFER_LINK		= 1,
+	ATA_DEFER_PORT		= 2,
+
 	/* desc_len for ata_eh_info and context */
 	ATA_EH_DESC_LEN		= 80,
 
@@ -566,6 +570,7 @@ struct ata_port_operations {
 	void (*bmdma_setup) (struct ata_queued_cmd *qc);
 	void (*bmdma_start) (struct ata_queued_cmd *qc);
 
+	int (*qc_defer) (struct ata_queued_cmd *qc);
 	void (*qc_prep) (struct ata_queued_cmd *qc);
 	unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
 
@@ -691,6 +696,7 @@ extern int ata_port_start (struct ata_po
 extern void ata_port_stop (struct ata_port *ap);
 extern void ata_host_stop (struct ata_host_set *host_set);
 extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
 extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
 extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
-- 
1.2.4



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

* [PATCH 7/7] libata-pm-prep: add HRST_TO_RESUME and implement resume action helpers
  2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
                   ` (3 preceding siblings ...)
  2006-05-11 16:37 ` [PATCH 3/7] libata-pm-prep: separate out sata_link_hardreset() Tejun Heo
@ 2006-05-11 16:37 ` Tejun Heo
  2006-05-11 16:37 ` [PATCH 5/7] libata-pm-prep: implement ops->qc_defer() Tejun Heo
  2006-05-11 16:37 ` [PATCH 6/7] libata-pm-prep: implement qc_defer helpers Tejun Heo
  6 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-05-11 16:37 UTC (permalink / raw)
  To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo

Some PM needs hardreset to resume link.  Add ATA_LFLAG_HRST_TO_RESUME
to mark such links and separate out ata_link_resume_action() such that
the test can be done in one place and, while at it, separate out
ata_link_init_probe() which sets resume action and probe mask from
ata_device_add().  These resume/probing related helpers will be used
by PM.

---

 drivers/scsi/libata-core.c |    7 +------
 drivers/scsi/libata-eh.c   |    6 +++---
 drivers/scsi/libata-scsi.c |    4 ++--
 include/linux/libata.h     |   17 +++++++++++++++++
 4 files changed, 23 insertions(+), 11 deletions(-)

b23bfeecdddff57fd54e62193ae8b05e88729c63
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index fb64a0f..148d84d 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5472,14 +5472,9 @@ int ata_device_add(const struct ata_prob
 			ata_port_probe(ap);
 
 			spin_lock_irqsave(&ap->host_set->lock, flags);
-
-			ap->link.eh_info.probe_mask =
-				(1 << ata_link_max_devices(&ap->link)) - 1;
-			ap->link.eh_info.action |= ATA_EH_SOFTRESET;
-
 			set_bit(bit, &ap->flags);
+			ata_link_init_probe(&ap->link);
 			ata_port_schedule_eh(ap);
-
 			spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
 			wait_on_bit(&ap->flags, bit, ata_boot_probe_wait,
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index ffbd028..d62a529 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -941,7 +941,7 @@ static void ata_eh_analyze_serror(struct
 	}
 	if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) {
 		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_HARDRESET;
+		action |= ata_link_resume_action(link);
 		ehc->i.probe_mask |= 1;
 	}
 
@@ -1695,7 +1695,7 @@ int ata_eh_recover(struct ata_port *ap, 
 				ata_eh_detach_dev(dev);
 				ata_dev_init(dev);
 				ehc->did_probe_mask |= (1 << dev->devno);
-				ehc->i.action |= ATA_EH_SOFTRESET;
+				ehc->i.action |= ata_link_resume_action(link);
 			}
 		}
 	}
@@ -1805,7 +1805,7 @@ int ata_eh_recover(struct ata_port *ap, 
 
 			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 			ehc->did_probe_mask |= (1 << dev->devno);
-			ehc->i.action |= ATA_EH_SOFTRESET;
+			ehc->i.action |= ata_link_resume_action(link);
 		}
 	} else {
 		/* soft didn't work?  be haaaaard */
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 9589013..de40b80 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2903,7 +2903,7 @@ static int ata_scsi_user_scan(struct Scs
 		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;
+			link->eh_info.action |= ata_link_resume_action(link);
 		}
 	} else {
 		struct ata_device *dev = ata_find_dev(ap, id);
@@ -2911,7 +2911,7 @@ static int ata_scsi_user_scan(struct Scs
 		if (dev) {
 			link = dev->link;
 			link->eh_info.probe_mask |= 1 << dev->devno;
-			link->eh_info.action |= ATA_EH_SOFTRESET;
+			link->eh_info.action |= ata_link_resume_action(link);
 		} else
 			rc = -EINVAL;
 	}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index df78f3e..bbfd176 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -143,6 +143,9 @@ enum {
 
 	ATA_DEV_ERING_SIZE	= 32,	/* record 32 recent errors */
 
+	/* struct ata_link flags */
+	ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset needed to resume */
+
 	/* struct ata_port flags */
 	ATA_FLAG_SLAVE_POSS	= (1 << 0), /* host supports slave dev */
 					    /* (doesn't imply presence) */
@@ -934,6 +937,20 @@ static inline int ata_link_max_devices(c
 	return 1;
 }
 
+static inline unsigned int ata_link_resume_action(struct ata_link *link)
+{
+	if (link->flags & ATA_LFLAG_HRST_TO_RESUME)
+		return ATA_EH_HARDRESET;
+	return ATA_EH_SOFTRESET;
+}
+
+static inline void ata_link_init_probe(struct ata_link *link)
+{
+	link->eh_info.probe_mask = (1 << ata_link_max_devices(link)) - 1;
+	link->eh_info.action = ata_link_resume_action(link);
+	link->eh_context.i = link->eh_info;
+}
+
 static inline int ata_link_active(struct ata_link *link)
 {
 	return ata_tag_valid(link->active_tag) || link->sactive;
-- 
1.2.4



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

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

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-11 16:37 [PATCHSET 10/11] prep for PM support Tejun Heo
2006-05-11 16:37 ` [PATCH 1/7] libata-pm-prep: add @new_class to ata_dev_revalidate() Tejun Heo
2006-05-11 16:37 ` [PATCH 4/7] libata-pm-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
2006-05-11 16:37 ` [PATCH 2/7] libata-pm-prep: make a number of functions global to libata Tejun Heo
2006-05-11 16:37 ` [PATCH 3/7] libata-pm-prep: separate out sata_link_hardreset() Tejun Heo
2006-05-11 16:37 ` [PATCH 7/7] libata-pm-prep: add HRST_TO_RESUME and implement resume action helpers Tejun Heo
2006-05-11 16:37 ` [PATCH 5/7] libata-pm-prep: implement ops->qc_defer() Tejun Heo
2006-05-11 16:37 ` [PATCH 6/7] libata-pm-prep: implement qc_defer helpers 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).