linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHSET 2/3] prep for PMP support, take 2
@ 2006-07-08  5:51 Tejun Heo
  2006-07-08  5:51 ` [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata Tejun Heo
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide, htejun

Howdy,

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

This is the first take of libata-pmp-prep patchset.  This patchset
contains 6 patches and implements various stuff needed for PMP.

Changes from the last take[L] are.

* s/pm/pmp/g
* link resume handling updated

This patchset is against

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

--
tejun

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



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

* [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate()
  2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
  2006-07-08  5:51 ` [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata Tejun Heo
@ 2006-07-08  5:51 ` Tejun Heo
  2006-07-08  5:51 ` [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

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

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

---

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

34beb969ad3952cf7a1cc77e5b21f3f1b563ee86
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index a887522..f004675 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2115,7 +2115,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;
 
@@ -2985,6 +2985,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
@@ -2996,9 +2997,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;
 
@@ -3007,13 +3008,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 076badd..55d43c1 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1717,7 +1717,7 @@ static int ata_eh_revalidate_and_attach(
 			}
 
 			ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
-			rc = ata_dev_revalidate(dev,
+			rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
 					ehc->i.flags & ATA_EHI_DID_RESET);
 			if (rc)
 				break;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b6715c1..d65bb05 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -693,7 +693,8 @@ extern int sata_std_hardreset(struct ata
 extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
 extern void sata_std_hp_poll_activate(struct ata_port *ap);
 extern int sata_std_hp_poll(struct ata_port *ap);
-extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
+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.3.2



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

* [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata
  2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
@ 2006-07-08  5:51 ` Tejun Heo
  2006-07-08  5:51 ` [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, 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 PMP.

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

---

 drivers/scsi/libata-core.c |    9 ++++-----
 drivers/scsi/libata-eh.c   |   31 +++++++++++++++----------------
 drivers/scsi/libata.h      |   19 +++++++++++++++++++
 3 files changed, 38 insertions(+), 21 deletions(-)

883d46c043da3fc913dbe979f49c2c19fd29889b
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index f004675..bb12e16 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -69,7 +69,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 sata_link_init_spd_limit(struct ata_link *link);
 
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
@@ -1656,7 +1655,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;
 
@@ -2583,7 +2582,7 @@ int sata_link_resume(struct ata_link *li
 	return sata_link_debounce(link, params);
 }
 
-static void ata_wait_spinup(struct ata_link *link)
+void ata_wait_spinup(struct ata_link *link)
 {
 	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned long end, secs;
@@ -5354,7 +5353,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;
 
@@ -5387,7 +5386,7 @@ static void ata_link_init(struct ata_por
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-static int sata_link_init_spd_limit(struct ata_link *link)
+int sata_link_init_spd_limit(struct ata_link *link)
 {
 
 	u32 scontrol, spd;
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 55d43c1..e6fd54a 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -59,7 +59,6 @@ struct list_head hp_poll_list = LIST_HEA
 DECLARE_WORK(hp_poll_work, ata_hp_poll_worker, NULL);
 
 static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
 static void ata_eh_handle_port_suspend(struct ata_port *ap);
 static void ata_eh_handle_port_resume(struct ata_port *ap);
 
@@ -773,7 +772,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_link *link = dev->link;
 	struct ata_port *ap = link->ap;
@@ -810,8 +809,8 @@ static void ata_eh_detach_dev(struct ata
  *	LOCKING:
  *	None.
  */
-static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
-			       unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+			unsigned int action)
 {
 	struct ata_port *ap = link->ap;
 	unsigned long flags;
@@ -838,8 +837,8 @@ static void ata_eh_about_to_do(struct at
  *	LOCKING:
  *	None.
  */
-static void ata_eh_done(struct ata_link *link, struct ata_device *dev,
-			unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+		 unsigned int action)
 {
 	ata_eh_clear_action(link, dev, &link->eh_context.i, action);
 }
@@ -1427,7 +1426,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;
 
@@ -1513,7 +1512,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;
 
@@ -1564,9 +1563,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;
@@ -2039,10 +2038,10 @@ static void ata_eh_handle_dev_fail(struc
  *	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_device *dev;
@@ -2196,7 +2195,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 c544d88..e610894 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -54,11 +54,13 @@ extern unsigned int ata_do_simple_cmd(st
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 			   int post_reset, u16 *id);
 extern int ata_dev_configure(struct ata_device *dev, int print_info);
+extern void sata_print_link_status(struct ata_link *link);
 extern int sata_down_spd_limit(struct ata_link *link);
 extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
 extern int ata_set_mode(struct ata_link *link,
 			struct ata_device **r_failed_dev);
+extern void ata_wait_spinup(struct ata_link *link);
 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);
@@ -68,6 +70,8 @@ extern void ata_dev_select(struct ata_po
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
 extern int ata_flush_cache(struct ata_device *dev);
 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 sata_link_init_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);
 
@@ -117,6 +121,21 @@ extern enum scsi_eh_timer_return ata_scs
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 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, struct ata_device *dev,
+			       unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+			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_hp_poll_activate(struct ata_port *ap);
 extern void ata_hp_poll_deactivate(struct ata_port *ap);
 
-- 
1.3.2



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

* [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset()
  2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
                   ` (3 preceding siblings ...)
  2006-07-08  5:51 ` [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers Tejun Heo
@ 2006-07-08  5:51 ` Tejun Heo
  2006-07-08  5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
  5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

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

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

---

 drivers/scsi/libata-core.c |   57 ++++++++++++++++++++++++++++++++++----------
 drivers/scsi/libata.h      |    2 ++
 2 files changed, 46 insertions(+), 13 deletions(-)

9a955b32a2ec11df498d7e2dc3005a29a554a6e7
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index bb12e16..4d09167 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2719,11 +2719,11 @@ 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
+ *	@timing: timing parameters { interval, duratinon, timeout } in msec
  *
- *	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)
@@ -2731,12 +2731,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, const unsigned long *timing)
 {
-	struct ata_port *ap = link->ap;
-	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
 	u32 scontrol;
-	int rc;
+	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
@@ -2747,24 +2745,24 @@ int sata_std_hardreset(struct ata_link *
 		 * and Sil3124.
 		 */
 		if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-			return rc;
+			goto out;
 
 		scontrol = (scontrol & 0x0f0) | 0x302;
 
 		if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
-			return rc;
+			goto out;
 
 		sata_set_spd(link);
 	}
 
 	/* issue phy wake/reset */
 	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-		return rc;
+		goto out;
 
 	scontrol = (scontrol & 0x0f0) | 0x301;
 
 	if ((rc = sata_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.
@@ -2772,9 +2770,42 @@ int sata_std_hardreset(struct ata_link *
 	msleep(1);
 
 	/* bring phy back */
-	sata_link_resume(link, timing);
+	rc = sata_link_resume(link, timing);
+ out:
+	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)
+{
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+	struct ata_port *ap = link->ap;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	/* do hardreset */
+	rc = sata_link_hardreset(link, timing);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"COMRESET failed (errno=%d)\n", 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 e610894..7017b9d 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -55,6 +55,8 @@ 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,
+			       const unsigned long *timing);
 extern int sata_down_spd_limit(struct ata_link *link);
 extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
-- 
1.3.2



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

* [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers
  2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
                   ` (2 preceding siblings ...)
  2006-07-08  5:51 ` [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
@ 2006-07-08  5:51 ` Tejun Heo
  2006-07-08  5:51 ` [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset() Tejun Heo
  2006-07-08  5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
  5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, 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 PMP.

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

---

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

e8c076ff470980da565d0c41bd95c9a1538ab561
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index f9644db..346130c 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1004,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_ONSTACK(wait);
 	unsigned long flags;
 	unsigned int err_mask;
@@ -1042,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;
@@ -1114,6 +1117,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
@@ -4520,10 +4524,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
@@ -4694,9 +4706,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 e6fd54a..122226b 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -293,6 +293,7 @@ void ata_scsi_error(struct Scsi_Host *ho
 
 		ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
 		ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+		ap->excl_link = NULL;	/* don't maintain exclusion over EH */
 
 		spin_unlock_irqrestore(ap->lock, flags);
 
@@ -2225,6 +2226,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;
 }
 
 /**
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 8a4adce..dea1e5f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -192,6 +192,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 */
@@ -549,12 +550,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_pmp_links;	/* nr of available PMP links */
 	struct ata_link		*pmp_link;	/* array of PMP links */
+	struct ata_link		*excl_link;	/* for PMP qc exclusion */
 
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
@@ -1022,6 +1025,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_pmp_links)
-- 
1.3.2



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

* [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis()
  2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
  2006-07-08  5:51 ` [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata Tejun Heo
  2006-07-08  5:51 ` [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
@ 2006-07-08  5:51 ` Tejun Heo
  2006-07-08  5:51 ` [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers Tejun Heo
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

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

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

---

 drivers/scsi/ahci.c        |   10 ++++------
 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, 16 insertions(+), 15 deletions(-)

ce524d81b263d170c5c14c90467ac284d5f06252
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index f41db5d..9f2f66a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -662,8 +662,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);
 
@@ -681,8 +680,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 */
@@ -732,7 +730,7 @@ static int ahci_hardreset(struct ata_lin
 	/* clear D2H reception area to properly wait for D2H FIS */
 	ata_tf_init(link->device, &tf);
 	tf.command = 0xff;
-	ata_tf_to_fis(&tf, d2h_fis, 0);
+	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
 	rc = sata_std_hardreset(link, class);
 
@@ -825,7 +823,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 4d09167..38ddeff 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -100,8 +100,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).
@@ -109,12 +110,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 e047890..fca2013 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -336,7 +336,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 b2b8d13..b1ae88d 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -706,7 +706,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 d65bb05..f46b215 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -741,7 +741,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 void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
-- 
1.3.2



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

* [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer()
  2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
                   ` (4 preceding siblings ...)
  2006-07-08  5:51 ` [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset() Tejun Heo
@ 2006-07-08  5:51 ` Tejun Heo
  2006-07-19 20:32   ` Jeff Garzik
  5 siblings, 1 reply; 9+ messages in thread
From: Tejun Heo @ 2006-07-08  5:51 UTC (permalink / raw)
  To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo

Controllers which support PMP 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 conditions are advisory and in general
ATA_DEFER_LINK can be considered as lower priority deferring 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 PMP)
* 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.

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

---

 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(-)

bdc03a79abfa9d30a7cb1c06c6038a0a5eb65095
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 9f2f66a..17b459f 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -242,6 +242,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 38ddeff..f9644db 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -3425,6 +3425,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
@@ -6150,6 +6181,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
 EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
 EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
 EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
+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 7e33506..d446a86 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1458,39 +1458,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
@@ -1521,15 +1488,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;
@@ -1557,6 +1522,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);
 
@@ -1578,8 +1548,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 b1ae88d..68a3fc1 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -391,6 +391,7 @@ static const struct ata_port_operations 
 
 	.tf_read		= sil24_tf_read,
 
+	.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 f46b215..8a4adce 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -249,6 +249,10 @@ enum {
 	/* ering size */
 	ATA_ERING_SIZE		= 32,
 
+	/* 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,
 
@@ -606,6 +610,7 @@ struct ata_port_operations {
 
 	void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
 
+	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);
 
@@ -759,6 +764,7 @@ extern void ata_pio_data_xfer(struct ata
 			      unsigned int buflen, int write_data);
 extern void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
 			      unsigned int buflen, int write_data);
+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.3.2



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

* Re: [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer()
  2006-07-08  5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
@ 2006-07-19 20:32   ` Jeff Garzik
  2006-07-24  6:21     ` Tejun Heo
  0 siblings, 1 reply; 9+ messages in thread
From: Jeff Garzik @ 2006-07-19 20:32 UTC (permalink / raw)
  To: Tejun Heo; +Cc: alan, lkml, forrest.zhao, linux-ide

Tejun Heo wrote:
> Controllers which support PMP 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 conditions are advisory and in general
> ATA_DEFER_LINK can be considered as lower priority deferring 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 PMP)
> * 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.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ACK patches 1-4.

For this patch (#5), I would much rather prefer to update ->qc_issue() 
or ->qc_prep() to return a DEFER return value.  That matches more 
closely other APIs in Linux.

	Jeff




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

* Re: [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer()
  2006-07-19 20:32   ` Jeff Garzik
@ 2006-07-24  6:21     ` Tejun Heo
  0 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-24  6:21 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: alan, lkml, forrest.zhao, linux-ide

Jeff Garzik wrote:
> Tejun Heo wrote:
>> Controllers which support PMP 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 conditions are advisory and in general
>> ATA_DEFER_LINK can be considered as lower priority deferring 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 PMP)
>> * 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.
>>
>> Signed-off-by: Tejun Heo <htejun@gmail.com>
> 
> ACK patches 1-4.
> 
> For this patch (#5), I would much rather prefer to update ->qc_issue() 
> or ->qc_prep() to return a DEFER return value.  That matches more 
> closely other APIs in Linux.

Will do.

-- 
tejun


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

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

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-08  5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
2006-07-08  5:51 ` [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata Tejun Heo
2006-07-08  5:51 ` [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
2006-07-08  5:51 ` [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
2006-07-08  5:51 ` [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers Tejun Heo
2006-07-08  5:51 ` [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset() Tejun Heo
2006-07-08  5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
2006-07-19 20:32   ` Jeff Garzik
2006-07-24  6:21     ` 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).