add NCQ support, take 2
PATCH 7/9 add NCQ support, take 2
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
PATCH 1/15 libata-ncq: add NCQ related ATA constants and id macros
Add NCQ related ATA constants and id macros.
---
include/linux/ata.h | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
5d6abbcdeb6bcb7eb9e427e1d84aa41f39dd22f9
include/linux/ata.h +9 -0
@@ -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) \
Signature · 1 line
1.2.4
PATCH 2/15 libata-ncq: add NCQ related libata flags
In reply to Tejun HeoAdd two NCQ related libata flags - ATA_DFLAG_NCQ and ATA_FLAG_NCQ..
---
include/linux/libata.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
b54166188991cd72df9e174b31692081237ba72c
include/linux/libata.h +2 -0
@@ -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. */
Signature · 1 line
1.2.4
PATCH 3/15 libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer
In reply to Tejun Heoata_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 | 34 +++++++++++++++++++++------------- 1 files changed, 21 insertions(+), 13 deletions(-)
3fd6c2e278004c2fddf09099560b9630a352fba4
drivers/scsi/libata-scsi.c +21 -13
@@ -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 atata_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; }/**
Signature · 1 line
1.2.4
PATCH 4/15 libata-ncq: implement ap->sactive
In reply to Tejun HeoImplement ap->sactive. This is libata's view of SActive register. This will be used to track NCQ commands and complete them.
---
drivers/scsi/libata-core.c | 22 +++++++++++++++++++++- include/linux/libata.h | 1 + 2 files changed, 22 insertions(+), 1 deletions(-)
29972b1500568aeb7a6dbb681192af3e90d988be
drivers/scsi/libata-core.c +21 -1
@@ -985,6 +985,7 @@ unsigned ata_exec_internal(struct ata_pou8 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_poata_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_poata_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_queuedif (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)) {
include/linux/libata.h +1 -0
@@ -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;
Signature · 1 line
1.2.4
PATCH 5/15 libata-ncq: implement command exclusion
In reply to Tejun HeoNCQ 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-scsi.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 41 insertions(+), 0 deletions(-)
7f78182953826cfcd2c9b0a7d897e01f6724cb6b
drivers/scsi/libata-scsi.c +41 -0
@@ -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 ; }/**
Signature · 1 line
1.2.4
PATCH 6/15 libata-ncq: implement NCQ command translation
In reply to Tejun HeoThis 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.
---
drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-scsi.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletions(-)
d3819d03d822cf98a8b932fde42fcdc3e553edb1
drivers/scsi/libata-core.c +1 -0
@@ -4287,6 +4287,7 @@ static inline int ata_should_dma_map(strstruct ata_port *ap = qc->ap;switch (qc->tf.protocol) { +case ATA_PROT_NCQ :case ATA_PROT_DMA :case ATA_PROT_ATAPI_DMA :return 1 ;
drivers/scsi/libata-scsi.c +30 -1
@@ -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)) {
Signature · 1 line
1.2.4
PATCH 7/15 libata-ncq: implement ata_eh_read_log_10h()
In reply to Tejun HeoImplement ata_eh_read_log_10h(). This will be used by NCQ EH.
---
drivers/scsi/libata-eh.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 107 insertions(+), 0 deletions(-)
ad48d9c5999b24b4ed71e6a2dd9cf1ff20aa90d9
drivers/scsi/libata-eh.c +107 -0
@@ -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
Signature · 1 line
1.2.4
PATCH 8/15 libata-ncq: update EH to handle NCQ
In reply to 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.
---
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
drivers/scsi/ahci.c +1 -1
@@ -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;
drivers/scsi/libata-bmdma.c +1 -1
@@ -700,7 +700,7 @@ void ata_bmdma_drive_eh(struct ata_portstruct 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);
drivers/scsi/libata-eh.c +76 -3
116 lines not on this page · raw message
drivers/scsi/sata_sil24.c +1 -1
@@ -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;
include/linux/libata.h +1 -0
@@ -700,6 +700,7 @@ extern void ata_eh_schedule_port(structextern 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,
Signature · 1 line
1.2.4
PATCH 9/15 libata-ncq: implement NCQ device configuration
In reply to Tejun HeoNow 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.
---
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
drivers/scsi/libata-core.c +28 -2
@@ -1258,6 +1258,27 @@ static inline u8 ata_dev_knobble(const sreturn ((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);
drivers/scsi/libata-scsi.c +48 -0
66 lines not on this page · raw message
include/linux/libata.h +3 -1
@@ -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 scsstruct 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);
Signature · 1 line
1.2.4
PATCH 10/15 libata-ncq: implement ata_ncq_complete()
In reply to Tejun HeoImplement 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.
---
drivers/scsi/libata-core.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 1 + 2 files changed, 48 insertions(+), 0 deletions(-)
99b30184e83c4f6b32e604d792af8ae45f12815a
drivers/scsi/libata-core.c +47 -0
@@ -4589,6 +4589,52 @@ irqreturn_t ata_interrupt (int irq, voidreturn 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);
include/linux/libata.h +1 -0
@@ -581,6 +581,7 @@ extern int ata_scsi_ioctl(struct scsi_deextern 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 *);
Signature · 1 line
1.2.4
PATCH 11/15 ahci: clean up AHCI constants in preparation for NCQ
In reply to 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(-)
6493b186a1b012e7a8cc76467d06c6b3701ace3a
drivers/scsi/ahci.c +9 -6
@@ -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;
Signature · 1 line
1.2.4
PATCH 12/15 ahci: add HOST_CAP_NCQ constant
In reply to Tejun HeoAdd HOST_CAP_NCQ.
---
drivers/scsi/ahci.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
868de01742b3cf25a5b053269737196690a75e53
drivers/scsi/ahci.c +1 -0
@@ -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 */
Signature · 1 line
1.2.4
PATCH 13/15 ahci: kill pp->cmd_tbl_sg
In reply to Tejun HeoWith 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(-)
54c5e95cb986b8045d510cb62d2f89376ffcbc30
drivers/scsi/ahci.c +1 -4
@@ -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);
Signature · 1 line
1.2.4
PATCH 14/15 ahci: implement NCQ suppport
In reply to Tejun HeoImplement NCQ support.
Original implementation is from Jens Axboe.
---
drivers/scsi/ahci.c | 82 ++++++++++++++++++++++++++++++++++----------------- 1 files changed, 54 insertions(+), 28 deletions(-)
67b28600437cd9e5c4b55527f73a3be049064a2d
drivers/scsi/ahci.c +54 -28
@@ -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(streturn 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_pormsleep (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_portata_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_queustruct 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_queuif (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(strucstatic 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(structif (!(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(structstruct 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_devVPRINTK ("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_devif (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 */
Signature · 1 line
1.2.4
PATCH 15/15 sata_sil24: implement NCQ support
In reply to Tejun HeoImplement 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 | 79 +++++++++++++++++++++++++++++++++------------ 1 files changed, 58 insertions(+), 21 deletions(-)
83fbbc40a0cca8a044f50d6097fe819cfb11b750
drivers/scsi/sata_sil24.c +58 -21
@@ -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_questatic 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(strustatic 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(strucif (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 istatic 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_pstruct 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 ;
Signature · 1 line
1.2.4
Quoted 8 lines · Tejun Heo
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_sil24NCQ 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