* [PATCH 04/15] libata-ncq: implement ap->sactive
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (5 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 02/15] libata-ncq: add NCQ related libata flags Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 11/15] ahci: clean up AHCI constants in preparation for NCQ Tejun Heo
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
29972b1500568aeb7a6dbb681192af3e90d988be
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index ac79c5c..7dc668c 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -985,6 +985,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;
@@ -1020,7 +1021,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;
@@ -1082,6 +1085,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
@@ -4212,6 +4216,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)
@@ -4311,7 +4321,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 c9dfc7d..b194f3f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -452,6 +452,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] 17+ messages in thread
* [PATCHSET 7/9] add NCQ support, take 2
@ 2006-04-11 13:53 Tejun Heo
2006-04-11 13:53 ` [PATCH 03/15] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
` (15 more replies)
0 siblings, 16 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, linux-ide, htejun
Hello, again.
This is the second take of add-NCQ-support patchset. Changes from the
last take[L] are...
* ahci autopsy result is used to determine use_log_10h
* sata_sil24 NCQ support added
This patchset is against
upstream (c2a6585296009379e0f4eff39cdcb108b457ebf2)
+ [1] misc-reset-updates patchset (repost)
+ [2] implement-and-use-ata_wait_register patchset (repost)
+ [3] misc-ata_bus_probe-updates patchset
+ [4] fixes-errata-workaround-and-reset-updates patchset, take 2
+ [5] implement-scsi_eh_schedule patchset
+ [6] fix scsi_kill_request() busy count handling patch
+ [7] new-EH-framework patchset, take 2
+ [8] new-EH-implementation patchset, take 2
Thanks.
--
tejun
[L] http://article.gmane.org/gmane.linux.ide/9355
[1] http://article.gmane.org/gmane.linux.ide/9495
[2] http://article.gmane.org/gmane.linux.ide/9499
[3] http://article.gmane.org/gmane.linux.ide/9506
[4] http://article.gmane.org/gmane.linux.ide/9516
[5] http://article.gmane.org/gmane.linux.ide/9290
[6] http://article.gmane.org/gmane.linux.ide/9487
[7] http://article.gmane.org/gmane.linux.ide/9524
[8] http://article.gmane.org/gmane.linux.ide/9540
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 07/15] libata-ncq: implement ata_eh_read_log_10h()
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
2006-04-11 13:53 ` [PATCH 03/15] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
2006-04-11 13:53 ` [PATCH 06/15] libata-ncq: implement NCQ command translation Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 05/15] libata-ncq: implement command exclusion Tejun Heo
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
ad48d9c5999b24b4ed71e6a2dd9cf1ff20aa90d9
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 0d8a9cb..795f580 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -560,6 +560,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] 17+ messages in thread
* [PATCH 02/15] libata-ncq: add NCQ related libata flags
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (4 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 01/15] libata-ncq: add NCQ related ATA constants and id macros Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 04/15] libata-ncq: implement ap->sactive Tejun Heo
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
b54166188991cd72df9e174b31692081237ba72c
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 603d800..c9dfc7d 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -123,6 +123,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 */
@@ -149,6 +150,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] 17+ messages in thread
* [PATCH 01/15] libata-ncq: add NCQ related ATA constants and id macros
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (3 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 05/15] libata-ncq: implement command exclusion Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 02/15] libata-ncq: add NCQ related libata flags Tejun Heo
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
5d6abbcdeb6bcb7eb9e427e1d84aa41f39dd22f9
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] 17+ messages in thread
* [PATCH 03/15] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 06/15] libata-ncq: implement NCQ command translation Tejun Heo
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
3fd6c2e278004c2fddf09099560b9630a352fba4
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 1c1b510..c978a5d 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;
}
/**
@@ -2459,19 +2462,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;
}
/**
@@ -2490,15 +2497,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];
@@ -2509,7 +2517,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);
@@ -2517,7 +2525,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] 17+ messages in thread
* [PATCH 05/15] libata-ncq: implement command exclusion
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (2 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 07/15] libata-ncq: implement ata_eh_read_log_10h() Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 01/15] libata-ncq: add NCQ related ATA constants and id macros Tejun Heo
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
7f78182953826cfcd2c9b0a7d897e01f6724cb6b
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index c978a5d..00cb9ca 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] 17+ messages in thread
* [PATCH 06/15] libata-ncq: implement NCQ command translation
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
2006-04-11 13:53 ` [PATCH 03/15] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 07/15] libata-ncq: implement ata_eh_read_log_10h() Tejun Heo
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
d3819d03d822cf98a8b932fde42fcdc3e553edb1
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 7dc668c..8e90aa0 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4287,6 +4287,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 00cb9ca..fdc95f1 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] 17+ messages in thread
* [PATCH 15/15] sata_sil24: implement NCQ support
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (8 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 12/15] ahci: add HOST_CAP_NCQ constant Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 10/15] libata-ncq: implement ata_ncq_complete() Tejun Heo
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, linux-ide; +Cc: Tejun Heo
Implement NCQ support. Sil24 has 31 command slots and all of them are
used for NCQ command queueing. libata guarantees that no other
command is in progress when it issues an internal command, so always
use tag 0 for internal commands.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/sata_sil24.c | 79 +++++++++++++++++++++++++++++++++------------
1 files changed, 58 insertions(+), 21 deletions(-)
83fbbc40a0cca8a044f50d6097fe819cfb11b750
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index c2c5ed9..6a7ea97 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -217,6 +217,8 @@ enum {
SGE_DRD = (1 << 29), /* discard data read (/dev/null)
data address ignored */
+ SIL24_MAX_CMDS = 31,
+
/* board id */
BID_SIL3124 = 0,
BID_SIL3132 = 1,
@@ -224,7 +226,8 @@ enum {
/* host flags */
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_NCQ,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
IRQ_STAT_4PORTS = 0xf,
@@ -358,6 +361,8 @@ static struct scsi_host_template sil24_s
.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 = SIL24_MAX_CMDS,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
@@ -666,14 +671,21 @@ static void sil24_qc_prep(struct ata_que
{
struct ata_port *ap = qc->ap;
struct sil24_port_priv *pp = ap->private_data;
- union sil24_cmd_block *cb = pp->cmd_block + qc->tag;
+ unsigned int tag;
+ union sil24_cmd_block *cb;
struct sil24_prb *prb;
struct sil24_sge *sge;
u16 ctrl = 0;
+ tag = qc->tag;
+ if (unlikely(ata_tag_internal(tag)))
+ tag = 0;
+ cb = &pp->cmd_block[tag];
+
switch (qc->tf.protocol) {
case ATA_PROT_PIO:
case ATA_PROT_DMA:
+ case ATA_PROT_NCQ:
case ATA_PROT_NODATA:
prb = &cb->ata.prb;
sge = cb->ata.sge;
@@ -711,12 +723,21 @@ static void sil24_qc_prep(struct ata_que
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
- dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block);
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *activate;
+ unsigned int tag;
+ dma_addr_t paddr;
+
+ tag = qc->tag;
+ if (unlikely(ata_tag_internal(tag)))
+ tag = 0;
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+ paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
+ activate = port + PORT_CMD_ACTIVATE + tag * 8;
+
+ writel((u32)paddr, activate);
+ writel((u64)paddr >> 32, activate + 4);
return 0;
}
@@ -821,7 +842,7 @@ static void sil24_error_handler(struct a
/* perform recovery */
action |= sil24_eh_autopsy(ap, irq_stat, &err_mask, desc, sizeof(desc));
- qc = ata_eh_determine_qc(ap, 0, &tf);
+ qc = ata_eh_determine_qc(ap, err_mask & AC_ERR_DEV, &tf);
if (qc)
qc->err_mask |= err_mask;
@@ -846,7 +867,6 @@ static void sil24_post_internal_cmd(stru
static inline void sil24_host_intr(struct ata_port *ap)
{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
u32 slot_stat, irq_stat;
@@ -857,18 +877,35 @@ static inline void sil24_host_intr(struc
if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
- /* !HOST_SSAT_ATTN guarantees successful completion,
- * so reading back tf registers is unnecessary for
- * most commands. TODO: read tf registers for
- * commands which require these values on successful
- * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER,
- * DEVICE RESET and READ PORT MULTIPLIER (any more?).
- */
- sil24_update_tf(ap);
+ if (ap->sactive) {
+ if (ata_ncq_complete(ap, slot_stat & ~HOST_SSTAT_ATTN))
+ return;
+ } else {
+ struct ata_queued_cmd *qc;
+
+ /* !HOST_SSAT_ATTN guarantees successful
+ * completion, so reading back tf registers is
+ * unnecessary for most commands. TODO: read
+ * tf registers for commands which require
+ * these values on successful completion
+ * (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER,
+ * DEVICE RESET and READ PORT MULTIPLIER (any
+ * more?).
+ */
+ sil24_update_tf(ap);
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ qc->err_mask |= ac_err_mask(pp->tf.command);
+ ata_qc_complete(qc);
+ return;
+ }
+ }
- if (qc) {
- qc->err_mask |= ac_err_mask(pp->tf.command);
- ata_qc_complete(qc);
+ if (ata_ratelimit()) {
+ printk(KERN_INFO "ata%u: spurious interrupt "
+ "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+ ap->id, slot_stat, ap->active_tag, ap->sactive);
}
return;
@@ -926,7 +963,7 @@ static irqreturn_t sil24_interrupt(int i
static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
{
- const size_t cb_size = sizeof(*pp->cmd_block);
+ const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
}
@@ -936,7 +973,7 @@ static int sil24_port_start(struct ata_p
struct device *dev = ap->host_set->dev;
struct sil24_port_priv *pp;
union sil24_cmd_block *cb;
- size_t cb_size = sizeof(*cb);
+ size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
dma_addr_t cb_dma;
int rc = -ENOMEM;
--
1.2.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 14/15] ahci: implement NCQ suppport
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (10 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 10/15] libata-ncq: implement ata_ncq_complete() Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 08/15] libata-ncq: update EH to handle NCQ Tejun Heo
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
67b28600437cd9e5c4b55527f73a3be049064a2d
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 027fea1..3f1fd7c 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_softreset(struct ata_port *ap, unsigned int *class)
@@ -581,7 +587,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);
@@ -600,7 +607,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);
@@ -700,9 +707,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;
@@ -712,7 +718,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);
@@ -733,6 +739,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;
@@ -741,16 +748,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.
@@ -761,7 +769,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, u32 irq_stat,
@@ -846,7 +854,7 @@ static void ahci_error_handler(struct at
/* perform recovery */
action |= ahci_eh_autopsy(ap, irq_stat, &err_mask, desc, sizeof(desc));
- qc = ata_eh_determine_qc(ap, 0, &tf);
+ qc = ata_eh_determine_qc(ap, err_mask & AC_ERR_DEV, &tf);
if (qc)
qc->err_mask |= err_mask;
@@ -873,10 +881,11 @@ static void ahci_post_internal_cmd(struc
static inline void 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);
@@ -900,18 +909,28 @@ static inline void 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;
+ } 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;
}
}
- 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;
}
@@ -935,7 +954,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;
@@ -993,7 +1012,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;
@@ -1243,6 +1264,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");
@@ -1310,6 +1333,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] 17+ messages in thread
* [PATCH 10/15] libata-ncq: implement ata_ncq_complete()
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (9 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 15/15] sata_sil24: implement NCQ support Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 14/15] ahci: implement NCQ suppport Tejun Heo
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
99b30184e83c4f6b32e604d792af8ae45f12815a
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 0158b5f..d49d4c7 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4589,6 +4589,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,
@@ -5363,6 +5409,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 0413c7b..e86d63c 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -581,6 +581,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] 17+ messages in thread
* [PATCH 09/15] libata-ncq: implement NCQ device configuration
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (13 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 13/15] ahci: kill pp->cmd_tbl_sg Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-27 9:11 ` [PATCHSET 7/9] add NCQ support, take 2 Jeff Garzik
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
7b8a0fd4e490e83258185c96e2ec80aa9657f097
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 8e90aa0..0158b5f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1258,6 +1258,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
@@ -1319,6 +1340,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;
@@ -1327,15 +1349,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 */
@@ -5335,6 +5360,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 fdc95f1..5f81136 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 d463156..0413c7b 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -108,7 +108,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,
@@ -644,6 +644,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] 17+ messages in thread
* [PATCH 11/15] ahci: clean up AHCI constants in preparation for NCQ
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (6 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 04/15] libata-ncq: implement ap->sactive Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 12/15] ahci: add HOST_CAP_NCQ constant Tejun Heo
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
6493b186a1b012e7a8cc76467d06c6b3701ace3a
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index f3d117e..405d4da 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] 17+ messages in thread
* [PATCH 12/15] ahci: add HOST_CAP_NCQ constant
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (7 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 11/15] ahci: clean up AHCI constants in preparation for NCQ Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 15/15] sata_sil24: implement NCQ support Tejun Heo
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
868de01742b3cf25a5b053269737196690a75e53
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 405d4da..375857b 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] 17+ messages in thread
* [PATCH 13/15] ahci: kill pp->cmd_tbl_sg
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (12 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 08/15] libata-ncq: update EH to handle NCQ Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 09/15] libata-ncq: implement NCQ device configuration Tejun Heo
2006-04-27 9:11 ` [PATCHSET 7/9] add NCQ support, take 2 Jeff Garzik
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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(-)
54c5e95cb986b8045d510cb62d2f89376ffcbc30
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 375857b..027fea1 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)
@@ -715,7 +712,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] 17+ messages in thread
* [PATCH 08/15] libata-ncq: update EH to handle NCQ
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (11 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 14/15] ahci: implement NCQ suppport Tejun Heo
@ 2006-04-11 13:53 ` Tejun Heo
2006-04-11 13:53 ` [PATCH 13/15] ahci: kill pp->cmd_tbl_sg Tejun Heo
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2006-04-11 13:53 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, lkosewsk, 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 +++++++++++++++++++++++++++++++++++++++++--
drivers/scsi/sata_sil24.c | 2 +
include/linux/libata.h | 1 +
5 files changed, 80 insertions(+), 6 deletions(-)
80d986bf527942c9a6188b258b15e2f5667678ff
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 67950ee..f3d117e 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -845,7 +845,7 @@ static void ahci_error_handler(struct at
/* perform recovery */
action |= ahci_eh_autopsy(ap, irq_stat, &err_mask, desc, sizeof(desc));
- qc = ata_eh_determine_qc(ap, &tf);
+ qc = ata_eh_determine_qc(ap, 0, &tf);
if (qc)
qc->err_mask |= err_mask;
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 795f580..1a87bce 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -669,6 +669,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
@@ -681,12 +682,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;
}
/**
@@ -1018,11 +1072,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);
}
@@ -1247,7 +1301,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)) {
@@ -1275,4 +1331,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/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index bbbc18a..c2c5ed9 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -821,7 +821,7 @@ static void sil24_error_handler(struct a
/* perform recovery */
action |= sil24_eh_autopsy(ap, irq_stat, &err_mask, desc, sizeof(desc));
- qc = ata_eh_determine_qc(ap, &tf);
+ qc = ata_eh_determine_qc(ap, 0, &tf);
if (qc)
qc->err_mask |= err_mask;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b194f3f..d463156 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -700,6 +700,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] 17+ messages in thread
* Re: [PATCHSET 7/9] add NCQ support, take 2
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
` (14 preceding siblings ...)
2006-04-11 13:53 ` [PATCH 09/15] libata-ncq: implement NCQ device configuration Tejun Heo
@ 2006-04-27 9:11 ` Jeff Garzik
15 siblings, 0 replies; 17+ messages in thread
From: Jeff Garzik @ 2006-04-27 9:11 UTC (permalink / raw)
To: Tejun Heo; +Cc: alan, axboe, albertcc, lkosewsk, linux-ide
Tejun Heo wrote:
> Hello, again.
>
> This is the second take of add-NCQ-support patchset. Changes from the
> last take[L] are...
>
> * ahci autopsy result is used to determine use_log_10h
>
> * sata_sil24 NCQ support added
I've skipped ahead in the review order a bit, to this patchset. Its
fairly straightforward, so I ACK all 15 patches.
I'm worried cruft still remains related to ATA_MAX_QUEUE, but its a
vague worry. ATA_MAX_QUEUE magically changes a bunch of allocations
and loops, when changed, and I didn't take the time to audit each use.
Jeff
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2006-04-27 9:11 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-11 13:53 [PATCHSET 7/9] add NCQ support, take 2 Tejun Heo
2006-04-11 13:53 ` [PATCH 03/15] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
2006-04-11 13:53 ` [PATCH 06/15] libata-ncq: implement NCQ command translation Tejun Heo
2006-04-11 13:53 ` [PATCH 07/15] libata-ncq: implement ata_eh_read_log_10h() Tejun Heo
2006-04-11 13:53 ` [PATCH 05/15] libata-ncq: implement command exclusion Tejun Heo
2006-04-11 13:53 ` [PATCH 01/15] libata-ncq: add NCQ related ATA constants and id macros Tejun Heo
2006-04-11 13:53 ` [PATCH 02/15] libata-ncq: add NCQ related libata flags Tejun Heo
2006-04-11 13:53 ` [PATCH 04/15] libata-ncq: implement ap->sactive Tejun Heo
2006-04-11 13:53 ` [PATCH 11/15] ahci: clean up AHCI constants in preparation for NCQ Tejun Heo
2006-04-11 13:53 ` [PATCH 12/15] ahci: add HOST_CAP_NCQ constant Tejun Heo
2006-04-11 13:53 ` [PATCH 15/15] sata_sil24: implement NCQ support Tejun Heo
2006-04-11 13:53 ` [PATCH 10/15] libata-ncq: implement ata_ncq_complete() Tejun Heo
2006-04-11 13:53 ` [PATCH 14/15] ahci: implement NCQ suppport Tejun Heo
2006-04-11 13:53 ` [PATCH 08/15] libata-ncq: update EH to handle NCQ Tejun Heo
2006-04-11 13:53 ` [PATCH 13/15] ahci: kill pp->cmd_tbl_sg Tejun Heo
2006-04-11 13:53 ` [PATCH 09/15] libata-ncq: implement NCQ device configuration Tejun Heo
2006-04-27 9:11 ` [PATCHSET 7/9] add NCQ support, take 2 Jeff Garzik
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).