* [PATCH 02/12] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 01/12] libata-ncq: add NCQ related ATA/libata constants and macros Tejun Heo
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, 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.
---
drivers/scsi/libata-scsi.c | 40 ++++++++++++++++++++++++----------------
1 files changed, 24 insertions(+), 16 deletions(-)
31df0610cf8d4ea725d9b3be8676a49248d6b1c9
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index e61cc35..96517ca 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1248,11 +1248,14 @@ 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_device *dev, struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- ata_xlat_func_t xlat_func)
+static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *),
+ ata_xlat_func_t xlat_func)
{
struct ata_queued_cmd *qc;
u8 *scsicmd = cmd->cmnd;
@@ -1290,13 +1293,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);
@@ -1304,7 +1307,7 @@ err_mem:
cmd->result = (DID_ERROR << 16);
done(cmd);
DPRINTK("EXIT - internal\n");
- return;
+ return 0;
}
/**
@@ -2456,20 +2459,24 @@ 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_device *dev)
+static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *),
+ 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(dev, cmd, done, xlat_func);
+ rc = ata_scsi_translate(dev, cmd, done, xlat_func);
else
ata_scsi_simulate(dev, cmd, done);
} else
- ata_scsi_translate(dev, cmd, done, atapi_xlat);
+ rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
+
+ return rc;
}
/**
@@ -2488,15 +2495,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 = ata_shost_to_port(shost);
@@ -2507,7 +2515,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *
dev = ata_scsi_find_dev(ap, scsidev);
if (likely(dev))
- __ata_scsi_queuecmd(cmd, done, dev);
+ rc = __ata_scsi_queuecmd(cmd, done, dev);
else {
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
@@ -2515,7 +2523,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] 14+ messages in thread* [PATCH 01/12] libata-ncq: add NCQ related ATA/libata constants and macros
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
2006-05-11 14:44 ` [PATCH 02/12] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 05/12] libata-ncq: implement NCQ command translation and exclusion Tejun Heo
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Add NCQ related ATA/libata constants and macros.
---
include/linux/ata.h | 9 +++++++++
include/linux/libata.h | 2 ++
2 files changed, 11 insertions(+), 0 deletions(-)
65d7503ff8ed1ba872c5538327247b98473a44e9
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 1cbeb43..c494e1c 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,
@@ -221,6 +227,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 */
@@ -276,6 +283,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) \
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ed884d6..c9d20d4 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -125,6 +125,7 @@ enum {
ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */
ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */
ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */
+ ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
@@ -152,6 +153,7 @@ enum {
ATA_FLAG_IRQ_MASK = (1 << 9), /* Mask IRQ in PIO xfers */
ATA_FLAG_PIO_POLLING = (1 << 10), /* use polling PIO if LLD
* doesn't handle PIO interrupts */
+ ATA_FLAG_NCQ = (1 << 11), /* host supports NCQ */
ATA_FLAG_DEBUGMSG = (1 << 14),
ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* flush port task */
--
1.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 05/12] libata-ncq: implement NCQ command translation and exclusion
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
2006-05-11 14:44 ` [PATCH 02/12] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer Tejun Heo
2006-05-11 14:44 ` [PATCH 01/12] libata-ncq: add NCQ related ATA/libata constants and macros Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 06/12] libata-ncq: update EH to handle NCQ Tejun Heo
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
This patch implements NCQ command translation and exclusion. 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.
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.
---
drivers/scsi/libata-core.c | 1 +
drivers/scsi/libata-scsi.c | 72 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 72 insertions(+), 1 deletions(-)
350c9937c660b34043c1384e730b3075052bc788
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 0c2550e..3e3d3d1 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4415,6 +4415,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 96517ca..9bef68c 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1103,7 +1103,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)) {
@@ -1227,6 +1256,39 @@ static void ata_scsi_qc_complete(struct
}
/**
+ * ata_scmd_need_defer - Check whether we need to defer scmd
+ * @dev: ATA device to which the command is addressed
+ * @is_io: Is the command IO (and thus possibly NCQ)?
+ *
+ * NCQ and non-NCQ commands cannot run together. As upper layer
+ * only knows the queue depth, we are responsible for maintaining
+ * exclusion. This function checks whether a new command can be
+ * issued to @dev.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * 1 if deferring is needed, 0 otherwise.
+ */
+static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
+{
+ struct ata_port *ap = dev->ap;
+
+ 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
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
@@ -1259,9 +1321,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(dev, is_io)))
+ goto defer;
+
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1308,6 +1374,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] 14+ messages in thread* [PATCH 06/12] libata-ncq: update EH to handle NCQ
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (2 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 05/12] libata-ncq: implement NCQ command translation and exclusion Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 03/12] libata-ncq: rename ap->qactive to ap->qc_allocated Tejun Heo
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Update EH to handle NCQ. ata_eh_autopsy() is updated to call
ata_eh_analyze_ncq_error() which reads log page 10h on NCQ device
error and updates eh_context accordingly. ata_eh_report() is updated
to report SActive.
---
drivers/scsi/libata-eh.c | 171 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 163 insertions(+), 8 deletions(-)
a65e2e8c8ee789ed540ee0f10a05aa3b404cd05a
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 3b692f5..b6268b5 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -691,6 +691,98 @@ static const char * ata_err_string(unsig
}
/**
+ * ata_read_log_page - read a specific log page
+ * @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_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(dev, &tf);
+ 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(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
+ * @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_device *dev,
+ int *tag, struct ata_taskfile *tf)
+{
+ u8 *buf = dev->ap->sector_buf;
+ unsigned int err_mask;
+ u8 csum;
+ int i;
+
+ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
+ if (err_mask)
+ return -EIO;
+
+ csum = 0;
+ for (i = 0; i < ATA_SECT_SIZE; i++)
+ csum += buf[i];
+ if (csum)
+ ata_dev_printk(dev, KERN_WARNING,
+ "invalid checksum 0x%x on log page 10h\n", csum);
+
+ if (buf[0] & 0x80)
+ return -ENOENT;
+
+ *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];
+
+ return 0;
+}
+
+/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
* @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -789,6 +881,66 @@ static void ata_eh_analyze_serror(struct
}
/**
+ * ata_eh_analyze_ncq_error - analyze NCQ error
+ * @ap: ATA port to analyze NCQ error for
+ *
+ * Read log page 10h, determine the offending qc and acquire
+ * error status TF. For NCQ device errors, all LLDDs have to do
+ * is setting AC_ERR_DEV in ehi->err_mask. This function takes
+ * care of the rest.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev = ap->device;
+ struct ata_queued_cmd *qc;
+ struct ata_taskfile tf;
+ int tag, rc;
+
+ /* if frozen, we can't do much */
+ if (ap->flags & ATA_FLAG_FROZEN)
+ return;
+
+ /* is it NCQ device error? */
+ if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+ return;
+
+ /* has LLDD analyzed already? */
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ if (qc->err_mask)
+ return;
+ }
+
+ /* okay, this error is ours */
+ rc = ata_eh_read_log_10h(dev, &tag, &tf);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+ "(errno=%d)\n", rc);
+ return;
+ }
+
+ if (!(ap->sactive & (1 << tag))) {
+ ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+ "inactive tag %d\n", tag);
+ return;
+ }
+
+ /* we've got the perpetrator, condemn it */
+ qc = __ata_qc_from_tag(ap, tag);
+ memcpy(&qc->result_tf, &tf, sizeof(tf));
+ qc->err_mask |= AC_ERR_DEV;
+ ehc->i.err_mask &= ~AC_ERR_DEV;
+}
+
+/**
* ata_eh_analyze_tf - analyze taskfile of a failed qc
* @qc: qc to analyze
* @tf: Taskfile registers to analyze
@@ -1005,6 +1157,9 @@ static void ata_eh_autopsy(struct ata_po
} else if (rc != -EOPNOTSUPP)
action |= ATA_EH_HARDRESET;
+ /* analyze NCQ failure */
+ ata_eh_analyze_ncq_error(ap);
+
/* any real error trumps AC_ERR_OTHER */
if (ehc->i.err_mask & ~AC_ERR_OTHER)
ehc->i.err_mask &= ~AC_ERR_OTHER;
@@ -1099,17 +1254,17 @@ static void ata_eh_report(struct ata_por
frozen = " frozen";
if (ehc->i.dev) {
- ata_dev_printk(ehc->i.dev, KERN_ERR,
- "exception Emask 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ehc->i.serror, ehc->i.action,
- frozen);
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+ ehc->i.err_mask, ap->sactive, ehc->i.serror,
+ ehc->i.action, frozen);
if (desc)
ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
} else {
- ata_port_printk(ap, KERN_ERR,
- "exception Emask 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ehc->i.serror, ehc->i.action,
- frozen);
+ ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+ ehc->i.err_mask, ap->sactive, ehc->i.serror,
+ ehc->i.action, frozen);
if (desc)
ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
}
--
1.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 03/12] libata-ncq: rename ap->qactive to ap->qc_allocated
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (3 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 06/12] libata-ncq: update EH to handle NCQ Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 12/12] sata_sil24: implement NCQ support Tejun Heo
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Rename ap->qactive to ap->qc_allocated. This is to accomodate
addition of ap->qc_active, mask of active qcs.
---
drivers/scsi/libata-core.c | 6 +++---
include/linux/libata.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
657b87491833e0c1be9a48536cf09a878b671451
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 6d28722..bafc460 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1006,7 +1006,7 @@ unsigned ata_exec_internal(struct ata_de
else
tag = 0;
- if (test_and_set_bit(tag, &ap->qactive))
+ if (test_and_set_bit(tag, &ap->qc_allocated))
BUG();
qc = __ata_qc_from_tag(ap, tag);
@@ -4206,7 +4206,7 @@ static struct ata_queued_cmd *ata_qc_new
/* the last tag is reserved for internal command. */
for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
- if (!test_and_set_bit(i, &ap->qactive)) {
+ if (!test_and_set_bit(i, &ap->qc_allocated)) {
qc = __ata_qc_from_tag(ap, i);
break;
}
@@ -4263,7 +4263,7 @@ void ata_qc_free(struct ata_queued_cmd *
tag = qc->tag;
if (likely(ata_tag_valid(tag))) {
qc->tag = ATA_TAG_POISON;
- clear_bit(tag, &ap->qactive);
+ clear_bit(tag, &ap->qc_allocated);
}
}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index c9d20d4..ffb57fc 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -477,7 +477,7 @@ struct ata_port {
struct ata_device device[ATA_MAX_DEVICES];
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
- unsigned long qactive;
+ unsigned long qc_allocated;
unsigned int active_tag;
struct ata_host_stats stats;
--
1.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 12/12] sata_sil24: implement NCQ support
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (4 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 03/12] libata-ncq: rename ap->qactive to ap->qc_allocated Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 04/12] libata-ncq: implement ap->qc_active, ap->sactive and complete helper Tejun Heo
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, 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.
---
drivers/scsi/sata_sil24.c | 68 +++++++++++++++++++++++++++++++--------------
1 files changed, 47 insertions(+), 21 deletions(-)
16de6240bcc7474f1d4c36982445b4e81a5b90ea
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index adbb5a6..202d34e 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -216,6 +216,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,
@@ -223,7 +225,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,
@@ -355,7 +358,8 @@ static struct scsi_host_template sil24_s
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .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,
@@ -437,6 +441,13 @@ static struct ata_port_info sil24_port_i
},
};
+static int sil24_tag(int tag)
+{
+ if (unlikely(ata_tag_internal(tag)))
+ return 0;
+ return tag;
+}
+
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -649,14 +660,17 @@ 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;
+ union sil24_cmd_block *cb;
struct sil24_prb *prb;
struct sil24_sge *sge;
u16 ctrl = 0;
+ cb = &pp->cmd_block[sil24_tag(qc->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;
@@ -694,12 +708,17 @@ 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;
+ unsigned int tag = sil24_tag(qc->tag);
+ dma_addr_t paddr;
+ void __iomem *activate;
- 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;
}
@@ -791,9 +810,6 @@ static void sil24_error_intr(struct ata_
/* record error info */
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
- int tag = qc->tag;
- if (unlikely(ata_tag_internal(tag)))
- tag = 0;
sil24_update_tf(ap);
qc->err_mask |= err_mask;
} else
@@ -809,11 +825,17 @@ static void sil24_error_intr(struct ata_
ata_port_abort(ap);
}
+static void sil24_finish_qc(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ sil24_update_tf(qc->ap);
+}
+
static inline void sil24_host_intr(struct ata_port *ap)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- struct ata_queued_cmd *qc;
- u32 slot_stat;
+ u32 slot_stat, qc_active;
+ int rc;
slot_stat = readl(port + PORT_SLOT_STAT);
@@ -825,18 +847,22 @@ static inline void sil24_host_intr(struc
if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc) {
- if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(ap);
- ata_qc_complete(qc);
+ qc_active = slot_stat & ~HOST_SSTAT_ATTN;
+ rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
return;
}
if (ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(slot_stat 0x%x active_tag %d)\n",
- slot_stat, ap->active_tag);
+ "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+ slot_stat, ap->active_tag, ap->sactive);
}
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -903,7 +929,7 @@ static void sil24_post_internal_cmd(stru
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);
}
@@ -913,7 +939,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] 14+ messages in thread* [PATCH 04/12] libata-ncq: implement ap->qc_active, ap->sactive and complete helper
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (5 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 12/12] sata_sil24: implement NCQ support Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 11/12] ahci: implement NCQ suppport Tejun Heo
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Add ap->qc_active and ap->sactive, mask of all active qcs and libata's
view of the SActive register, respectively. Also, implement
ata_qc_complete_multiple() which takes new qc_active mask and complete
multiple qcs according to the mask.
These will be used to track NCQ commands and complete them. The
distinction between ap->qc_active and ap->sactive is also useful for
later PM implementation.
---
drivers/scsi/libata-core.c | 81 +++++++++++++++++++++++++++++++++++++++++++-
include/linux/libata.h | 5 +++
2 files changed, 84 insertions(+), 2 deletions(-)
4e46d5244102b748d414e888fdc6cd3a42087b78
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index bafc460..0c2550e 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -981,6 +981,7 @@ unsigned ata_exec_internal(struct ata_de
u8 command = tf->command;
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
+ u32 preempted_sactive, preempted_qc_active;
DECLARE_COMPLETION(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1017,7 +1018,11 @@ unsigned ata_exec_internal(struct ata_de
ata_qc_reinit(qc);
preempted_tag = ap->active_tag;
+ preempted_sactive = ap->sactive;
+ preempted_qc_active = ap->qc_active;
ap->active_tag = ATA_TAG_POISON;
+ ap->sactive = 0;
+ ap->qc_active = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1082,6 +1087,8 @@ unsigned ata_exec_internal(struct ata_de
ata_qc_free(qc);
ap->active_tag = preempted_tag;
+ ap->sactive = preempted_sactive;
+ ap->qc_active = preempted_qc_active;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -4269,6 +4276,8 @@ void ata_qc_free(struct ata_queued_cmd *
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
+ struct ata_port *ap = qc->ap;
+
WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -4276,13 +4285,17 @@ void __ata_qc_complete(struct ata_queued
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- qc->ap->active_tag = ATA_TAG_POISON;
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ ap->sactive &= ~(1 << qc->tag);
+ else
+ ap->active_tag = ATA_TAG_POISON;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
* is called. (when rc != 0 and atapi request sense is needed)
*/
qc->flags &= ~ATA_QCFLAG_ACTIVE;
+ ap->qc_active &= ~(1 << qc->tag);
/* call completion callback */
qc->complete_fn(qc);
@@ -4348,6 +4361,55 @@ void ata_qc_complete(struct ata_queued_c
}
}
+/**
+ * ata_qc_complete_multiple - Complete multiple qcs successfully
+ * @ap: port in question
+ * @qc_active: new qc_active mask
+ * @finish_qc: LLDD callback invoked before completing a qc
+ *
+ * Complete in-flight commands. This functions is meant to be
+ * called from low-level driver's interrupt routine to complete
+ * requests normally. ap->qc_active and @qc_active 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_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
+ void (*finish_qc)(struct ata_queued_cmd *))
+{
+ int nr_done = 0;
+ u32 done_mask;
+ int i;
+
+ done_mask = ap->qc_active ^ qc_active;
+
+ if (unlikely(done_mask & qc_active)) {
+ ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
+ "(%08x->%08x)\n", ap->qc_active, qc_active);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ struct ata_queued_cmd *qc;
+
+ if (!(done_mask & (1 << i)))
+ continue;
+
+ if ((qc = ata_qc_from_tag(ap, i))) {
+ if (finish_qc)
+ finish_qc(qc);
+ ata_qc_complete(qc);
+ nr_done++;
+ }
+ }
+
+ return nr_done;
+}
+
static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -4387,8 +4449,22 @@ void ata_qc_issue(struct ata_queued_cmd
{
struct ata_port *ap = qc->ap;
- qc->ap->active_tag = qc->tag;
+ /* Make sure only one non-NCQ command is outstanding. The
+ * check is skipped for old EH because it reuses active qc to
+ * request ATAPI sense.
+ */
+ WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+
+ 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;
+ ap->qc_active |= 1 << qc->tag;
if (ata_should_dma_map(qc)) {
if (qc->flags & ATA_QCFLAG_SG) {
@@ -5549,6 +5625,7 @@ EXPORT_SYMBOL_GPL(ata_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
EXPORT_SYMBOL_GPL(ata_tf_load);
EXPORT_SYMBOL_GPL(ata_tf_read);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ffb57fc..d059c75 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -478,7 +478,10 @@ struct ata_port {
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
unsigned long qc_allocated;
+ unsigned int qc_active;
+
unsigned int active_tag;
+ u32 sactive;
struct ata_host_stats stats;
struct ata_host_set *host_set;
@@ -671,6 +674,8 @@ extern void ata_bmdma_drive_eh(struct at
extern void ata_bmdma_error_handler(struct ata_port *ap);
extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
extern void ata_qc_complete(struct ata_queued_cmd *qc);
+extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
+ void (*finish_qc)(struct ata_queued_cmd *));
extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *));
extern int ata_std_bios_param(struct scsi_device *sdev,
--
1.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 11/12] ahci: implement NCQ suppport
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (6 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 04/12] libata-ncq: implement ap->qc_active, ap->sactive and complete helper Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 09/12] ahci: add HOST_CAP_NCQ constant Tejun Heo
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Implement NCQ support.
Original implementation is from Jens Axboe.
---
drivers/scsi/ahci.c | 88 +++++++++++++++++++++++++++++++++------------------
1 files changed, 57 insertions(+), 31 deletions(-)
8e45ed212780b8ccf089fad7b15dfa23d4046969
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 49f5101..9f020cd 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
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .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,
@@ -528,12 +529,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_clo(struct ata_port *ap)
@@ -605,7 +611,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);
@@ -624,7 +631,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);
@@ -735,9 +742,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;
@@ -747,7 +753,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);
@@ -768,6 +774,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;
@@ -776,16 +783,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.
@@ -796,7 +804,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 void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
@@ -867,8 +875,8 @@ static void ahci_host_intr(struct ata_po
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_queued_cmd *qc;
- u32 status, serror, ci;
+ u32 status, serror, qc_active;
+ int rc;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
@@ -892,16 +900,27 @@ static void ahci_host_intr(struct ata_po
return;
}
- if ((qc = ata_qc_from_tag(ap, ap->active_tag))) {
- ci = readl(port_mmio + PORT_CMD_ISSUE);
- if ((ci & 0x1) == 0) {
- ata_qc_complete(qc);
- return;
- }
+ if (ap->sactive)
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ else
+ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+
+ rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
}
/* hmmm... a spurious interupt */
+ /* some devices send D2H reg with I bit set during NCQ command phase */
+ if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+ return;
+
/* ignore interim PIO setup fis interrupts */
if (ata_tag_valid(ap->active_tag)) {
struct ata_queued_cmd *qc =
@@ -914,8 +933,8 @@ static void ahci_host_intr(struct ata_po
if (ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(irq_stat 0x%x active_tag %d)\n",
- status, ap->active_tag);
+ "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
+ status, ap->active_tag, ap->sactive);
}
static void ahci_irq_clear(struct ata_port *ap)
@@ -923,7 +942,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;
@@ -981,7 +1000,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;
@@ -1257,6 +1278,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");
@@ -1324,6 +1347,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] 14+ messages in thread* [PATCH 09/12] ahci: add HOST_CAP_NCQ constant
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (7 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 11/12] ahci: implement NCQ suppport Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 10/12] ahci: kill pp->cmd_tbl_sg Tejun Heo
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Add HOST_CAP_NCQ.
---
drivers/scsi/ahci.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
e0ec8cbb8c52825db6eb4c838bfc3a69f4f3c8a4
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 1177ae5..beb269a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -93,6 +93,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] 14+ messages in thread* [PATCH 10/12] ahci: kill pp->cmd_tbl_sg
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (8 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 09/12] ahci: add HOST_CAP_NCQ constant Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 08/12] ahci: clean up AHCI constants in preparation for NCQ Tejun Heo
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, 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.
---
drivers/scsi/ahci.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
51dea343a3a00edf4389d9efbe024b478f9ba377
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index beb269a..49f5101 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -191,7 +191,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;
};
@@ -397,8 +396,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)
@@ -750,7 +747,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] 14+ messages in thread* [PATCH 08/12] ahci: clean up AHCI constants in preparation for NCQ
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (9 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 10/12] ahci: kill pp->cmd_tbl_sg Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-11 14:44 ` [PATCH 07/12] libata-ncq: implement NCQ device configuration Tejun Heo
2006-05-13 22:39 ` [PATCHSET 05/11] add NCQ support, take 3 Jeff Garzik
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, 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.
---
drivers/scsi/ahci.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
e24ebe47347cf08d2c2b57923b3948732e94b7f3
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 680dd5b..1177ae5 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),
@@ -89,8 +92,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 */
@@ -393,7 +396,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] 14+ messages in thread* [PATCH 07/12] libata-ncq: implement NCQ device configuration
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (10 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 08/12] ahci: clean up AHCI constants in preparation for NCQ Tejun Heo
@ 2006-05-11 14:44 ` Tejun Heo
2006-05-13 22:39 ` [PATCHSET 05/11] add NCQ support, take 3 Jeff Garzik
12 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2006-05-11 14:44 UTC (permalink / raw)
To: jgarzik, alan, axboe, albertcc, forrest.zhao, efalk, linux-ide; +Cc: Tejun Heo
Now that all NCQ related stuff are in place, implement NCQ device
configuration and bump ATA_MAX_QUEUE to 32 thus activating NCQ
support.
Original implementation is from Jens Axboe.
---
drivers/scsi/libata-core.c | 31 ++++++++++++++++++++++++++++--
drivers/scsi/libata-scsi.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/libata.h | 4 +++-
3 files changed, 78 insertions(+), 3 deletions(-)
efed0a60183811c87f012f7b32f50f8cc3139564
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 3e3d3d1..54240db 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1251,6 +1251,28 @@ static inline u8 ata_dev_knobble(struct
return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
+static void ata_dev_config_ncq(struct ata_device *dev,
+ char *desc, size_t desc_sz)
+{
+ struct ata_port *ap = dev->ap;
+ 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
* @dev: Target device to configure
@@ -1311,6 +1333,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;
@@ -1319,14 +1342,17 @@ static int ata_dev_configure(struct ata_
lba_desc = "LBA48";
}
+ /* config NCQ */
+ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+
/* print device info to dmesg */
if (print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
- "max %s, %Lu sectors: %s\n",
+ "max %s, %Lu sectors: %s %s\n",
ata_id_major_version(id),
ata_mode_string(xfer_mask),
(unsigned long long)dev->n_sectors,
- lba_desc);
+ lba_desc, ncq_desc);
} else {
/* CHS */
@@ -5675,6 +5701,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_scr_valid);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 9bef68c..996058a 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>
@@ -684,6 +685,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);
+ }
}
/**
@@ -718,6 +727,43 @@ 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 = ata_shost_to_port(sdev->host);
+ struct ata_device *dev;
+ int max_depth;
+
+ if (queue_depth < 1)
+ return sdev->queue_depth;
+
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (!dev || !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 d059c75..97e25a6 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,
@@ -682,6 +682,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_device *adev);
/*
--
1.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCHSET 05/11] add NCQ support, take 3
2006-05-11 14:44 [PATCHSET 05/11] add NCQ support, take 3 Tejun Heo
` (11 preceding siblings ...)
2006-05-11 14:44 ` [PATCH 07/12] libata-ncq: implement NCQ device configuration Tejun Heo
@ 2006-05-13 22:39 ` Jeff Garzik
12 siblings, 0 replies; 14+ messages in thread
From: Jeff Garzik @ 2006-05-13 22:39 UTC (permalink / raw)
To: Tejun Heo; +Cc: alan, axboe, albertcc, forrest.zhao, efalk, linux-ide
Tejun Heo wrote:
> An-Nyoung.
>
> This is part of patchset series described in [T].
>
> This is the third take of add-NCQ-support patchset. Changes from the
> last take [L] are
[...]
> This patchset is against
>
> upstream (acc696d93dcf993dec123d69d599979e1456ffec)
> + [1] prep-for-new-EH patchset
> + [2] new-EH-framework patchset, take 3
> + [3] new-EH-implementation patchset, take 3
> + [4] merge-irq-pio patchset
>
> --
> tejun
>
> [T] http://article.gmane.org/gmane.linux.ide/9957
> [L] http://article.gmane.org/gmane.linux.ide/9555
> [1] http://article.gmane.org/gmane.linux.ide/9959
> [2] http://article.gmane.org/gmane.linux.ide/9984
> [3] http://article.gmane.org/gmane.linux.ide/9995
> [4] http://article.gmane.org/gmane.linux.ide/10005
ACK entire patchset. Yay, NCQ! Thanks to you and Jens for your hard work.
Jeff
^ permalink raw reply [flat|nested] 14+ messages in thread