linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHSET] libata: add NCQ support
@ 2006-04-03  8:32 Tejun Heo
  2006-04-03  8:32 ` [PATCH 05/14] libata: implement command exclusion Tejun Heo
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide, htejun

Hello, all.

This patchset implements NCQ support to libata and update ahci such
that it supports NCQ.  It contains 14 patches.

#01-03	prep for NCQ support
#04-10	implement NCQ support
#11-14	update ahci to support NCQ

This patchset is against

  upstream [1]
  + scsi_eh_schedule patchset, take 2 [2][3]
  + ahci softreset presence detection patch [4]
  + eh-framework patchset [5]
  + eh patchset [6]

#01-04	Prep for EH.  Add constants, implement ering and utility functions
#05-09	Implement EH helpers.  These are the backbones of new EH.
#10	Implement stock BMDMA EH using EH helpers.
#11-13	Convert ata_piix, sata_sil and ahci to new EH

Thanks.

--
tejun

[1] 6d5f9732a16a74d75f8cdba5b00557662e83f466
[2] http://marc.theaimsgroup.com/?l=linux-scsi&m=114399387517874&w=2
[3] http://marc.theaimsgroup.com/?l=linux-ide&m=114399407718154&w=2
[4] http://marc.theaimsgroup.com/?l=linux-ide&m=114399712126232&w=2
[5] http://article.gmane.org/gmane.linux.ide/9311
[6] http://article.gmane.org/gmane.linux.ide/9343



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

* [PATCH 01/14] libata: add NCQ related ATA constants and id macros
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (5 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 02/14] libata: add NCQ related libata flags Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 07/14] libata: implement ata_eh_read_log_10h() Tejun Heo
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Add NCQ related ATA constants and id macros.

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

---

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

48e08259332120710872ee5dce6d2051324f5d46
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 283138f..0509340 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -133,6 +133,8 @@ enum {
 	ATA_CMD_WRITE		= 0xCA,
 	ATA_CMD_WRITE_EXT	= 0x35,
 	ATA_CMD_WRITE_FUA_EXT	= 0x3D,
+	ATA_CMD_FPDMA_READ	= 0x60,
+	ATA_CMD_FPDMA_WRITE	= 0x61,
 	ATA_CMD_PIO_READ	= 0x20,
 	ATA_CMD_PIO_READ_EXT	= 0x24,
 	ATA_CMD_PIO_WRITE	= 0x30,
@@ -151,6 +153,10 @@ enum {
 	ATA_CMD_INIT_DEV_PARAMS	= 0x91,
 	ATA_CMD_READ_NATIVE_MAX	= 0xF8,
 	ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+	ATA_CMD_READ_LOG_EXT	= 0x2f,
+
+	/* READ_LOG_EXT pages */
+	ATA_LOG_SATA_NCQ	= 0x10,
 
 	/* SETFEATURES stuff */
 	SETFEATURES_XFER	= 0x03,
@@ -218,6 +224,7 @@ enum ata_tf_protocols {
 	ATA_PROT_NODATA,	/* no data */
 	ATA_PROT_PIO,		/* PIO single sector */
 	ATA_PROT_DMA,		/* DMA */
+	ATA_PROT_NCQ,		/* NCQ */
 	ATA_PROT_ATAPI,		/* packet command, PIO data xfer*/
 	ATA_PROT_ATAPI_NODATA,	/* packet command, no data */
 	ATA_PROT_ATAPI_DMA,	/* packet command with special DMA sauce */
@@ -273,6 +280,8 @@ struct ata_taskfile {
 #define ata_id_has_pm(id)	((id)[82] & (1 << 3))
 #define ata_id_has_lba(id)	((id)[49] & (1 << 9))
 #define ata_id_has_dma(id)	((id)[49] & (1 << 8))
+#define ata_id_has_ncq(id)	((id)[76] & (1 << 8))
+#define ata_id_queue_depth(id)	(((id)[75] & 0x1f) + 1)
 #define ata_id_removeable(id)	((id)[0] & (1 << 7))
 #define ata_id_has_dword_io(id)	((id)[50] & (1 << 0))
 #define ata_id_u32(id,n)	\
-- 
1.2.4



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

* [PATCH 02/14] libata: add NCQ related libata flags
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (4 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 03/14] libata: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 01/14] libata: add NCQ related ATA constants and id macros Tejun Heo
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Add two NCQ related libata flags - ATA_DFLAG_NCQ and ATA_FLAG_NCQ..

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

---

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

190336a29c98e025ad0c9e76f8d6115d00a90918
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 43e5392..c3a3cc0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -124,6 +124,7 @@ enum {
 	/* struct ata_device stuff */
 	ATA_DFLAG_LBA		= (1 << 0), /* device supports LBA */
 	ATA_DFLAG_LBA48		= (1 << 1), /* device supports LBA48 */
+	ATA_DFLAG_NCQ		= (1 << 2), /* device supports NCQ */
 	ATA_DFLAG_CFG_MASK	= (1 << 8) - 1,
 
 	ATA_DFLAG_PIO		= (1 << 8), /* device currently in PIO mode */
@@ -150,6 +151,7 @@ enum {
 	ATA_FLAG_PIO_DMA	= (1 << 7), /* PIO cmds via DMA */
 	ATA_FLAG_PIO_LBA48	= (1 << 8), /* Host DMA engine is LBA28 only */
 	ATA_FLAG_IRQ_MASK	= (1 << 9), /* Mask IRQ in PIO xfers */
+	ATA_FLAG_NCQ		= (1 << 10), /* host supports NCQ */
 
 	ATA_FLAG_NOINTR		= (1 << 16), /* FIXME: Remove this once
 					      * proper HSM is in place. */
-- 
1.2.4



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

* [PATCH 04/14] libata: implement ap->sactive
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (8 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 10/14] libata: implement ata_ncq_complete() Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 11/14] libata: clean up AHCI constants in preparation for NCQ Tejun Heo
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Implement ap->sactive.  This is libata's view of SActive register.
This will be used to track NCQ commands and complete them.

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

---

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

60995c11803d5d1844b6998ae373ba2d8d01be6d
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 5491afb..b4eeb4b 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -982,6 +982,7 @@ unsigned ata_exec_internal(struct ata_po
 	u8 command = tf->command;
 	struct ata_queued_cmd *qc;
 	unsigned int tag, preempted_tag;
+	u32 preempted_sactive;
 	DECLARE_COMPLETION(wait);
 	unsigned long flags;
 	unsigned int err_mask;
@@ -1017,7 +1018,9 @@ unsigned ata_exec_internal(struct ata_po
 	ata_qc_reinit(qc);
 
 	preempted_tag = ap->active_tag;
+	preempted_sactive = ap->sactive;
 	ap->active_tag = ATA_TAG_POISON;
+	ap->sactive = 0;
 
 	/* prepare & issue qc */
 	qc->tf = *tf;
@@ -1069,6 +1072,7 @@ unsigned ata_exec_internal(struct ata_po
 
 	ata_qc_free(qc);
 	ap->active_tag = preempted_tag;
+	ap->sactive = preempted_sactive;
 
 	/* XXX - Some LLDDs (sata_mv) disable port on command failure.
 	 * Until those drivers are fixed, we detect the condition
@@ -4197,6 +4201,12 @@ void __ata_qc_complete(struct ata_queued
 	if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
 		ata_sg_clean(qc);
 
+	/* sactive bit must be turned atomically w.r.t. command
+	 * completion, so it cannot be turned off in ata_qc_free().
+	 */
+	if (qc->tf.protocol == ATA_PROT_NCQ)
+		qc->ap->sactive &= ~(1 << qc->tag);
+
 	/* atapi: mark qc as inactive to prevent the interrupt handler
 	 * from completing the command twice later, before the error handler
 	 * is called. (when rc != 0 and atapi request sense is needed)
@@ -4296,7 +4306,17 @@ void ata_qc_issue(struct ata_queued_cmd 
 {
 	struct ata_port *ap = qc->ap;
 
-	qc->ap->active_tag = qc->tag;
+	/* old EH reuses active qc to request ATAPI sense */
+	WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+
+	if (qc->tf.protocol == ATA_PROT_NCQ) {
+		WARN_ON(ap->sactive & (1 << qc->tag));
+		ap->sactive |= 1 << qc->tag;
+	} else {
+		WARN_ON(ap->sactive);
+		ap->active_tag = qc->tag;
+	}
+
 	qc->flags |= ATA_QCFLAG_ACTIVE;
 
 	if (ata_should_dma_map(qc)) {
diff --git a/include/linux/libata.h b/include/linux/libata.h
index c3a3cc0..7175191 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -450,6 +450,7 @@ struct ata_port {
 	struct ata_queued_cmd	qcmd[ATA_MAX_QUEUE];
 	unsigned long		qactive;
 	unsigned int		active_tag;
+	u32			sactive;
 
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
-- 
1.2.4



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

* [PATCH 05/14] libata: implement command exclusion
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 08/14] libata: update EH to handle NCQ Tejun Heo
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

NCQ enabled device will have queue depth larger than one but no two
non-NCQ commands can be issued simultaneously, neither can a non-NCQ
command and NCQ commands.  This patch makes ata_scsi_translate()
return SCSI_MLQUEUE_DEVICE_BUSY if such exclusion is necessary.  SCSI
midlayer will retry the command later.

As SCSI midlayer always retries once a command completes, this doesn't
incur unnecessary delays and as most commands will be NCQ ones for NCQ
device, so the overhead should be negligible.

Initial implementation is from Jens Axboe and using
SCSI_MLQUEUE_DEVICE_BUSY for exclusion is suggested by Jeff Garzik.

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

---

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

a5ceff438d7136a71a11fa1a6fcd0b4d3061a867
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index a1a4307..f3a73c4 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1229,6 +1229,39 @@ static void ata_scsi_qc_complete(struct 
 }
 
 /**
+ *	ata_scmd_need_defer - Check whether we need to defer scmd
+ *	@ap: ATA port to which the command is addressed
+ *	@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_port *ap, struct ata_device *dev,
+			       int is_io)
+{
+	if (!(dev->flags & ATA_DFLAG_NCQ))
+		return 0;
+
+	if (is_io) {
+		if (!ata_tag_valid(ap->active_tag))
+			return 0;
+	} else {
+		if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
+			return 0;
+	}
+	return 1;
+}
+
+/**
  *	ata_scsi_translate - Translate then issue SCSI command to ATA device
  *	@ap: ATA port to which the command is addressed
  *	@dev: ATA device to which the command is addressed
@@ -1263,9 +1296,13 @@ static int ata_scsi_translate(struct ata
 {
 	struct ata_queued_cmd *qc;
 	u8 *scsicmd = cmd->cmnd;
+	int is_io = xlat_func == ata_scsi_rw_xlat;
 
 	VPRINTK("ENTER\n");
 
+	if (unlikely(ata_scmd_need_defer(ap, dev, is_io)))
+		goto defer;
+
 	qc = ata_scsi_qc_new(ap, dev, cmd, done);
 	if (!qc)
 		goto err_mem;
@@ -1312,6 +1349,10 @@ err_mem:
 	done(cmd);
 	DPRINTK("EXIT - internal\n");
 	return 0;
+
+defer:
+	DPRINTK("EXIT - defer\n");
+	return SCSI_MLQUEUE_DEVICE_BUSY;
 }
 
 /**
-- 
1.2.4



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

* [PATCH 08/14] libata: update EH to handle NCQ
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
  2006-04-03  8:32 ` [PATCH 05/14] libata: implement command exclusion Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 09/14] libata: implement NCQ device configuration Tejun Heo
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

* ata_eh_determine_qc() is updated to take log page 10h into account
  to determine which qc has failed and obtain its TF.

* ata_eh_report() is updated to report ap->sactive.

* ata_eh_finish_qcs() is updated to finish all aborted NCQ commands.

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

---

 drivers/scsi/ahci.c         |    2 +
 drivers/scsi/libata-bmdma.c |    2 +
 drivers/scsi/libata-eh.c    |   79 +++++++++++++++++++++++++++++++++++++++++--
 include/linux/libata.h      |    1 +
 4 files changed, 79 insertions(+), 5 deletions(-)

7afc779e20e434b5ce39626a2c5ef4b2f9cae017
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 21aea0b..3dad10f 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -862,7 +862,7 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	qc = ata_eh_determine_qc(ap, &tf);
+	qc = ata_eh_determine_qc(ap, 0, &tf);
 
 	action |= ahci_eh_autopsy(ap, qc, irq_stat, desc, sizeof(desc));
 	action |= ata_eh_autopsy(ap, qc, &tf, serror);
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 6e48ce5..3c3bc71 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -700,7 +700,7 @@ void ata_bmdma_drive_eh(struct ata_port 
 	struct ata_taskfile tf;
 	u32 serror;
 
-	qc = ata_eh_determine_qc(ap, &tf);
+	qc = ata_eh_determine_qc(ap, 0, &tf);
 
 	/* reset PIO HSM and stop DMA engine */
 	spin_lock_irqsave(&host_set->lock, flags);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 94ecb0c..10c0574 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -637,6 +637,7 @@ static int ata_eh_read_log_10h(struct at
 /**
  *	ata_eh_determine_qc - Determine which qc caused error
  *	@ap: port which failed
+ *	@use_log_10h: use log page 10h result
  *	@tf: resulting taskfile registers of the failed command
  *
  *	Determine which qc caused failure and read associated tf
@@ -649,12 +650,65 @@ static int ata_eh_read_log_10h(struct at
  *	Pointer to the failed qc.
  */
 struct ata_queued_cmd * ata_eh_determine_qc(struct ata_port *ap,
+					    int use_log_10h,
 					    struct ata_taskfile *tf)
 {
+	struct ata_queued_cmd *first_qc, *qc;
+	struct ata_device *dev;
+	struct ata_taskfile tmp_tf;
+	unsigned int tag;
+	int rc;
+
 	memset(tf, 0, sizeof(*tf));
 	ap->ops->tf_read(ap, tf);
 
-	return __ata_qc_from_tag(ap, ap->active_tag);
+	qc = __ata_qc_from_tag(ap, ap->active_tag);
+	if (qc)
+		return qc;
+
+	if (!ap->sactive)
+		return NULL;
+
+	/* NCQ.  Assume the first device. */
+	dev = &ap->device[0];
+
+	/* Find the first active qc with error.  If no qc is
+	 * explicitly marked with error, use the first active qc.
+	 */
+	first_qc = NULL;
+	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+		qc = __ata_qc_from_tag(ap, tag);
+		if (qc->flags & ATA_QCFLAG_ACTIVE) {
+			if (!first_qc)
+				first_qc = qc;
+			if (qc->err_mask)
+				break;
+		}
+	}
+	if (tag == ATA_MAX_QUEUE)
+		qc = first_qc;
+
+	/* Always read log page 10h to unjam the device but use the
+	 * result only if use_log_10h is non-zero.
+	 */
+	rc = ata_eh_read_log_10h(ap, dev, &tag, &tmp_tf);
+	if (rc || !(ap->sactive & (1 << tag))) {
+		if (rc == 0)
+			rc = -ENOENT;
+		printk(KERN_ERR "ata%u: failed to read log page 10h (errno=%d)\n",
+		       ap->id, rc);
+		qc->err_mask &= ~AC_ERR_DEV;
+		qc->err_mask |= AC_ERR_OTHER;
+	}
+	DPRINTK("ata%u: rc=%d emask=0x%x tag=%d stat=0x%x err=0x%x\n",
+		ap->id, rc, qc->err_mask, tag, tmp_tf.command, tmp_tf.feature);
+
+	if (use_log_10h) {
+		qc = __ata_qc_from_tag(ap, tag);
+		memcpy(tf, &tmp_tf, sizeof(*tf));
+	}
+
+	return qc;
 }
 
 /**
@@ -980,11 +1034,11 @@ void ata_eh_report(struct ata_port *ap, 
 
 	printk(KERN_ERR
 	       "ata%u: dev %u command 0x%x tag %u failed with %s\n"
-	       "      Emask 0x%x stat 0x%x err 0x%x SErr 0x%x action 0x%x\n"
+	       "      Emask 0x%x stat 0x%x err 0x%x SAct 0x%x SErr 0x%x action 0x%x\n"
 	       "%s%s%s",
 	       ap->id, qc->dev->devno, qc->tf.command, qc->tag,
 	       ata_err_string(qc->err_mask), qc->err_mask,
-	       tf->command, tf->feature, serror, action,
+	       tf->command, tf->feature, ap->sactive, serror, action,
 	       desc_head, desc, desc_tail);
 }
 
@@ -1166,7 +1220,9 @@ void ata_eh_finish_qcs(struct ata_port *
 		       struct ata_taskfile *tf)
 {
 	struct ata_taskfile tmp_tf;
+	int i;
 
+	/* first, the failed qc */
 	if (qc) {
 		/* prevent infinite retry loop */
 		if (!qc->err_mask && !(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
@@ -1194,4 +1250,21 @@ void ata_eh_finish_qcs(struct ata_port *
 		else
 			ata_eh_qc_retry(qc);
 	}
+
+	/* and, victimized NCQ commands */
+
+	/* feed zero TF to sense generation */
+	memset(&tmp_tf, 0, sizeof(tmp_tf));
+
+	for (i = 0; i < ATA_MAX_QUEUE; i++) {
+		qc = __ata_qc_from_tag(ap, i);
+		if (qc->flags & ATA_QCFLAG_ACTIVE) {
+			tmp_tf.flags = qc->tf.flags;
+			tmp_tf.protocol = qc->tf.protocol;
+			tmp_tf.ctl = qc->tf.ctl;
+			qc->tf = tmp_tf;
+
+			ata_eh_qc_retry(qc);
+		}
+	}
 }
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7175191..f3f6f50 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -696,6 +696,7 @@ extern void ata_eh_schedule_port(struct 
 extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
 extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
 extern struct ata_queued_cmd * ata_eh_determine_qc(struct ata_port *ap,
+						   int use_log_10h,
 						   struct ata_taskfile *tf);
 extern unsigned int ata_eh_autopsy(struct ata_port *ap,
 				   struct ata_queued_cmd *qc,
-- 
1.2.4



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

* [PATCH 06/14] libata: implement NCQ command translation
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (2 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 09/14] libata: implement NCQ device configuration Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 03/14] libata: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

This patch implements NCQ command translation.  Note that NCQ commands
don't use ata_rwcmd_protocol() to choose ATA command.  This is
because, unlike non-NCQ RW commands, NCQ commands can only be used for
NCQ protocol and FUA handling is done with a flag rather than separate
command.

Original implementation is from Jens Axboe.

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

---

 drivers/scsi/libata-core.c |    1 +
 drivers/scsi/libata-scsi.c |   31 ++++++++++++++++++++++++++++++-
 2 files changed, 31 insertions(+), 1 deletions(-)

b3b26b1edc907b391ca73d68a0b5d03d409d6799
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index b4eeb4b..cc45cfc 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4272,6 +4272,7 @@ static inline int ata_should_dma_map(str
 	struct ata_port *ap = qc->ap;
 
 	switch (qc->tf.protocol) {
+	case ATA_PROT_NCQ:
 	case ATA_PROT_DMA:
 	case ATA_PROT_ATAPI_DMA:
 		return 1;
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index f3a73c4..d5748b1 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1098,7 +1098,36 @@ static unsigned int ata_scsi_rw_xlat(str
 		 */
 		goto nothing_to_do;
 
-	if (dev->flags & ATA_DFLAG_LBA) {
+	if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+		/* yay, NCQ */
+		if (!lba_48_ok(block, n_block))
+			goto out_of_range;
+
+		tf->protocol = ATA_PROT_NCQ;
+		tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+
+		if (tf->flags & ATA_TFLAG_WRITE)
+			tf->command = ATA_CMD_FPDMA_WRITE;
+		else
+			tf->command = ATA_CMD_FPDMA_READ;
+
+		qc->nsect = n_block;
+
+		tf->nsect = qc->tag << 3;
+		tf->hob_feature = (n_block >> 8) & 0xff;
+		tf->feature = n_block & 0xff;
+
+		tf->hob_lbah = (block >> 40) & 0xff;
+		tf->hob_lbam = (block >> 32) & 0xff;
+		tf->hob_lbal = (block >> 24) & 0xff;
+		tf->lbah = (block >> 16) & 0xff;
+		tf->lbam = (block >> 8) & 0xff;
+		tf->lbal = block & 0xff;
+
+		tf->device = 1 << 6;
+		if (tf->flags & ATA_TFLAG_FUA)
+			tf->device |= 1 << 7;
+	} else if (dev->flags & ATA_DFLAG_LBA) {
 		tf->flags |= ATA_TFLAG_LBA;
 
 		if (lba_28_ok(block, n_block)) {
-- 
1.2.4



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

* [PATCH 03/14] libata: pass ata_scsi_translate() return value to SCSI midlayer
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (3 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 06/14] libata: implement NCQ command translation Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 02/14] libata: add NCQ related libata flags Tejun Heo
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

ata_scsi_translate() will need to return SCSI_ML_QUEUE_DEVICE_BUSY to
achieve exlusion between NCQ and non-NCQ commands or among non-NCQ
commands.  Pass its return value upward to SCSI midlayer.

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

---

 drivers/scsi/libata-scsi.c |   34 +++++++++++++++++++++-------------
 1 files changed, 21 insertions(+), 13 deletions(-)

a2a749416f31f6cc1b790f6170a47b79bcbd1d91
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index bfb9a5b..a1a4307 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1251,9 +1251,12 @@ static void ata_scsi_qc_complete(struct 
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
+ *	needs to be deferred.
  */
-
-static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
+static int ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
 			      struct scsi_cmnd *cmd,
 			      void (*done)(struct scsi_cmnd *),
 			      ata_xlat_func_t xlat_func)
@@ -1294,13 +1297,13 @@ static void ata_scsi_translate(struct at
 	ata_qc_issue(qc);
 
 	VPRINTK("EXIT\n");
-	return;
+	return 0;
 
 early_finish:
         ata_qc_free(qc);
 	done(cmd);
 	DPRINTK("EXIT - early finish (good or error)\n");
-	return;
+	return 0;
 
 err_did:
 	ata_qc_free(qc);
@@ -1308,7 +1311,7 @@ err_mem:
 	cmd->result = (DID_ERROR << 16);
 	done(cmd);
 	DPRINTK("EXIT - internal\n");
-	return;
+	return 0;
 }
 
 /**
@@ -2461,19 +2464,23 @@ static inline void ata_scsi_dump_cdb(str
 #endif
 }
 
-static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
-				       struct ata_port *ap, struct ata_device *dev)
+static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
+				      struct ata_port *ap, struct ata_device *dev)
 {
+	int rc = 0;
+
 	if (dev->class == ATA_DEV_ATA) {
 		ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
 							      cmd->cmnd[0]);
 
 		if (xlat_func)
-			ata_scsi_translate(ap, dev, cmd, done, xlat_func);
+			rc = ata_scsi_translate(ap, dev, cmd, done, xlat_func);
 		else
 			ata_scsi_simulate(ap, dev, cmd, done);
 	} else
-		ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
+		rc = ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
+
+	return rc;
 }
 
 /**
@@ -2492,15 +2499,16 @@ static inline void __ata_scsi_queuecmd(s
  *	Releases scsi-layer-held lock, and obtains host_set lock.
  *
  *	RETURNS:
- *	Zero.
+ *	Return value from __ata_scsi_queuecmd() if @cmd can be queued,
+ *	0 otherwise.
  */
-
 int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
 	struct ata_port *ap;
 	struct ata_device *dev;
 	struct scsi_device *scsidev = cmd->device;
 	struct Scsi_Host *shost = scsidev->host;
+	int rc = 0;
 
 	ap = (struct ata_port *) &shost->hostdata[0];
 
@@ -2511,7 +2519,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *
 
 	dev = ata_scsi_find_dev(ap, scsidev);
 	if (likely(dev))
-		__ata_scsi_queuecmd(cmd, done, ap, dev);
+		rc = __ata_scsi_queuecmd(cmd, done, ap, dev);
 	else {
 		cmd->result = (DID_BAD_TARGET << 16);
 		done(cmd);
@@ -2519,7 +2527,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *
 
 	spin_unlock(&ap->host_set->lock);
 	spin_lock(shost->host_lock);
-	return 0;
+	return rc;
 }
 
 /**
-- 
1.2.4



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

* [PATCH 07/14] libata: implement ata_eh_read_log_10h()
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (6 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 01/14] libata: add NCQ related ATA constants and id macros Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 10/14] libata: implement ata_ncq_complete() Tejun Heo
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Implement ata_eh_read_log_10h().  This will be used by NCQ EH.

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

---

 drivers/scsi/libata-eh.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 107 insertions(+), 0 deletions(-)

c70528a1ce4ae9f5dffb41986e56f349f4a172ca
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 3dadff8..94ecb0c 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -528,6 +528,113 @@ static unsigned int atapi_eh_request_sen
 }
 
 /**
+ *	ata_read_log_page - read a specific log page
+ *	@ap: port on which device we wish to probe resides
+ *	@dev: target device
+ *	@page: page to read
+ *	@buf: buffer to store read page
+ *	@sectors: number of sectors to read
+ *
+ *	Read log page using READ_LOG_EXT command.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_read_log_page(struct ata_port *ap,
+				      struct ata_device *dev,
+				      u8 page, void *buf, unsigned int sectors)
+{
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	DPRINTK("read log page - page %d\n", page);
+
+	ata_tf_init(ap, &tf, dev->devno);
+	tf.command = ATA_CMD_READ_LOG_EXT;
+	tf.lbal = page;
+	tf.nsect = sectors;
+	tf.hob_nsect = sectors >> 8;
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+	tf.protocol = ATA_PROT_PIO;
+
+	err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_FROM_DEVICE,
+				     buf, sectors * ATA_SECT_SIZE);
+
+	DPRINTK("EXIT, err_mask=%x\n", err_mask);
+	return err_mask;
+}
+
+/**
+ *	ata_eh_read_log_10h - Read log page 10h for NCQ error details
+ *	@ap: Port associated with device @dev
+ *	@dev: Device to read log page 10h from
+ *	@tag: Resulting tag of the failed command
+ *	@tf: Resulting taskfile registers of the failed command
+ *
+ *	Read log page 10h to obtain NCQ error details and clear error
+ *	condition.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int ata_eh_read_log_10h(struct ata_port *ap, struct ata_device *dev,
+			       unsigned int *tag, struct ata_taskfile *tf)
+{
+	u8 *buf, csum;
+	unsigned int err_mask;
+	int i, rc;
+
+	buf = kmalloc(ATA_SECT_SIZE, GFP_KERNEL);
+	if (buf == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	err_mask = ata_read_log_page(ap, dev, ATA_LOG_SATA_NCQ, buf, 1);
+	if (err_mask) {
+		rc = -EIO;
+		goto out;
+	}
+
+	csum = 0;
+	for (i = 0; i < ATA_SECT_SIZE; i++)
+		csum += buf[i];
+	if (csum)
+		printk(KERN_WARNING "ata%u: dev %u invalid checksum 0x%x on "
+		       "log page 10h\n", ap->id, dev->devno, csum);
+
+	if (buf[0] & 0x80) {
+		rc = -ENOENT;
+		goto out;
+	}
+
+	*tag = buf[0] & 0x1f;
+
+	tf->command = buf[2];
+	tf->feature = buf[3];
+	tf->lbal = buf[4];
+	tf->lbam = buf[5];
+	tf->lbah = buf[6];
+	tf->device = buf[7];
+	tf->hob_lbal = buf[8];
+	tf->hob_lbam = buf[9];
+	tf->hob_lbah = buf[10];
+	tf->nsect = buf[12];
+	tf->hob_nsect = buf[13];
+
+	rc = 0;
+ out:
+	kfree(buf);
+	return rc;
+}
+
+/**
  *	ata_eh_determine_qc - Determine which qc caused error
  *	@ap: port which failed
  *	@tf: resulting taskfile registers of the failed command
-- 
1.2.4



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

* [PATCH 10/14] libata: implement ata_ncq_complete()
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (7 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 07/14] libata: implement ata_eh_read_log_10h() Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 04/14] libata: implement ap->sactive Tejun Heo
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Implement NCQ helper function ata_ncq_complete().  This function takes
the current value of SActive, compares it against ap->sactive and
invoke ata_qc_complete() on all finished commands.  This function is
to be used by interrupt handlers implementing NCQ.

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

---

 drivers/scsi/libata-core.c |   47 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    1 +
 2 files changed, 48 insertions(+), 0 deletions(-)

429f220dc61c1d67cedbbc7da9eb9f52b20c2271
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 56637f0..fa941cc 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4574,6 +4574,52 @@ irqreturn_t ata_interrupt (int irq, void
 	return IRQ_RETVAL(handled);
 }
 
+/**
+ *	ata_ncq_complete - NCQ driver helper.  Complete requests normally.
+ *	@ap: port in question
+ *	@sactive: current SActive value
+ *
+ *	Complete in-flight commands.  One device per port is assumed.
+ *	This functions is meant to be called from low-level driver's
+ *	interrupt routine to complete requests normally.  On
+ *	invocation, if non-NCQ command was in-flight, it's completed
+ *	normally.  If NCQ commands were in-flight, cached ap->sactive
+ *	and new @sactive is compared and commands are completed
+ *	accordingly.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Number of completed commands on success, -errno otherwise.
+ */
+int ata_ncq_complete(struct ata_port *ap, u32 sactive)
+{
+	int nr_done = 0;
+	unsigned long done_mask = 0;
+	int i;
+
+	if (ap->sactive) {
+		done_mask = ap->sactive ^ sactive;
+
+		if (unlikely(done_mask & sactive)) {
+			printk(KERN_ERR "ata%u: illegal sactive transition "
+			       "(%08x->%08x)\n", ap->id, ap->sactive, sactive);
+			return -EINVAL;
+		}
+	} else if (ap->active_tag != ATA_TAG_POISON)
+		done_mask = 1 << ap->active_tag;
+
+	for (i = 0; i < ATA_MAX_QUEUE; i++) {
+		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, i);
+		if (done_mask & (1 << i) && qc) {
+			ata_qc_complete(qc);
+			nr_done++;
+		}
+	}
+
+	return nr_done;
+}
 
 /*
  * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
@@ -5300,6 +5346,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_slave_config)
 EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
+EXPORT_SYMBOL_GPL(ata_ncq_complete);
 EXPORT_SYMBOL_GPL(ata_id_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 9ae1f03..b9abfb3 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -580,6 +580,7 @@ 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_ncq_complete(struct ata_port *ap, u32 sactive);
 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_port *, struct ata_device *);
-- 
1.2.4



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

* [PATCH 09/14] libata: implement NCQ device configuration
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
  2006-04-03  8:32 ` [PATCH 05/14] libata: implement command exclusion Tejun Heo
  2006-04-03  8:32 ` [PATCH 08/14] libata: update EH to handle NCQ Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 06/14] libata: implement NCQ command translation Tejun Heo
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Now that all NCQ related issue, processing and EH stuff are in place,
implement NCQ device configuration and bump ATA_MAX_QUEUE to 32 thus
activating NCQ support.

Original implementation if from Jens Axboe.

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

---

 drivers/scsi/libata-core.c |   30 ++++++++++++++++++++++++++--
 drivers/scsi/libata-scsi.c |   48 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    4 +++-
 3 files changed, 79 insertions(+), 3 deletions(-)

c8155294899ef8ed64d845a08ad6da4219ac9561
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index cc45cfc..56637f0 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1243,6 +1243,27 @@ static inline u8 ata_dev_knobble(const s
 	return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
 }
 
+static void ata_dev_config_ncq(struct ata_port *ap, struct ata_device *dev,
+			       char *desc, size_t desc_sz)
+{
+	int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+
+	if (!ata_id_has_ncq(dev->id)) {
+		desc[0] = '\0';
+		return;
+	}
+
+	if (ap->flags & ATA_FLAG_NCQ) {
+		hdepth = min(ap->host->can_queue, ATA_MAX_QUEUE - 1);
+		dev->flags |= ATA_DFLAG_NCQ;
+	}
+
+	if (hdepth >= ddepth)
+		snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+	else
+		snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
+}
+
 /**
  *	ata_dev_configure - Configure the specified ATA/ATAPI device
  *	@ap: Port on which target device resides
@@ -1304,6 +1325,7 @@ static int ata_dev_configure(struct ata_
 
 		if (ata_id_has_lba(id)) {
 			const char *lba_desc;
+			char ncq_desc[20];
 
 			lba_desc = "LBA";
 			dev->flags |= ATA_DFLAG_LBA;
@@ -1312,15 +1334,18 @@ static int ata_dev_configure(struct ata_
 				lba_desc = "LBA48";
 			}
 
+			/* config NCQ */
+			ata_dev_config_ncq(ap, dev, ncq_desc, sizeof(ncq_desc));
+
 			/* print device info to dmesg */
 			if (print_info)
 				printk(KERN_INFO "ata%u: dev %u ATA-%d, "
-				       "max %s, %Lu sectors: %s\n",
+				       "max %s, %Lu sectors: %s %s\n",
 				       ap->id, dev->devno,
 				       ata_id_major_version(id),
 				       ata_mode_string(xfer_mask),
 				       (unsigned long long)dev->n_sectors,
-				       lba_desc);
+				       lba_desc, ncq_desc);
 		} else {
 			/* CHS */
 
@@ -5272,6 +5297,7 @@ EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(ata_id_string);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index d5748b1..b19fc74 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -41,6 +41,7 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_request.h>
+#include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport.h>
 #include <linux/libata.h>
 #include <linux/hdreg.h>
@@ -679,6 +680,14 @@ static void ata_scsi_dev_config(struct s
 		request_queue_t *q = sdev->request_queue;
 		blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
 	}
+
+	if (dev->flags & ATA_DFLAG_NCQ) {
+		int depth;
+
+		depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+		depth = min(ATA_MAX_QUEUE - 1, depth);
+		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
+	}
 }
 
 /**
@@ -713,6 +722,45 @@ int ata_scsi_slave_config(struct scsi_de
 }
 
 /**
+ *	ata_scsi_change_queue_depth - SCSI callback for queue depth config
+ *	@sdev: SCSI device to configure queue depth for
+ *	@queue_depth: new queue depth
+ *
+ *	This is libata standard hostt->change_queue_depth callback.
+ *	SCSI will call into this callback when user tries to set queue
+ *	depth via sysfs.
+ *
+ *	LOCKING:
+ *	SCSI layer (we don't care)
+ *
+ *	RETURNS:
+ *	Newly configured queue depth.
+ */
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+	struct ata_port *ap;
+	struct ata_device *dev;
+	int max_depth;
+
+	if (sdev->id >= ATA_MAX_DEVICES || queue_depth < 1)
+		return sdev->queue_depth;
+
+	ap = (struct ata_port *) &sdev->host->hostdata[0];
+	dev = &ap->device[sdev->id];
+
+	if (!ata_dev_enabled(dev))
+		return sdev->queue_depth;
+
+	max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+	max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
+	if (queue_depth > max_depth)
+		queue_depth = max_depth;
+
+	scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+	return queue_depth;
+}
+
+/**
  *	ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
  *	@qc: Storage for translated ATA taskfile
  *	@scsicmd: SCSI command to translate
diff --git a/include/linux/libata.h b/include/linux/libata.h
index f3f6f50..9ae1f03 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -109,7 +109,7 @@ enum {
 	ATA_MAX_PORTS		= 8,
 	ATA_DEF_QUEUE		= 1,
 	/* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */
-	ATA_MAX_QUEUE		= 2,
+	ATA_MAX_QUEUE		= 32,
 	ATA_TAG_INTERNAL	= ATA_MAX_QUEUE - 1,
 	ATA_MAX_SECTORS		= 200,	/* FIXME */
 	ATA_MAX_BUS		= 2,
@@ -640,6 +640,8 @@ extern int ata_std_bios_param(struct scs
 			      struct block_device *bdev,
 			      sector_t capacity, int geom[]);
 extern int ata_scsi_slave_config(struct scsi_device *sdev);
+extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
+				       int queue_depth);
 extern struct ata_device *ata_dev_pair(struct ata_port *ap, 
 				       struct ata_device *adev);
 
-- 
1.2.4



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

* [PATCH 11/14] libata: clean up AHCI constants in preparation for NCQ
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (9 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 04/14] libata: implement ap->sactive Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 12/14] ahci: add HOST_CAP_NCQ constant Tejun Heo
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

* Rename CMD_TBL_HDR to CMD_TBL_HDR_SZ as it's size not offset.

* Define MAX_CMDS and CMD_SZ and use them in calculation of other
  constants.

* Define CMD_TBL_AR_SZ as product of CMD_TBL_SZ and MAX_CMDS, and use
  it when calculating PRIV_DMA_SZ.

* CMD_SLOT_SZ is also dependent on MAX_CMDS but hasn't been changed
  because I didn't want to change the value used by the original code
  (32 commands).  Later NCQ change will bump MAX_CMDS to 32 anyway and
  the hard coded 32 can be changed to MAX_CMDS then.

* Reorder HOST_CAP_* flags.

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

---

 drivers/scsi/ahci.c |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)

82ed365bb9a6628a1fbf1a2d3bba240dc5a88069
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 3dad10f..c01e58a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -56,12 +56,15 @@ enum {
 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
 	AHCI_DMA_BOUNDARY	= 0xffffffff,
 	AHCI_USE_CLUSTERING	= 0,
-	AHCI_CMD_SLOT_SZ	= 32 * 32,
+	AHCI_MAX_CMDS		= 1,
+	AHCI_CMD_SZ		= 32,
+	AHCI_CMD_SLOT_SZ	= 32 * AHCI_CMD_SZ,
 	AHCI_RX_FIS_SZ		= 256,
-	AHCI_CMD_TBL_HDR	= 0x80,
 	AHCI_CMD_TBL_CDB	= 0x40,
-	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
-	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
+	AHCI_CMD_TBL_HDR_SZ	= 0x80,
+	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
+	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
 				  AHCI_RX_FIS_SZ,
 	AHCI_IRQ_ON_SG		= (1 << 31),
 	AHCI_CMD_ATAPI		= (1 << 5),
@@ -88,8 +91,8 @@ enum {
 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
 
 	/* HOST_CAP bits */
-	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
+	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
 
 	/* registers for each SATA port */
 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
@@ -381,7 +384,7 @@ static int ahci_port_start(struct ata_po
 	pp->cmd_tbl = mem;
 	pp->cmd_tbl_dma = mem_dma;
 
-	pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR;
+	pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR_SZ;
 
 	ap->private_data = pp;
 
-- 
1.2.4



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

* [PATCH 12/14] ahci: add HOST_CAP_NCQ constant
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (10 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 11/14] libata: clean up AHCI constants in preparation for NCQ Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 13/14] ahci: kill pp->cmd_tbl_sg Tejun Heo
  2006-04-03  8:32 ` [PATCH 14/14] ahci: implement NCQ suppport Tejun Heo
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Add HOST_CAP_NCQ.

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

---

 drivers/scsi/ahci.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

daf357752b747466ef5f6e6ddd1cbfb76049de1c
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index c01e58a..bd4faa1 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -92,6 +92,7 @@ enum {
 
 	/* HOST_CAP bits */
 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
+	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
 
 	/* registers for each SATA port */
-- 
1.2.4



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

* [PATCH 14/14] ahci: implement NCQ suppport
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (12 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 13/14] ahci: kill pp->cmd_tbl_sg Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

Implement NCQ support.

Original implementation is from Jens Axboe.

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

---

 drivers/scsi/ahci.c |   82 ++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 54 insertions(+), 28 deletions(-)

4d81afc6685879024602ce293215a70a3fe0a441
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 8201a06..fb89fca 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -56,9 +56,9 @@ enum {
 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
 	AHCI_DMA_BOUNDARY	= 0xffffffff,
 	AHCI_USE_CLUSTERING	= 0,
-	AHCI_MAX_CMDS		= 1,
+	AHCI_MAX_CMDS		= 32,
 	AHCI_CMD_SZ		= 32,
-	AHCI_CMD_SLOT_SZ	= 32 * AHCI_CMD_SZ,
+	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
 	AHCI_RX_FIS_SZ		= 256,
 	AHCI_CMD_TBL_CDB	= 0x40,
 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
@@ -216,7 +216,8 @@ static struct scsi_host_template ahci_sh
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
-	.can_queue		= ATA_DEF_QUEUE,
+	.change_queue_depth	= ata_scsi_change_queue_depth,
+	.can_queue		= AHCI_MAX_CMDS - 1,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= AHCI_MAX_SG,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
@@ -516,12 +517,17 @@ static unsigned int ahci_dev_classify(st
 	return ata_dev_classify(&tf);
 }
 
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+			       u32 opts)
 {
-	pp->cmd_slot[0].opts = cpu_to_le32(opts);
-	pp->cmd_slot[0].status = 0;
-	pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
-	pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+	dma_addr_t cmd_tbl_dma;
+
+	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
+
+	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
+	pp->cmd_slot[tag].status = 0;
+	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
+	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
 static int ahci_poll_register(void __iomem *reg, u32 mask, u32 val,
@@ -600,7 +606,8 @@ static int ahci_softreset(struct ata_por
 	fis = pp->cmd_tbl;
 
 	/* issue the first D2H Register FIS */
-	ahci_fill_cmd_slot(pp, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+	ahci_fill_cmd_slot(pp, 0,
+			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
 
 	tf.ctl |= ATA_SRST;
 	ata_tf_to_fis(&tf, fis, 0);
@@ -619,7 +626,7 @@ static int ahci_softreset(struct ata_por
 	msleep(1);
 
 	/* issue the second D2H Register FIS */
-	ahci_fill_cmd_slot(pp, cmd_fis_len);
+	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
 
 	tf.ctl &= ~ATA_SRST;
 	ata_tf_to_fis(&tf, fis, 0);
@@ -722,9 +729,8 @@ static void ahci_tf_read(struct ata_port
 	ata_tf_from_fis(d2h_fis, tf);
 }
 
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
 {
-	struct ahci_port_priv *pp = qc->ap->private_data;
 	struct scatterlist *sg;
 	struct ahci_sg *ahci_sg;
 	unsigned int n_sg = 0;
@@ -734,7 +740,7 @@ static unsigned int ahci_fill_sg(struct 
 	/*
 	 * Next, the S/G list.
 	 */
-	ahci_sg = pp->cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
 	ata_for_each_sg(sg, qc) {
 		dma_addr_t addr = sg_dma_address(sg);
 		u32 sg_len = sg_dma_len(sg);
@@ -755,6 +761,7 @@ static void ahci_qc_prep(struct ata_queu
 	struct ata_port *ap = qc->ap;
 	struct ahci_port_priv *pp = ap->private_data;
 	int is_atapi = is_atapi_taskfile(&qc->tf);
+	void *cmd_tbl;
 	u32 opts;
 	const u32 cmd_fis_len = 5; /* five dwords */
 	unsigned int n_elem;
@@ -763,16 +770,17 @@ static void ahci_qc_prep(struct ata_queu
 	 * Fill in command table information.  First, the header,
 	 * a SATA Register - Host to Device command FIS.
 	 */
-	ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
+	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
 	if (is_atapi) {
-		memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
-		memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
-		       qc->dev->cdb_len);
+		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
 	}
 
 	n_elem = 0;
 	if (qc->flags & ATA_QCFLAG_DMAMAP)
-		n_elem = ahci_fill_sg(qc);
+		n_elem = ahci_fill_sg(qc, cmd_tbl);
 
 	/*
 	 * Fill in command slot information.
@@ -783,7 +791,7 @@ static void ahci_qc_prep(struct ata_queu
 	if (is_atapi)
 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
-	ahci_fill_cmd_slot(pp, opts);
+	ahci_fill_cmd_slot(pp, qc->tag, opts);
 }
 
 static unsigned int ahci_eh_autopsy(struct ata_port *ap,
@@ -863,7 +871,7 @@ static void ahci_error_handler(struct at
 	}
 
 	/* perform recovery */
-	qc = ata_eh_determine_qc(ap, 0, &tf);
+	qc = ata_eh_determine_qc(ap, irq_stat & PORT_IRQ_TF_ERR, &tf);
 
 	action |= ahci_eh_autopsy(ap, qc, irq_stat, desc, sizeof(desc));
 	action |= ata_eh_autopsy(ap, qc, &tf, serror);
@@ -893,10 +901,11 @@ static void ahci_post_internal_cmd(struc
 
 static inline int ahci_host_intr(struct ata_port *ap)
 {
+	static int spurious_cnt = 10;
 	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);
-	u32 status, serror, ci;
+	u32 status, sactive, serror, ci;
 	unsigned int eh_flags;
 
 	status = readl(port_mmio + PORT_IRQ_STAT);
@@ -914,18 +923,28 @@ static inline int ahci_host_intr(struct 
 	if (!(status & PORT_IRQ_ERROR)) {
 		struct ata_queued_cmd *qc;
 
-		if ((qc = ata_qc_from_tag(ap, ap->active_tag))) {
+		if (ap->sactive) {
+			sactive = readl(port_mmio + PORT_SCR_ACT);
+			if (ata_ncq_complete(ap, sactive))
+				return 1;
+		} else if ((qc = ata_qc_from_tag(ap, ap->active_tag))) {
 			ci = readl(port_mmio + PORT_CMD_ISSUE);
-			if ((ci & 0x1) == 0) {
+			if ((ci & (1 << qc->tag)) == 0) {
 				ata_qc_complete(qc);
 				return 1;
 			}
 		}
 
-		if (ata_ratelimit())
+		/* Some drives spuriously generate D2H FISes w/ I bit
+		 * set during NCQ command phase.
+		 */
+		if (spurious_cnt && ata_ratelimit()) {
+			spurious_cnt--;
 			printk(KERN_INFO "ata%u: spurious interrupt "
-			       "(irq_stat 0x%x active_tag %d)\n",
-			       ap->id, status, ap->active_tag);
+			       "(irq_stat 0x%x active_tag %d sactive 0x%x%s)\n",
+			       ap->id, status, ap->active_tag, ap->sactive,
+			       spurious_cnt ? "" : ", shutting up");
+		}
 
 		return 1;
 	}
@@ -951,7 +970,7 @@ static void ahci_irq_clear(struct ata_po
 	/* TODO */
 }
 
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
 	struct ahci_host_priv *hpriv;
@@ -1014,7 +1033,9 @@ static unsigned int ahci_qc_issue(struct
 	struct ata_port *ap = qc->ap;
 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 
-	writel(1, port_mmio + PORT_CMD_ISSUE);
+	if (qc->tf.protocol == ATA_PROT_NCQ)
+		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
 
 	return 0;
@@ -1264,6 +1285,8 @@ static int ahci_init_one (struct pci_dev
 
 	VPRINTK("ENTER\n");
 
+	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
@@ -1331,6 +1354,9 @@ static int ahci_init_one (struct pci_dev
 	if (rc)
 		goto err_out_hpriv;
 
+	if (hpriv->cap & HOST_CAP_NCQ)
+		probe_ent->host_flags |= ATA_FLAG_NCQ;
+
 	ahci_print_info(probe_ent);
 
 	/* FIXME: check ata_device_add return value */
-- 
1.2.4



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

* [PATCH 13/14] ahci: kill pp->cmd_tbl_sg
  2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
                   ` (11 preceding siblings ...)
  2006-04-03  8:32 ` [PATCH 12/14] ahci: add HOST_CAP_NCQ constant Tejun Heo
@ 2006-04-03  8:32 ` Tejun Heo
  2006-04-03  8:32 ` [PATCH 14/14] ahci: implement NCQ suppport Tejun Heo
  13 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2006-04-03  8:32 UTC (permalink / raw)
  To: jgarzik, alan, albertcc, axboe, linux-ide; +Cc: Tejun Heo

With NCQ, there are multiple sg tables, so pp->cmd_tbl_sg doesn't cut
it.  Directly calculate sg table address from pp->cmd_tbl.

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

---

 drivers/scsi/ahci.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

53bd8cc0f4d783cfeb2ba226e61ba58d4534d330
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index bd4faa1..8201a06 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -187,7 +187,6 @@ struct ahci_port_priv {
 	dma_addr_t		cmd_slot_dma;
 	void			*cmd_tbl;
 	dma_addr_t		cmd_tbl_dma;
-	struct ahci_sg		*cmd_tbl_sg;
 	void			*rx_fis;
 	dma_addr_t		rx_fis_dma;
 	/* register values stored by interrupt handler for EH */
@@ -385,8 +384,6 @@ static int ahci_port_start(struct ata_po
 	pp->cmd_tbl = mem;
 	pp->cmd_tbl_dma = mem_dma;
 
-	pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR_SZ;
-
 	ap->private_data = pp;
 
 	if (hpriv->cap & HOST_CAP_64)
@@ -737,7 +734,7 @@ static unsigned int ahci_fill_sg(struct 
 	/*
 	 * Next, the S/G list.
 	 */
-	ahci_sg = pp->cmd_tbl_sg;
+	ahci_sg = pp->cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
 	ata_for_each_sg(sg, qc) {
 		dma_addr_t addr = sg_dma_address(sg);
 		u32 sg_len = sg_dma_len(sg);
-- 
1.2.4



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

end of thread, other threads:[~2006-04-03  8:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-03  8:32 [PATCHSET] libata: add NCQ support Tejun Heo
2006-04-03  8:32 ` [PATCH 05/14] libata: implement command exclusion Tejun Heo
2006-04-03  8:32 ` [PATCH 08/14] libata: update EH to handle NCQ Tejun Heo
2006-04-03  8:32 ` [PATCH 09/14] libata: implement NCQ device configuration Tejun Heo
2006-04-03  8:32 ` [PATCH 06/14] libata: implement NCQ command translation Tejun Heo
2006-04-03  8:32 ` [PATCH 03/14] libata: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
2006-04-03  8:32 ` [PATCH 02/14] libata: add NCQ related libata flags Tejun Heo
2006-04-03  8:32 ` [PATCH 01/14] libata: add NCQ related ATA constants and id macros Tejun Heo
2006-04-03  8:32 ` [PATCH 07/14] libata: implement ata_eh_read_log_10h() Tejun Heo
2006-04-03  8:32 ` [PATCH 10/14] libata: implement ata_ncq_complete() Tejun Heo
2006-04-03  8:32 ` [PATCH 04/14] libata: implement ap->sactive Tejun Heo
2006-04-03  8:32 ` [PATCH 11/14] libata: clean up AHCI constants in preparation for NCQ Tejun Heo
2006-04-03  8:32 ` [PATCH 12/14] ahci: add HOST_CAP_NCQ constant Tejun Heo
2006-04-03  8:32 ` [PATCH 13/14] ahci: kill pp->cmd_tbl_sg Tejun Heo
2006-04-03  8:32 ` [PATCH 14/14] ahci: implement NCQ suppport 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).