SATA NCQ #3
PATCH 1/1 SATA NCQ #3
Hi,
Updated patch. Changes:
- (ahci) improve error handling some more.
- (libata) kill double queue depth accounting, add ap->queue_depth and use ap->flags & ATA_FLAG_NCQ_QUEUED to differentiate between the two.
- (libata) cleanup the reissue-on-busy logic. punt everything to SCSI, if we can. We can kill ATA_QCFLAG_DEFER and ATA_QC_ISSUE_DEFER then.
- (libata) leave ATA_DEVICE_OBS alone, which means we have to clear bit 7 in the NCQ command setup.
- (libata) import an error handling fix from Hannes.
- various other fixes/cleanups.
Error handling still needs some work, but at least it's a little less embarassing now (and doesn't hang the kernel if it triggers).
Jeff, I'll update your ncq branch at the end of this week if you don't beat me to it.
drivers/scsi/ahci.c +253 -46
@@ -19,8 +19,8 @@* If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * -* Version 1.0 of the AHCI specification: -* http://www.intel.com/technology/serialata/pdf/rev1_0.pdf +* Version 1.1 of the AHCI specification: +* http://www.intel.com/technology/serialata/pdf/rev1_1.pdf * */
@@ -47,10 +47,13 @@ enum {AHCI_MAX_SG =168 ,/* hardware max is 64K */ AHCI_DMA_BOUNDARY =0xffffffff ,AHCI_USE_CLUSTERING =0 , -AHCI_CMD_SLOT_SZ =32 *32 , -AHCI_RX_FIS_SZ =256 , +AHCI_MAX_CMDS =32 , +AHCI_CMD_SZ =32 ,AHCI_CMD_TBL_HDR =0x80 , -AHCI_CMD_TBL_SZ =AHCI_CMD_TBL_HDR + (AHCI_MAX_SG *16 ), +AHCI_CMD_SLOT_SZ =AHCI_MAX_CMDS *AHCI_CMD_SZ , +AHCI_RX_FIS_SZ =256 , +AHCI_CMD_TOTAL =AHCI_CMD_TBL_HDR + (AHCI_MAX_SG *16 ), +AHCI_CMD_TBL_SZ =AHCI_MAX_CMDS *AHCI_CMD_TOTAL ,AHCI_PORT_PRIV_DMA_SZ =AHCI_CMD_SLOT_SZ +AHCI_CMD_TBL_SZ +AHCI_RX_FIS_SZ , AHCI_IRQ_ON_SG = (1 << 31),
@@ -58,6 +61,7 @@ enum {AHCI_CMD_WRITE = (1 <<6 ),RX_FIS_D2H_REG =0x40 ,/* offset of D2H Register FIS data */ +RX_FIS_SDB_REG =0x58 ,/* offset of SDB Register FIS data */ board_ahci = 0,
@@ -75,6 +79,7 @@ enum {/* HOST_CAP bits */ HOST_CAP_64 = (1 <<31 ),/* PCI DAC (64-bit DMA) support */ +HOST_CAP_NCQ = (1 <<30 ),/* Native Command Queueing */ /* registers for each SATA port */ PORT_LST_ADDR = 0x00, /* command list DMA addr */
@@ -162,9 +167,9 @@ 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; +u32 sactive; };static u32 ahci_scr_read (struct ata_port *ap,unsigned int sc_reg);
@@ -182,7 +187,7 @@ static void ahci_tf_read(struct ata_portstatic void ahci_qc_prep (struct ata_queued_cmd *qc);static u8 ahci_check_status (struct ata_port *ap);static u8 ahci_check_err (struct ata_port *ap); -static inline int ahci_host_intr (struct ata_port *ap,struct ata_queued_cmd *qc); +static inline int ahci_host_intr (struct ata_port *ap);static Scsi_Host_Template ahci_sht = { .module =THIS_MODULE ,
@@ -190,7 +195,8 @@ static Scsi_Host_Template ahci_sht = { .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 = ATA_MAX_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = AHCI_MAX_SG, .max_sectors = ATA_MAX_SECTORS,
@@ -201,7 +207,7 @@ static Scsi_Host_Template ahci_sht = { .dma_boundary = AHCI_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, - .ordered_flush = 1, + .ordered_flush = 0, /* conflicts with NCQ for now */ };static struct ata_port_operations ahci_ops = {
@@ -342,14 +348,11 @@ static int ahci_port_start(struct ata_po mem_dma +=AHCI_RX_FIS_SZ ;/* -* Third item: data area for storing a single command -* and its scatter-gather table +* Third item: data area for storing commands and their sg tables */ pp->cmd_tbl = mem; pp->cmd_tbl_dma = mem_dma; - pp->cmd_tbl_sg = mem +AHCI_CMD_TBL_HDR ; - ap->private_data = pp;if (hpriv->cap &HOST_CAP_64 )
@@ -481,9 +484,10 @@ static void ahci_tf_read(struct ata_portata_tf_from_fis (d2h_fis, tf); } -static void ahci_fill_sg (struct ata_queued_cmd *qc) +static void ahci_fill_sg (struct ata_queued_cmd *qc,int offset) {struct ahci_port_priv *pp = qc->ap->private_data; +struct ahci_sg *cmd_tbl_sg;unsigned int i;VPRINTK ("ENTER\n" );
@@ -491,6 +495,7 @@ static void ahci_fill_sg(struct ata_queu/* * Next, the S/G list. */ + cmd_tbl_sg = pp->cmd_tbl + offset +AHCI_CMD_TBL_HDR ;for (i =0 ; i < qc->n_elem; i++) {u32 sg_len;dma_addr_t addr;
@@ -498,21 +503,22 @@ static void ahci_fill_sg(struct ata_queu addr =sg_dma_address (&qc->sg[i]); sg_len =sg_dma_len (&qc->sg[i]); - pp->cmd_tbl_sg[i].addr =cpu_to_le32 (addr &0xffffffff ); - pp->cmd_tbl_sg[i].addr_hi =cpu_to_le32 ((addr >>16 ) >>16 ); - pp->cmd_tbl_sg[i].flags_size =cpu_to_le32 (sg_len -1 ); + cmd_tbl_sg[i].addr =cpu_to_le32 (addr &0xffffffff ); + cmd_tbl_sg[i].addr_hi =cpu_to_le32 ((addr >>16 ) >>16 ); + cmd_tbl_sg[i].flags_size =cpu_to_le32 (sg_len -1 ); } }static void ahci_qc_prep (struct ata_queued_cmd *qc) {struct ahci_port_priv *pp = qc->ap->private_data; -u32 opts;const u32 cmd_fis_len =5 ;/* five dwords */ +dma_addr_t cmd_tbl_dma; +u32 opts; +int offset;/* -* Fill in command slot information (currently only one slot, -* slot 0, is currently since we don't do queueing) +* Fill in command slot information */ opts = (qc->n_elem <<16 ) | cmd_fis_len;
@@ -531,29 +537,39 @@ static void ahci_qc_prep(struct ata_queubreak ; } - 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 ); +/* +* the tag determines the offset into the allocated cmd table +*/ + offset = qc->tag *AHCI_CMD_TOTAL ; + + cmd_tbl_dma = pp->cmd_tbl_dma + offset; + + pp->cmd_slot[qc->tag].opts =cpu_to_le32 (opts); + pp->cmd_slot[qc->tag].status =0 ; + pp->cmd_slot[qc->tag].tbl_addr =cpu_to_le32 (cmd_tbl_dma &0xffffffff ); + pp->cmd_slot[qc->tag].tbl_addr_hi =cpu_to_le32 ((cmd_tbl_dma >>16 ) >>16 );/* * 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 ); +ata_tf_to_fis (&qc->tf, pp->cmd_tbl + offset,0 );if (!(qc->flags &ATA_QCFLAG_DMAMAP ))return ; -ahci_fill_sg (qc); +ahci_fill_sg (qc, offset); } -static void ahci_intr_error (struct ata_port *ap,u32 irq_stat) +/* +* Return 1 if COMRESET was done +*/ +static int ahci_intr_error (struct ata_port *ap,u32 irq_stat) {void *mmio = ap->host_set->mmio_base;void *port_mmio =ahci_port_base (mmio, ap->port_no);u32 tmp; -int work; +int work, reset =0 ;/* stop DMA */ tmp =readl (port_mmio +PORT_CMD );
@@ -575,6 +591,10 @@ static void ahci_intr_error(struct ata_p tmp =readl (port_mmio +PORT_SCR_ERR );writel (tmp, port_mmio +PORT_SCR_ERR ); +/* clear status */ + tmp =readl (port_mmio +PORT_IRQ_STAT ); +writel (tmp, port_mmio +PORT_IRQ_STAT ); +/* if DRQ/BSY is set, device needs to be reset. * if so, issue COMRESET */
@@ -585,6 +605,7 @@ static void ahci_intr_error(struct ata_pudelay (10 );writel (0x300 , port_mmio +PORT_SCR_CTL );readl (port_mmio +PORT_SCR_CTL );/* flush */ + reset =1 ; }/* re-start DMA */
@@ -594,9 +615,108 @@ static void ahci_intr_error(struct ata_preadl (port_mmio +PORT_CMD );/* flush */ printk (KERN_WARNING "ata%u: error occurred, port reset\n" , ap->id); +return reset; } -static void ahci_eng_timeout (struct ata_port *ap) +static void ahci_complete_requests (struct ata_port *ap,unsigned int tag_mask, +int err) +{ +while (tag_mask) { +struct ata_queued_cmd *qc; +int tag =ffs (tag_mask) -1 ; + + tag_mask &= ~(1 << tag); + qc =ata_qc_from_tag (ap, tag); +if (qc) +ata_qc_complete (qc, err); +else +printk (KERN_ERR "ahci: missing tag %d\n" , tag); + } +} + +static void dump_log_page (unsigned char *p) +{ +int i; + +printk ("LOG 0x10: nq=%d, tag=%d\n" , p[0 ] >>7 , p[0 ] &0x1f ); + +for (i =2 ; i <14 ; i++) +printk ("%d:%d " , i, p[i]); + +printk ("\n" ); +} + +/* +* TODO: needs to use READ_LOG_EXT/page=10h to retrieve error information +*/ +extern void ata_qc_free (struct ata_queued_cmd *qc); +static void ahci_ncq_timeout (struct ata_port *ap) +{ +struct ahci_port_priv *pp = ap->private_data; +void *mmio = ap->host_set->mmio_base; +void *port_mmio =ahci_port_base (mmio, ap->port_no); +unsigned long flags; +char *buffer; +u32 sactive; +int reset; + +printk (KERN_ERR "ata%u: ncq interrupt error\n" , ap->id); + +spin_lock_irqsave (&ap->host_set->lock, flags); + + sactive =readl (port_mmio +PORT_SCR_ACT ); + +printk (KERN_ERR "ata%u: SActive 0x%x (0x%x)\n" , ap->id, sactive, pp->sactive); + reset =ahci_intr_error (ap,readl (port_mmio +PORT_IRQ_STAT )); + + sactive &= pp->sactive; +while (sactive) { +struct ata_queued_cmd *qc; +int tag =ffs (sactive) -1 ; + + sactive &= ~(1 << tag); + qc =ata_qc_from_tag (ap, tag); +if (qc) { +if (qc->scsicmd) +ata_qc_free (qc); +else +ata_qc_complete (qc,ATA_ERR ); + }else +printk (KERN_ERR "ahci: missing tag %d\n" , tag); + } + +printk (KERN_ERR "requeued commands, busy %d, ncq %d\n" , ap->queue_depth, (int ) (ap->flags &ATA_FLAG_NCQ_QUEUED )); + +spin_unlock_irqrestore (&ap->host_set->lock, flags); + +printk (KERN_ERR "ata%u: COMRESET done %d\n" , ap->id, reset); + +/* +* if COMRESET was done, we don't have to issue a log page read +*/ +if (reset) + goto done; + + buffer =kmalloc (512 ,GFP_KERNEL ); +if (!buffer) { +printk (KERN_ERR "ata%u: unable to allocate memory for error\n" , ap->id); + goto done; + } + +if (ata_read_log_page (ap,0 ,READ_LOG_SATA_NCQ_PAGE , buffer,1 )) { +printk (KERN_ERR "ata%u: unable to read log page\n" , ap->id); + goto out; + } + +dump_log_page (buffer); + +out: +kfree (buffer); +done: +ata_scsi_unblock_requests (ap); +} + +static void ahci_nonncq_timeout (struct ata_port *ap) {void *mmio = ap->host_set->mmio_base;void *port_mmio =ahci_port_base (mmio, ap->port_no);
@@ -620,13 +740,84 @@ static void ahci_eng_timeout(struct ata_ qc->scsidone = scsi_finish_command;ata_qc_complete (qc,ATA_ERR ); } +} + +static void ahci_eng_timeout (struct ata_port *ap) +{ +if (ap->flags &ATA_FLAG_NCQ_QUEUED ) +ahci_ncq_timeout (ap); +else +ahci_nonncq_timeout (ap); +} + +static inline void ahci_ncq_intr (struct ata_port *ap,u32 status) +{ +struct ahci_port_priv *pp = ap->private_data; +void *mmio = ap->host_set->mmio_base; +void *port_mmio =ahci_port_base (mmio, ap->port_no); +u32 sactive; + +if (status &PORT_IRQ_D2H_REG_FIS ) { +u8 *d2h_fis = pp->rx_fis +RX_FIS_D2H_REG ; + +/* +* pre-BSY clear error, let timeout error handling take care +* of it when it kicks in +*/ +if (d2h_fis[2 ] &ATA_ERR ) { +VPRINTK ("D2H fis, err %x\n" , d2h_fis[2 ]); +return ; + } + }else if (status &PORT_IRQ_SDB_FIS ) { +u8 *sdb_fis = pp->rx_fis +RX_FIS_SDB_REG ; + +if (sdb_fis[1 ] &ATA_ERR ) { +VPRINTK ("SDB fis, err %x\n" , sdb_fis[1 ]); +return ; + } + } + +/* +* SActive will have the bits cleared for completed commands +*/ + sactive =readl (port_mmio +PORT_SCR_ACT ); +ahci_complete_requests (ap, pp->sactive & ~sactive,0 ); + pp->sactive = sactive; +} + +static void ahci_ncq_intr_error (struct ata_port *ap,u32 status) +{ +struct ahci_port_priv *pp = ap->private_data; +struct ata_queued_cmd *qc; +struct ata_taskfile tf; +int tag; + +/* +* let command timeout deal with error handling +*/ +printk (KERN_ERR "ata%u: NCQ err status 0x%x\n" , ap->id, status); + +if (status &PORT_IRQ_D2H_REG_FIS ) { +ahci_tf_read (ap, &tf); + tag = tf.nsect >>3 ; + + qc =ata_qc_from_tag (ap, tag); +if (qc) { +printk (KERN_ERR "ata%u: ending bad tag %d\n" , ap->id, tag); + pp->sactive &= ~(1 << tag); +ata_qc_complete (qc,ATA_ERR ); + }else +printk (KERN_ERR "ata%u: error on tag %d, but not present\n" , ap->id, tag); + } +ata_scsi_block_requests (ap); } -static inline int ahci_host_intr (struct ata_port *ap,struct ata_queued_cmd *qc) +static inline int ahci_host_intr (struct ata_port *ap) {void *mmio = ap->host_set->mmio_base;void *port_mmio =ahci_port_base (mmio, ap->port_no); +struct ata_queued_cmd *qc;u32 status, serr, ci; serr =readl (port_mmio +PORT_SCR_ERR );
@@ -635,18 +826,28 @@ static inline int ahci_host_intr(struct status =readl (port_mmio +PORT_IRQ_STAT );writel (status, port_mmio +PORT_IRQ_STAT ); - ci =readl (port_mmio +PORT_CMD_ISSUE ); -if (likely ((ci &0x1 ) ==0 )) { -if (qc) { -ata_qc_complete (qc,0 ); - qc =NULL ; +if (ap->flags &ATA_FLAG_NCQ_QUEUED ) { +VPRINTK ("NCQ interrupt\n" ); + +if (unlikely (status &PORT_IRQ_FATAL )) +ahci_ncq_intr_error (ap, status); +else +ahci_ncq_intr (ap, status); + }else { +VPRINTK ("NON-NCQ interrupt\n" ); + ci =readl (port_mmio +PORT_CMD_ISSUE ); +if (likely ((ci &0x1 ) ==0 )) { + qc =ata_qc_from_tag (ap, ap->active_tag); +if (qc) +ata_qc_complete (qc,0 ); } - } -if (status &PORT_IRQ_FATAL ) { -ahci_intr_error (ap, status); -if (qc) -ata_qc_complete (qc,ATA_ERR ); +if (status &PORT_IRQ_FATAL ) { +ahci_intr_error (ap, status); + qc =ata_qc_from_tag (ap, ap->active_tag); +if (qc) +ata_qc_complete (qc,ATA_ERR ); + } }return 1 ;
@@ -686,9 +887,7 @@ static irqreturn_t ahci_interrupt (int i ap = host_set->ports[i]; tmp = irq_stat & (1 << i);if (tmp && ap) { -struct ata_queued_cmd *qc; - qc =ata_qc_from_tag (ap, ap->active_tag); -if (ahci_host_intr (ap, qc)) +if (ahci_host_intr (ap)) irq_ack |= (1 << i); } }
@@ -708,12 +907,17 @@ static irqreturn_t ahci_interrupt (int istatic int ahci_qc_issue (struct ata_queued_cmd *qc) {struct ata_port *ap = qc->ap; +struct ahci_port_priv *pp = qc->ap->private_data;void *port_mmio = (void *) ap->ioaddr.cmd_addr; -writel (1 , port_mmio +PORT_SCR_ACT ); -readl (port_mmio +PORT_SCR_ACT );/* flush */ +if (qc->flags &ATA_QCFLAG_NCQ ) { + pp->sactive |= (1 << qc->tag); -writel (1 , port_mmio +PORT_CMD_ISSUE ); +writel (1 << qc->tag, port_mmio +PORT_SCR_ACT ); +readl (port_mmio +PORT_SCR_ACT );/* flush */ + } + +writel (1 << qc->tag, port_mmio +PORT_CMD_ISSUE );readl (port_mmio +PORT_CMD_ISSUE );/* flush */ return 0 ;
@@ -1030,6 +1234,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 */
drivers/scsi/libata-core.c +241 -16
417 lines not on this page · raw message
drivers/scsi/libata-scsi.c +156 -19
275 lines not on this page · raw message
drivers/scsi/scsi_error.c +36 -3
@@ -1613,6 +1613,40 @@ static void scsi_unjam_host(struct Scsi_scsi_eh_flush_done_q (&eh_done_q); } +static void scsi_invoke_strategy_handler (struct Scsi_Host *shost) +{ +int rtn; +struct list_head *lh, *lh_sf; +struct scsi_cmnd *scmd; +unsigned long flags; +LIST_HEAD (eh_work_q); +LIST_HEAD (eh_done_q); + + rtn = shost->hostt->eh_strategy_handler (shost); + +spin_lock_irqsave (shost->host_lock, flags); +list_splice_init (&shost->eh_cmd_q, &eh_work_q); +spin_unlock_irqrestore (shost->host_lock, flags); + +SCSI_LOG_ERROR_RECOVERY (1 ,scsi_eh_prt_fail_stats (shost, &eh_work_q)); + +list_for_each_safe (lh, lh_sf, &eh_work_q) { + scmd = list_entry(lh, struct scsi_cmnd, eh_entry); + +if (scsi_eh_eflags_chk (scmd,SCSI_EH_CANCEL_CMD ) || + !SCSI_SENSE_VALID (scmd)) +continue ; + scmd->retries = scmd->allowed; +scsi_eh_finish_cmd (scmd, &eh_done_q); + } + +if (!list_empty (&eh_work_q)) +if (!scsi_eh_abort_cmds (&eh_work_q, &eh_done_q)) +scsi_eh_ready_devs (shost, &eh_work_q, &eh_done_q); + +scsi_eh_flush_done_q (&eh_done_q); +} +/** * scsi_error_handler - Handle errors/timeouts of SCSI cmds. * @data: Host for which we are running.
@@ -1627,7 +1661,6 @@ static void scsi_unjam_host(struct Scsi_int scsi_error_handler (void *data) {struct Scsi_Host *shost = (struct Scsi_Host *) data; -int rtn;DECLARE_MUTEX_LOCKED (sem);/*
@@ -1683,8 +1716,8 @@ int scsi_error_handler(void *data)* what we need to do to get it up and online again (if we can). * If we fail, we end up taking the thing offline. */ -if (shost->hostt->eh_strategy_handler) - rtn = shost->hostt->eh_strategy_handler (shost); +if (shost->hostt->eh_strategy_handler) +scsi_invoke_strategy_handler (shost);else scsi_unjam_host (shost);
drivers/scsi/scsi_lib.c +5 -1
@@ -1292,13 +1292,17 @@ static void scsi_request_fn(struct reque shost = sdev->host;while (!blk_queue_plugged (q)) {int rtn; + +if (!scsi_dev_queue_ready (q, sdev)) +break ; +/* * get next queueable request. We do this early to make sure * that the request is fully prepared even if we cannot * accept it. */ req =elv_next_request (q); -if (!req || !scsi_dev_queue_ready (q, sdev)) +if (!req)break ;if (unlikely (!scsi_device_online (sdev))) {
include/linux/ata.h +10 -0
@@ -125,9 +125,17 @@ enum {ATA_CMD_PACKET =0xA0 ,ATA_CMD_VERIFY =0x40 ,ATA_CMD_VERIFY_EXT =0x42 , +ATA_CMD_FPDMA_READ =0x60 , +ATA_CMD_FPDMA_WRITE =0x61 , +ATA_CMD_READ_LOG_EXT =0x2f , + +/* READ_LOG_EXT pages */ +READ_LOG_SATA_NCQ_PAGE =0x10 ,/* SETFEATURES stuff */ SETFEATURES_XFER =0x03 , +SETFEATURES_EN_WCACHE =0x02 , +SETFEATURES_DIS_WCACHE =0x82 ,XFER_UDMA_7 =0x47 ,XFER_UDMA_6 =0x46 , XFER_UDMA_5 = 0x45,
@@ -233,7 +241,9 @@ 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_removeable (id) ((id)[0] & (1 << 7)) +#define ata_id_queue_depth (id) (((id)[75] & 0x1f) + 1)#define ata_id_u32 (id,n) \ (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))#define ata_id_u64 (id,n) \
include/linux/libata.h +22 -3
@@ -80,7 +80,8 @@ enum {LIBATA_MAX_PRD =ATA_MAX_PRD /2 ,ATA_MAX_PORTS =8 ,ATA_DEF_QUEUE =1 , -ATA_MAX_QUEUE =1 , +ATA_MAX_CMDS =31 ,/* to avoid SActive 0xffffffff error */ +ATA_MAX_QUEUE =30 ,/* leave one command for errors */ ATA_MAX_SECTORS =200 ,/* FIXME */ ATA_MAX_BUS =2 , ATA_DEF_BUSY_WAIT = 10000,
@@ -95,6 +96,7 @@ enum {ATA_DFLAG_LBA48 = (1 <<0 ),/* device supports LBA48 */ ATA_DFLAG_PIO = (1 <<1 ),/* device currently in PIO mode */ ATA_DFLAG_LOCK_SECTORS = (1 <<2 ),/* don't adjust max_sectors */ +ATA_DFLAG_NCQ = (1 <<3 ),/* Device can do NCQ */ ATA_DEV_UNKNOWN =0 ,/* unknown device */ ATA_DEV_ATA = 1, /* ATA device */
@@ -113,11 +115,18 @@ enum {ATA_FLAG_MMIO = (1 <<6 ),/* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 <<7 ),/* use COMRESET */ ATA_FLAG_PIO_DMA = (1 <<8 ),/* PIO cmds via DMA */ +ATA_FLAG_NCQ = (1 <<9 ),/* Can do NCQ */ +ATA_FLAG_NCQ_QUEUED = (1 <<10 ),/* NCQ commands are queued */ ATA_QCFLAG_ACTIVE = (1 <<1 ),/* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 <<3 ),/* have s/g table? */ ATA_QCFLAG_SINGLE = (1 <<4 ),/* no s/g, just a single buffer */ ATA_QCFLAG_DMAMAP =ATA_QCFLAG_SG |ATA_QCFLAG_SINGLE , +ATA_QCFLAG_NCQ = (1 <<5 ),/* using NCQ */ +ATA_QCFLAG_PREEMPT = (1 <<6 ),/* for error handling */ + +ATA_QC_ISSUE_OK =0 , +ATA_QC_ISSUE_FATAL =-1 ,/* various lengths of time */ ATA_TMOUT_EDD = 5 * HZ, /* hueristic */
@@ -305,9 +314,13 @@ struct ata_port {struct ata_device device[ATA_MAX_DEVICES ]; -struct ata_queued_cmd qcmd[ATA_MAX_QUEUE ]; +struct ata_queued_cmd qcmd[ATA_MAX_CMDS ];unsigned long qactive;unsigned int active_tag; +unsigned int queue_depth; + +wait_queue_head_t cmd_wait_queue; +unsigned int cmd_waiters;struct ata_host_stats stats;struct ata_host_set *host_set;
@@ -434,6 +447,12 @@ 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 *,int ); +extern void ata_scsi_block_requests (struct ata_port *); +extern void ata_scsi_unblock_requests (struct ata_port *); +extern void ata_scsi_requeue (struct ata_queued_cmd *); +extern int ata_read_log_page (struct ata_port *,unsigned int ,char ,char *, +unsigned int );#ifdef CONFIG_PCI
@@ -453,7 +472,7 @@ extern int pci_test_config_bits(struct pstatic inline unsigned int ata_tag_valid (unsigned int tag) { -return (tag <ATA_MAX_QUEUE ) ?1 :0 ; +return (tag <ATA_MAX_CMDS ) ?1 :0 ; }static inline unsigned int ata_dev_present (struct ata_device *dev)
Signature · 1 line
Jens Axboe
Quoted 1 line · Jens Axboe
- (libata) import an error handling fix from Hannes.
Keep this separate, his fix is busted. Calling scsi_eh_abort_cmds() without an abort handler is highly ineffective, and highly silly.
Quoted 2 lines
Jeff, I'll update your ncq branch at the end of this week if you don't beat me to it.
Just an incremental patch will do it :)
Jeff
Quoted 5 lines · Jeff Garzik
Quoted 1 line · Jens Axboe
- (libata) import an error handling fix from Hannes.
Keep this separate, his fix is busted. Calling
scsi_eh_abort_cmds()without an abort handler is highly ineffective, and highly silly.
Irk, I didn't follow the recent discussion. I'll kill the fix locally for now.
Quoted 4 lines
Quoted 2 lines
Jeff, I'll update your ncq branch at the end of this week if you don't beat me to it.
Just an incremental patch will do it :)
Ok, will get you on.
Signature · 1 line
Jens Axboe
BTW, does the AHCI PCI MSI patch work for you?
I still haven't gotten any acks back from anybody yet, and PCI MSI support should make the driver even more efficient.
Jeff
drivers/scsi/ahci.c +63 -10
@@ -152,6 +152,7 @@ struct ahci_sg {struct ahci_host_priv {unsigned long flags; +unsigned int have_msi;/* is PCI MSI enabled? */ u32 cap;/* cache of HOST_CAP register */ u32 port_map;/* cache of HOST_PORTS_IMPL reg */ };
@@ -182,6 +183,7 @@ static void ahci_qc_prep(struct ata_queustatic u8 ahci_check_status (struct ata_port *ap);static u8 ahci_check_err (struct ata_port *ap);static inline int ahci_host_intr (struct ata_port *ap,struct ata_queued_cmd *qc); +static void ahci_remove_one (struct pci_dev *pdev);static Scsi_Host_Template ahci_sht = { .module =THIS_MODULE ,
@@ -271,7 +273,7 @@ static struct pci_driver ahci_pci_driver .name = DRV_NAME, .id_table = ahci_pci_tbl, .probe = ahci_init_one, - .remove = ata_pci_remove_one, + .remove = ahci_remove_one, };
@@ -876,15 +878,19 @@ static int ahci_host_init(struct ata_pro }/* move to PCI layer, integrate w/ MSI stuff */ -static void pci_enable_intx (struct pci_dev *pdev) +static void pci_intx (struct pci_dev *pdev,int enable) { -u16 pci_command; +u16 pci_command, new;pci_read_config_word (pdev,PCI_COMMAND , &pci_command); -if (pci_command &PCI_COMMAND_INTX_DISABLE ) { - pci_command &= ~PCI_COMMAND_INTX_DISABLE ; + +if (enable) + new = pci_command & ~PCI_COMMAND_INTX_DISABLE ; +else + new = pci_command |PCI_COMMAND_INTX_DISABLE ; + +if (new != pci_command)pci_write_config_word (pdev,PCI_COMMAND , pci_command); - } }static void ahci_print_info (struct ata_probe_ent *probe_ent)
@@ -966,7 +972,7 @@ static int ahci_init_one (struct pci_devunsigned long base;void *mmio_base;unsigned int board_idx = (unsigned int ) ent->driver_data; -int pci_dev_busy =0 ; +int have_msi, pci_dev_busy =0 ;int rc;VPRINTK ("ENTER\n" );
@@ -984,12 +990,17 @@ static int ahci_init_one (struct pci_dev goto err_out; } -pci_enable_intx (pdev); +if (pci_enable_msi (pdev) ==0 ) + have_msi =1 ; +else { +pci_intx (pdev,1 ); + have_msi =0 ; + } probe_ent =kmalloc (sizeof (*probe_ent),GFP_KERNEL );if (probe_ent ==NULL ) { rc = -ENOMEM ; - goto err_out_regions; + goto err_out_msi; }memset (probe_ent,0 ,sizeof (*probe_ent));
@@ -1022,6 +1033,8 @@ static int ahci_init_one (struct pci_dev probe_ent->mmio_base = mmio_base; probe_ent->private_data = hpriv; + hpriv->have_msi = have_msi; +/* initialize adapter */ rc =ahci_host_init (probe_ent);if (rc)
@@ -1041,7 +1054,11 @@ err_out_iounmap:iounmap (mmio_base); err_out_free_ent:kfree (probe_ent); -err_out_regions: +err_out_msi: +if (have_msi) +pci_disable_msi (pdev); +else +pci_intx (pdev,0 );pci_release_regions (pdev); err_out:if (!pci_dev_busy)
@@ -1049,6 +1066,42 @@ err_out:return rc; } +static void ahci_remove_one (struct pci_dev *pdev) +{ +struct device *dev =pci_dev_to_dev (pdev); +struct ata_host_set *host_set =dev_get_drvdata (dev); +struct ahci_host_priv *hpriv = host_set->private_data; +struct ata_port *ap; +unsigned int i; +int have_msi; + +for (i =0 ; i < host_set->n_ports; i++) { + ap = host_set->ports[i]; + +scsi_remove_host (ap->host); + } + + have_msi = hpriv->have_msi; +free_irq (host_set->irq, host_set); + host_set->ops->host_stop (host_set); +iounmap (host_set->mmio_base); + +for (i =0 ; i < host_set->n_ports; i++) { + ap = host_set->ports[i]; + +ata_scsi_release (ap->host); +scsi_host_put (ap->host); + } + +if (have_msi) +pci_disable_msi (pdev); +else +pci_intx (pdev,0 ); +pci_release_regions (pdev); +kfree (host_set); +pci_disable_device (pdev); +dev_set_drvdata (dev,NULL ); +}static int __init ahci_init (void ) {
Quoted 4 lines · Jeff Garzik
BTW, does the AHCI PCI MSI patch work for you?
I still haven't gotten any acks back from anybody yet, and PCI MSI support should make the driver even more efficient.
I will give it a shot, cannot before the morning though.
Signature · 1 line
Jens Axboe
Jeff Garzik wrote:
[]
drivers/scsi/ahci.c struct ahci_sg { · line 155
Quoted 4 lines
struct
ahci_host_priv{drivers/scsi/ahci.c +1
-0unsigned long flags; +unsigned int have_msi;/* is PCI MSI enabled? */
BTW, can have_msi' be just another bit in the flags' field?
/mjt
Quoted 10 lines · Michael Tokarev
Jeff Garzik wrote:
[]drivers/scsi/ahci.c struct ahci_sg { · line 155
Quoted 4 lines
struct ahci_host_priv { unsigned long flags;drivers/scsi/ahci.c +1
-0+unsigned int have_msi;/* is PCI MSI enabled? */ BTW, can
have_msi' be just another bit in theflags' field?
Yes, that would be a good cleanup to make.
Wanna submit a patch adding HOST_CAP_MSI bit?
Jeff