From 312f7da2824c82800ee78d6190f12854456957af Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 27 Sep 2005 17:38:03 +0800 Subject: [PATCH] libata: interrupt driven pio for libata-core - add PIO_ST_FIRST for the state before sending ATAPI CDB or sending "ATA PIO data out" first data block. - add ATA_TFLAG_POLLING and ATA_DFLAG_CDB_INTR flags - remove the ATA_FLAG_NOINTR flag since the interrupt handler is now aware of the states - modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt context - modify the ata_host_intr() to handle PIO interrupts - modify ata_qc_issue_prot() to initialize states - atapi_packet_task() changed to handle "ATA PIO data out" first data block - support the pre-ATA4 ATAPI device which raise interrupt when ready to receive CDB Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c4fcdc3..cc2d130 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1292,6 +1292,9 @@ retry: ap->cdb_len = (unsigned int) rc; ap->host->max_cmd_len = (unsigned char) ap->cdb_len; + if (ata_id_cdb_intr(dev->id)) + dev->flags |= ATA_DFLAG_CDB_INTR; + /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", ap->id, device, @@ -2405,7 +2408,6 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) unsigned long flags; spin_lock_irqsave(&ap->host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; ata_irq_on(ap); ata_qc_complete(qc, drv_stat); spin_unlock_irqrestore(&ap->host_set->lock, flags); @@ -2660,6 +2662,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) struct page *page; unsigned int offset; unsigned char *buf; + unsigned long flags; if (qc->cursect == (qc->nsect - 1)) ap->hsm_task_state = HSM_ST_LAST; @@ -2671,7 +2674,8 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) page = nth_page(page, (offset >> PAGE_SHIFT)); offset %= PAGE_SIZE; - buf = kmap(page) + offset; + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0) + offset; qc->cursect++; qc->cursg_ofs++; @@ -2687,7 +2691,8 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) do_write = (qc->tf.flags & ATA_TFLAG_WRITE); ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); - kunmap(page); + kunmap_atomic(buf - offset, KM_IRQ0); + local_irq_restore(flags); } /** @@ -2710,6 +2715,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) struct page *page; unsigned char *buf; unsigned int offset, count; + unsigned long flags; if (qc->curbytes + bytes >= qc->nbytes) ap->hsm_task_state = HSM_ST_LAST; @@ -2753,7 +2759,8 @@ next_sg: /* don't cross page boundaries */ count = min(count, (unsigned int)PAGE_SIZE - offset); - buf = kmap(page) + offset; + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0) + offset; bytes -= count; qc->curbytes += count; @@ -2769,7 +2776,8 @@ next_sg: /* do the actual data transfer */ ata_data_xfer(ap, buf, count, do_write); - kunmap(page); + kunmap_atomic(buf - offset, KM_IRQ0); + local_irq_restore(flags); if (bytes) goto next_sg; @@ -2808,6 +2816,8 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) if (do_write != i_write) goto err_out; + VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes); + __atapi_pio_bytes(qc, bytes); return; @@ -3054,6 +3064,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", ap->id, qc->tf.command, drv_stat, host_stat); + ap->hsm_task_state = HSM_ST_IDLE; + /* complete taskfile transaction */ ata_qc_complete(qc, drv_stat); break; @@ -3344,43 +3356,96 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); + /* start the command */ switch (qc->tf.protocol) { case ATA_PROT_NODATA: + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); + ap->hsm_task_state = HSM_ST_LAST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + queue_work(ata_wq, &ap->pio_task); + break; case ATA_PROT_DMA: + assert(!(qc->tf.flags & ATA_TFLAG_POLLING)); + ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ ap->ops->bmdma_start(qc); /* initiate bmdma */ + ap->hsm_task_state = HSM_ST_LAST; break; - case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ - ata_qc_set_polling(qc); + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); - ap->hsm_task_state = HSM_ST; - queue_work(ata_wq, &ap->pio_task); + + if (qc->tf.flags & ATA_TFLAG_POLLING) { + /* polling PIO */ + ap->hsm_task_state = HSM_ST; + queue_work(ata_wq, &ap->pio_task); + } else { + /* interrupt driven PIO */ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* PIO data out protocol */ + ap->hsm_task_state = HSM_ST_FIRST; + queue_work(ata_wq, &ap->packet_task); + + /* send first data block by polling */ + } else { + /* PIO data in protocol */ + ap->hsm_task_state = HSM_ST; + + /* interrupt handler takes over from here */ + } + } + break; case ATA_PROT_ATAPI: - ata_qc_set_polling(qc); + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); - queue_work(ata_wq, &ap->packet_task); + ap->hsm_task_state = HSM_ST_FIRST; + + /* send cdb by polling if no cdb interrupt */ + if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || + (qc->tf.flags & ATA_TFLAG_POLLING)) + queue_work(ata_wq, &ap->packet_task); break; case ATA_PROT_ATAPI_NODATA: - ap->flags |= ATA_FLAG_NOINTR; + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); - queue_work(ata_wq, &ap->packet_task); + ap->hsm_task_state = HSM_ST_FIRST; + + /* send cdb by polling if no cdb interrupt */ + if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || + (qc->tf.flags & ATA_TFLAG_POLLING)) + queue_work(ata_wq, &ap->packet_task); break; case ATA_PROT_ATAPI_DMA: - ap->flags |= ATA_FLAG_NOINTR; + assert(!(qc->tf.flags & ATA_TFLAG_POLLING)); + ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ - queue_work(ata_wq, &ap->packet_task); + ap->hsm_task_state = HSM_ST_FIRST; + + /* send cdb by polling if no cdb interrupt */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + queue_work(ata_wq, &ap->packet_task); break; default: @@ -3623,6 +3688,42 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) } /** + * atapi_send_cdb - Write CDB bytes to hardware + * @ap: Port to which ATAPI device is attached. + * @qc: Taskfile currently active + * + * When device has indicated its readiness to accept + * a CDB, this function is called. Send the CDB. + * + * LOCKING: + * caller. + */ + +static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + /* send SCSI cdb */ + DPRINTK("send cdb\n"); + assert(ap->cdb_len >= 12); + + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); + ata_altstatus(ap); /* flush */ + + switch (qc->tf.protocol) { + case ATA_PROT_ATAPI: + ap->hsm_task_state = HSM_ST; + break; + case ATA_PROT_ATAPI_NODATA: + ap->hsm_task_state = HSM_ST_LAST; + break; + case ATA_PROT_ATAPI_DMA: + ap->hsm_task_state = HSM_ST_LAST; + /* initiate bmdma */ + ap->ops->bmdma_start(qc); + break; + } +} + +/** * ata_host_intr - Handle host interrupt for given (port, task) * @ap: Port on which interrupt arrived (possibly...) * @qc: Taskfile currently active in engine @@ -3641,47 +3742,142 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { - u8 status, host_stat; - - switch (qc->tf.protocol) { + u8 status, host_stat = 0; - case ATA_PROT_DMA: - case ATA_PROT_ATAPI_DMA: - case ATA_PROT_ATAPI: - /* check status of DMA engine */ - host_stat = ap->ops->bmdma_status(ap); - VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); + VPRINTK("ata%u: protocol %d task_state %d\n", + ap->id, qc->tf.protocol, ap->hsm_task_state); - /* if it's not our irq... */ - if (!(host_stat & ATA_DMA_INTR)) + /* Check whether we are expecting interrupt in this state */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Check the ATA_DFLAG_CDB_INTR flag is enough here. + * The flag was turned on only for atapi devices. + * No need to check is_atapi_taskfile(&qc->tf) again. + */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) goto idle_irq; + break; + case HSM_ST_LAST: + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + /* check status of DMA engine */ + host_stat = ap->ops->bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); + + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; + + /* before we do anything else, clear DMA-Start bit */ + ap->ops->bmdma_stop(qc); + } + break; + case HSM_ST: + break; + default: + goto idle_irq; + } - /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(qc); + /* check altstatus */ + status = ata_altstatus(ap); + if (status & ATA_BUSY) + goto idle_irq; - /* fall through */ + /* check main status, clearing INTRQ */ + status = ata_chk_status(ap); + if (unlikely(status & ATA_BUSY)) + goto idle_irq; - case ATA_PROT_ATAPI_NODATA: - case ATA_PROT_NODATA: - /* check altstatus */ - status = ata_altstatus(ap); - if (status & ATA_BUSY) - goto idle_irq; + DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, ap->hsm_task_state, status); - /* check main status, clearing INTRQ */ - status = ata_chk_status(ap); - if (unlikely(status & ATA_BUSY)) - goto idle_irq; - DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", - ap->id, qc->tf.protocol, status); + /* ack bmdma irq events */ + ap->ops->irq_clear(ap); - /* ack bmdma irq events */ - ap->ops->irq_clear(ap); + /* check error */ + if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR))) + ap->hsm_task_state = HSM_ST_ERR; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + + /* check device status */ + if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { + /* Wrong status. Let EH handle this */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + atapi_send_cdb(ap, qc); + + break; + + case HSM_ST: + /* complete command or read/write the data register */ + if (qc->tf.protocol == ATA_PROT_ATAPI) { + /* ATAPI PIO protocol */ + if ((status & ATA_DRQ) == 0) { + /* no more data to transfer */ + ap->hsm_task_state = HSM_ST_LAST; + goto fsm_start; + } + + atapi_pio_bytes(qc); + + if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) + /* bad ireason reported by device */ + goto fsm_start; + + } else { + /* ATA PIO protocol */ + if (unlikely((status & ATA_DRQ) == 0)) { + /* handle BSY=0, DRQ=0 as error */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sector(qc); + + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + /* all data read */ + ata_altstatus(ap); + status = ata_chk_status(ap); + goto fsm_start; + } + } + + ata_altstatus(ap); /* flush */ + break; + + case HSM_ST_LAST: + if (unlikely(status & ATA_DRQ)) { + /* handle DRQ=1 as error */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* no more data to transfer */ + DPRINTK("ata%u: command complete, drv_stat 0x%x\n", + ap->id, status); + + ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ ata_qc_complete(qc, status); break; + case HSM_ST_ERR: + printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", + ap->id, status, host_stat); + + ap->hsm_task_state = HSM_ST_IDLE; + ata_qc_complete(qc, status | ATA_ERR); + break; default: goto idle_irq; } @@ -3733,11 +3929,11 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) ap = host_set->ports[i]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN)) && + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && (qc->flags & ATA_QCFLAG_ACTIVE)) handled |= ata_host_intr(ap, qc); } @@ -3767,6 +3963,7 @@ static void atapi_packet_task(void *_data) struct ata_port *ap = _data; struct ata_queued_cmd *qc; u8 status; + unsigned long flags; qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); @@ -3782,38 +3979,40 @@ static void atapi_packet_task(void *_data) if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) goto err_out; - /* send SCSI cdb */ - DPRINTK("send cdb\n"); - assert(ap->cdb_len >= 12); + /* Send the CDB (atapi) or the first data block (ata pio out). + * During the state transition, interrupt handler shouldn't + * be invoked before the data transfer is complete and + * hsm_task_state is changed. Hence, the following locking. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { - unsigned long flags; + if (is_atapi_taskfile(&qc->tf)) { + /* send CDB */ + atapi_send_cdb(ap, qc); - /* Once we're done issuing command and kicking bmdma, - * irq handler takes over. To not lose irq, we need - * to clear NOINTR flag before sending cdb, but - * interrupt handler shouldn't be invoked before we're - * finished. Hence, the following locking. - */ - spin_lock_irqsave(&ap->host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; - ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) - ap->ops->bmdma_start(qc); /* initiate bmdma */ - spin_unlock_irqrestore(&ap->host_set->lock, flags); + if (qc->tf.flags & ATA_TFLAG_POLLING) + queue_work(ata_wq, &ap->pio_task); } else { - ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); + /* PIO data out protocol. + * send first data block. + */ - /* PIO commands are handled by polling */ + /* ata_pio_sector() might change the state to HSM_ST_LAST. + * so, the state is changed here before ata_pio_sector(). + */ ap->hsm_task_state = HSM_ST; - queue_work(ata_wq, &ap->pio_task); + ata_pio_sector(qc); + ata_altstatus(ap); /* flush */ + + /* interrupt handler takes over from here */ } + spin_unlock_irqrestore(&ap->host_set->lock, flags); + return; err_out: - ata_poll_qc_complete(qc, ATA_ERR); + ata_pio_error(ap); } diff --git a/include/linux/ata.h b/include/linux/ata.h index a5b74ef..6fec2f6 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -181,6 +181,7 @@ enum { ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ + ATA_TFLAG_POLLING = (1 << 4), /* set nIEN to 1 and use polling */ }; enum ata_tf_protocols { @@ -250,6 +251,8 @@ struct ata_taskfile { ((u64) (id)[(n) + 1] << 16) | \ ((u64) (id)[(n) + 0]) ) +#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20) + static inline int atapi_cdb_len(u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; diff --git a/include/linux/libata.h b/include/linux/libata.h index bb2d916..9ac2b69 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -97,6 +97,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_CDB_INTR = (1 << 3), /* device asserts INTRQ when ready for CDB */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -115,8 +116,6 @@ 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_NOINTR = (1 << 9), /* FIXME: Remove this once - * proper HSM is in place. */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ @@ -165,6 +164,7 @@ enum hsm_task_states { HSM_ST_LAST, HSM_ST_LAST_POLL, HSM_ST_ERR, + HSM_ST_FIRST, }; /* forward declarations */ -- cgit v0.10.2 From e50362eccd8809a224cda5f71714a088ba37b2ab Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 27 Sep 2005 17:39:50 +0800 Subject: [PATCH] libata: interrupt driven pio for LLD libata.h: libata-core: Add ATA_FLAG_PIO_POLLING flag for LLDs that expect interrupt for command completion only. sata_nv.c: sata_vsc.c: irq handler is wrapper around ata_host_intr(), can handle PIO interrupts. sata_promise.c: sata_sx4.c: sata_qstor.c: sata_mv.c: Private irq handler. Polling mode ATA_FLAG_PIO_POLLING used for compatibility. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cc2d130..f8a590e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3356,6 +3356,25 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + /* Use polling pio if the LLD doesn't handle + * interrupt driven pio and atapi CDB interrupt. + */ + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + case ATA_PROT_ATAPI_DMA: + if (qc->dev->flags & ATA_DFLAG_CDB_INTR) + BUG(); + break; + default: + break; + } + } + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ea76fe4..b8f1f69 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -241,7 +241,8 @@ static struct ata_port_info mv_port_info[] = { { /* chip_504x */ .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING), .pio_mask = 0x1f, /* pio4-0 */ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ .port_ops = &mv_ops, @@ -250,7 +251,7 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_DUAL_HC), + ATA_FLAG_PIO_POLLING | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio4-0 */ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ .port_ops = &mv_ops, @@ -259,6 +260,7 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING | MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA), .pio_mask = 0x1f, /* pio4-0 */ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ @@ -268,6 +270,7 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING | MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC | MV_FLAG_BDMA), .pio_mask = 0x1f, /* pio4-0 */ diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index c05653c..8b7e871 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -304,11 +304,11 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, ap = host_set->ports[i]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); } diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index def7e0d..f67deb0 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -162,7 +162,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_ata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_SRST | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -173,7 +174,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_ata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_SRST | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -184,7 +186,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_ata_sht, .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | - ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS, + ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -493,11 +496,11 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r ap = host_set->ports[i]; tmp = mask & (1 << (i + 1)); if (tmp && ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc_host_intr(ap, qc); } } diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index ffcdeb6..a604afa 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -175,7 +175,7 @@ static struct ata_port_info qs_port_info[] = { .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | //FIXME ATA_FLAG_SRST | - ATA_FLAG_MMIO, + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &qs_ata_ops, @@ -389,14 +389,13 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set) DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", sff1, sff0, port_no, sHST, sDST); handled = 1; - if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { switch (sHST) { case 0: /* sucessful CPB */ case 3: /* device error */ @@ -422,13 +421,13 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) struct ata_port *ap; ap = host_set->ports[port_no]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ u8 status = ata_chk_status(ap); diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 540a851..a9f9f76 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -219,7 +219,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_SRST | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -832,11 +833,11 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re tmp = mask & (1 << i); VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp); if (tmp && ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc20621_host_intr(ap, qc, (i > 4), mmio_base); } diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index cf94e01..92378d7 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -193,12 +193,12 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct ata_port *ap; ap = host_set->ports[i]; - if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + if (ap && + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 9ac2b69..ea8ab29 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -116,6 +116,8 @@ 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_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ -- cgit v0.10.2 From c56b14d2a3e32695e13cd49b417da889da744d1c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Sep 2005 19:07:39 +0800 Subject: [PATCH] libata irq-pio: add comments and cleanup Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f8a590e..617836a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3430,18 +3430,6 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_ATAPI: - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_qc_set_polling(qc); - - ata_tf_to_host_nolock(ap, &qc->tf); - ap->hsm_task_state = HSM_ST_FIRST; - - /* send cdb by polling if no cdb interrupt */ - if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || - (qc->tf.flags & ATA_TFLAG_POLLING)) - queue_work(ata_wq, &ap->packet_task); - break; - case ATA_PROT_ATAPI_NODATA: if (qc->tf.flags & ATA_TFLAG_POLLING) ata_qc_set_polling(qc); diff --git a/include/linux/libata.h b/include/linux/libata.h index ea8ab29..1fcd0ef 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -158,15 +158,16 @@ enum { }; enum hsm_task_states { - HSM_ST_UNKNOWN, - HSM_ST_IDLE, - HSM_ST_POLL, - HSM_ST_TMOUT, - HSM_ST, - HSM_ST_LAST, - HSM_ST_LAST_POLL, - HSM_ST_ERR, - HSM_ST_FIRST, + HSM_ST_UNKNOWN, /* state unknown */ + HSM_ST_IDLE, /* no command on going */ + HSM_ST_POLL, /* same as HSM_ST, waits longer */ + HSM_ST_TMOUT, /* timeout */ + HSM_ST, /* (waiting the device to) transfer data */ + HSM_ST_LAST, /* (waiting the device to) complete command */ + HSM_ST_LAST_POLL, /* same as HSM_ST_LAST, waits longer */ + HSM_ST_ERR, /* error */ + HSM_ST_FIRST, /* (waiting the device to) + write CDB or first data block */ }; /* forward declarations */ -- cgit v0.10.2 From f9997be974be40e884e9e8157ded2f2f9aed454c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Sep 2005 19:09:31 +0800 Subject: [PATCH] libata irq-pio: rename atapi_packet_task() and comments Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 617836a..a63758d 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3416,7 +3416,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - queue_work(ata_wq, &ap->packet_task); + queue_work(ata_wq, &ap->dataout_task); /* send first data block by polling */ } else { @@ -3440,7 +3440,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - queue_work(ata_wq, &ap->packet_task); + queue_work(ata_wq, &ap->dataout_task); break; case ATA_PROT_ATAPI_DMA: @@ -3452,7 +3452,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - queue_work(ata_wq, &ap->packet_task); + queue_work(ata_wq, &ap->dataout_task); break; default: @@ -3952,20 +3952,21 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) } /** - * atapi_packet_task - Write CDB bytes to hardware - * @_data: Port to which ATAPI device is attached. + * ata_dataout_task - Write first data block to hardware + * @_data: Port to which ATA/ATAPI device is attached. * * When device has indicated its readiness to accept - * a CDB, this function is called. Send the CDB. - * If DMA is to be performed, exit immediately. - * Otherwise, we are in polling mode, so poll - * status under operation succeeds or fails. + * the data, this function sends out the CDB or + * the first data block by PIO. + * After this, + * - If polling, ata_pio_task() handles the rest. + * - Otherwise, interrupt handler takes over. * * LOCKING: * Kernel thread context (may sleep) */ -static void atapi_packet_task(void *_data) +static void ata_dataout_task(void *_data) { struct ata_port *ap = _data; struct ata_queued_cmd *qc; @@ -3978,7 +3979,7 @@ static void atapi_packet_task(void *_data) /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) + if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) goto err_out; /* make sure DRQ is set */ @@ -4141,7 +4142,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; - INIT_WORK(&ap->packet_task, atapi_packet_task, ap); + INIT_WORK(&ap->dataout_task, ata_dataout_task, ap); INIT_WORK(&ap->pio_task, ata_pio_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) diff --git a/include/linux/libata.h b/include/linux/libata.h index 1fcd0ef..7e6feb9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -129,8 +129,8 @@ enum { ATA_TMOUT_PIO = 30 * HZ, ATA_TMOUT_BOOT = 30 * HZ, /* hueristic */ ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* hueristic */ - ATA_TMOUT_CDB = 30 * HZ, - ATA_TMOUT_CDB_QUICK = 5 * HZ, + ATA_TMOUT_DATAOUT = 30 * HZ, + ATA_TMOUT_DATAOUT_QUICK = 5 * HZ, /* ATA bus states */ BUS_UNKNOWN = 0, @@ -319,7 +319,7 @@ struct ata_port { struct ata_host_stats stats; struct ata_host_set *host_set; - struct work_struct packet_task; + struct work_struct dataout_task; struct work_struct pio_task; unsigned int hsm_task_state; -- cgit v0.10.2 From 86a7397cda08a65bc4f306e812c846e2437b5347 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Sep 2005 19:11:35 +0800 Subject: [PATCH] libata irq-pio: simplify if condition in ata_dataout_task() - Use if (qc->tf.protocol == ATA_PROT_PIO) instead of if(is_atapi_taskfile()) in ata_dataout_task() Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index a63758d..cf5a138 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3994,13 +3994,7 @@ static void ata_dataout_task(void *_data) */ spin_lock_irqsave(&ap->host_set->lock, flags); - if (is_atapi_taskfile(&qc->tf)) { - /* send CDB */ - atapi_send_cdb(ap, qc); - - if (qc->tf.flags & ATA_TFLAG_POLLING) - queue_work(ata_wq, &ap->pio_task); - } else { + if (qc->tf.protocol == ATA_PROT_PIO) { /* PIO data out protocol. * send first data block. */ @@ -4013,6 +4007,12 @@ static void ata_dataout_task(void *_data) ata_altstatus(ap); /* flush */ /* interrupt handler takes over from here */ + } else { + /* send CDB */ + atapi_send_cdb(ap, qc); + + if (qc->tf.flags & ATA_TFLAG_POLLING) + queue_work(ata_wq, &ap->pio_task); } spin_unlock_irqrestore(&ap->host_set->lock, flags); -- cgit v0.10.2 From 54f00389563c80fa1de250a21256313ba01ca07d Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Sep 2005 19:14:19 +0800 Subject: [PATCH] libata irq-pio: cleanup ata_qc_issue_prot() ata_qc_issue_prot(): - cleanup and let the PIO data out case always go through the ata_dataout_task() codepath. (Previously for PIO data out case, 2 code pathes were used - irq case goes through ata_data_out_task() codepath. - polling case jumps over the HSM_ST_FIRST state and goes to HSM_ST and ata_pio_task() directly.) ata_dataout_task(): - rearrange the queue_work() code to handle the PIO data out + polling case. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cf5a138..02a7a9e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3407,24 +3407,24 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) ata_tf_to_host_nolock(ap, &qc->tf); - if (qc->tf.flags & ATA_TFLAG_POLLING) { - /* polling PIO */ - ap->hsm_task_state = HSM_ST; - queue_work(ata_wq, &ap->pio_task); + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* PIO data out protocol */ + ap->hsm_task_state = HSM_ST_FIRST; + queue_work(ata_wq, &ap->dataout_task); + + /* always send first data block using + * the ata_dataout_task() codepath. + */ } else { - /* interrupt driven PIO */ - if (qc->tf.flags & ATA_TFLAG_WRITE) { - /* PIO data out protocol */ - ap->hsm_task_state = HSM_ST_FIRST; - queue_work(ata_wq, &ap->dataout_task); - - /* send first data block by polling */ - } else { - /* PIO data in protocol */ - ap->hsm_task_state = HSM_ST; - - /* interrupt handler takes over from here */ - } + /* PIO data in protocol */ + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + queue_work(ata_wq, &ap->pio_task); + + /* if polling, ata_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ } break; @@ -4005,15 +4005,15 @@ static void ata_dataout_task(void *_data) ap->hsm_task_state = HSM_ST; ata_pio_sector(qc); ata_altstatus(ap); /* flush */ - - /* interrupt handler takes over from here */ - } else { + } else /* send CDB */ atapi_send_cdb(ap, qc); - if (qc->tf.flags & ATA_TFLAG_POLLING) - queue_work(ata_wq, &ap->pio_task); - } + /* if polling, ata_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ + if (qc->tf.flags & ATA_TFLAG_POLLING) + queue_work(ata_wq, &ap->pio_task); spin_unlock_irqrestore(&ap->host_set->lock, flags); -- cgit v0.10.2 From c71c18576d0d8aa4db876c737c3c597c724cf02f Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 4 Oct 2005 06:03:45 -0400 Subject: libata: move atapi_send_cdb() and ata_dataout_task() to be near ata_pio_*() functions diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 5463368..ff291b3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2782,6 +2782,114 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) } /** + * atapi_send_cdb - Write CDB bytes to hardware + * @ap: Port to which ATAPI device is attached. + * @qc: Taskfile currently active + * + * When device has indicated its readiness to accept + * a CDB, this function is called. Send the CDB. + * + * LOCKING: + * caller. + */ + +static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + /* send SCSI cdb */ + DPRINTK("send cdb\n"); + assert(ap->cdb_len >= 12); + + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); + ata_altstatus(ap); /* flush */ + + switch (qc->tf.protocol) { + case ATA_PROT_ATAPI: + ap->hsm_task_state = HSM_ST; + break; + case ATA_PROT_ATAPI_NODATA: + ap->hsm_task_state = HSM_ST_LAST; + break; + case ATA_PROT_ATAPI_DMA: + ap->hsm_task_state = HSM_ST_LAST; + /* initiate bmdma */ + ap->ops->bmdma_start(qc); + break; + } +} + +/** + * ata_dataout_task - Write first data block to hardware + * @_data: Port to which ATA/ATAPI device is attached. + * + * When device has indicated its readiness to accept + * the data, this function sends out the CDB or + * the first data block by PIO. + * After this, + * - If polling, ata_pio_task() handles the rest. + * - Otherwise, interrupt handler takes over. + * + * LOCKING: + * Kernel thread context (may sleep) + */ + +static void ata_dataout_task(void *_data) +{ + struct ata_port *ap = _data; + struct ata_queued_cmd *qc; + u8 status; + unsigned long flags; + + qc = ata_qc_from_tag(ap, ap->active_tag); + assert(qc != NULL); + assert(qc->flags & ATA_QCFLAG_ACTIVE); + + /* sleep-wait for BSY to clear */ + DPRINTK("busy wait\n"); + if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) + goto err_out; + + /* make sure DRQ is set */ + status = ata_chk_status(ap); + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) + goto err_out; + + /* Send the CDB (atapi) or the first data block (ata pio out). + * During the state transition, interrupt handler shouldn't + * be invoked before the data transfer is complete and + * hsm_task_state is changed. Hence, the following locking. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + + /* ata_pio_sector() might change the state to HSM_ST_LAST. + * so, the state is changed here before ata_pio_sector(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sector(qc); + ata_altstatus(ap); /* flush */ + } else + /* send CDB */ + atapi_send_cdb(ap, qc); + + /* if polling, ata_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ + if (qc->tf.flags & ATA_TFLAG_POLLING) + queue_work(ata_wq, &ap->pio_task); + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + return; + +err_out: + ata_pio_error(ap); +} + +/** * __atapi_pio_bytes - Transfer data from/to the ATAPI device. * @qc: Command on going * @bytes: number of bytes @@ -3785,42 +3893,6 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) } /** - * atapi_send_cdb - Write CDB bytes to hardware - * @ap: Port to which ATAPI device is attached. - * @qc: Taskfile currently active - * - * When device has indicated its readiness to accept - * a CDB, this function is called. Send the CDB. - * - * LOCKING: - * caller. - */ - -static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) -{ - /* send SCSI cdb */ - DPRINTK("send cdb\n"); - assert(ap->cdb_len >= 12); - - ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); - ata_altstatus(ap); /* flush */ - - switch (qc->tf.protocol) { - case ATA_PROT_ATAPI: - ap->hsm_task_state = HSM_ST; - break; - case ATA_PROT_ATAPI_NODATA: - ap->hsm_task_state = HSM_ST_LAST; - break; - case ATA_PROT_ATAPI_DMA: - ap->hsm_task_state = HSM_ST_LAST; - /* initiate bmdma */ - ap->ops->bmdma_start(qc); - break; - } -} - -/** * ata_host_intr - Handle host interrupt for given (port, task) * @ap: Port on which interrupt arrived (possibly...) * @qc: Taskfile currently active in engine @@ -4042,79 +4114,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) } /** - * ata_dataout_task - Write first data block to hardware - * @_data: Port to which ATA/ATAPI device is attached. - * - * When device has indicated its readiness to accept - * the data, this function sends out the CDB or - * the first data block by PIO. - * After this, - * - If polling, ata_pio_task() handles the rest. - * - Otherwise, interrupt handler takes over. - * - * LOCKING: - * Kernel thread context (may sleep) - */ - -static void ata_dataout_task(void *_data) -{ - struct ata_port *ap = _data; - struct ata_queued_cmd *qc; - u8 status; - unsigned long flags; - - qc = ata_qc_from_tag(ap, ap->active_tag); - assert(qc != NULL); - assert(qc->flags & ATA_QCFLAG_ACTIVE); - - /* sleep-wait for BSY to clear */ - DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) - goto err_out; - - /* make sure DRQ is set */ - status = ata_chk_status(ap); - if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) - goto err_out; - - /* Send the CDB (atapi) or the first data block (ata pio out). - * During the state transition, interrupt handler shouldn't - * be invoked before the data transfer is complete and - * hsm_task_state is changed. Hence, the following locking. - */ - spin_lock_irqsave(&ap->host_set->lock, flags); - - if (qc->tf.protocol == ATA_PROT_PIO) { - /* PIO data out protocol. - * send first data block. - */ - - /* ata_pio_sector() might change the state to HSM_ST_LAST. - * so, the state is changed here before ata_pio_sector(). - */ - ap->hsm_task_state = HSM_ST; - ata_pio_sector(qc); - ata_altstatus(ap); /* flush */ - } else - /* send CDB */ - atapi_send_cdb(ap, qc); - - /* if polling, ata_pio_task() handles the rest. - * otherwise, interrupt handler takes over from here. - */ - if (qc->tf.flags & ATA_TFLAG_POLLING) - queue_work(ata_wq, &ap->pio_task); - - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - return; - -err_out: - ata_pio_error(ap); -} - - -/** * ata_port_start - Set port up for dma. * @ap: Port to initialize * -- cgit v0.10.2 From 7282aa4b49d08254ff1dcefdf3a2fb01b02ebbe2 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sun, 9 Oct 2005 09:46:07 -0400 Subject: [libata irq-pio] reorganize ata_pio_sector() and __atapi_pio_bytes() - move some code out of the kmap_atomic() / kunmap_atomic() zone - remove the redundant "do_write = (qc->tf.flags & ATA_TFLAG_WRITE);" Signed-off-by: Albert Lee diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 2c9275e..f893126 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2763,22 +2763,21 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) local_irq_save(flags); buf = kmap_atomic(page, KM_IRQ0) + offset; - qc->cursect++; - qc->cursg_ofs++; - - if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) { - qc->cursg++; - qc->cursg_ofs = 0; - } - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); /* do the actual data transfer */ - do_write = (qc->tf.flags & ATA_TFLAG_WRITE); ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); kunmap_atomic(buf - offset, KM_IRQ0); local_irq_restore(flags); + + qc->cursect++; + qc->cursg_ofs++; + + if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) { + qc->cursg++; + qc->cursg_ofs = 0; + } } /** @@ -2956,6 +2955,14 @@ next_sg: local_irq_save(flags); buf = kmap_atomic(page, KM_IRQ0) + offset; + DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + + /* do the actual data transfer */ + ata_data_xfer(ap, buf, count, do_write); + + kunmap_atomic(buf - offset, KM_IRQ0); + local_irq_restore(flags); + bytes -= count; qc->curbytes += count; qc->cursg_ofs += count; @@ -2965,14 +2972,6 @@ next_sg: qc->cursg_ofs = 0; } - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - - /* do the actual data transfer */ - ata_data_xfer(ap, buf, count, do_write); - - kunmap_atomic(buf - offset, KM_IRQ0); - local_irq_restore(flags); - if (bytes) goto next_sg; } -- cgit v0.10.2 From 083958d313f886dc7d00522f2972f90f55c40041 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sun, 9 Oct 2005 09:47:31 -0400 Subject: [libata irq-pio] reorganize "buf + offset" in ata_pio_sector() and __atapi_pio_bytes() - relocate DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - buf + offset, buf - offset tidy up Signed-off-by: Albert Lee diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f893126..35ee35e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2760,15 +2760,15 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) page = nth_page(page, (offset >> PAGE_SHIFT)); offset %= PAGE_SIZE; - local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0) + offset; - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0); + /* do the actual data transfer */ - ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); + ata_data_xfer(ap, buf + offset, ATA_SECT_SIZE, do_write); - kunmap_atomic(buf - offset, KM_IRQ0); + kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); qc->cursect++; @@ -2952,15 +2952,15 @@ next_sg: /* don't cross page boundaries */ count = min(count, (unsigned int)PAGE_SIZE - offset); - local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0) + offset; - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0); + /* do the actual data transfer */ - ata_data_xfer(ap, buf, count, do_write); + ata_data_xfer(ap, buf + offset, count, do_write); - kunmap_atomic(buf - offset, KM_IRQ0); + kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); bytes -= count; -- cgit v0.10.2 From 91b8b3132e1870bfe3c4d3a999f13f20fc4e9726 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sun, 9 Oct 2005 09:48:44 -0400 Subject: [libata irq-pio] use PageHighMem() to optimize the kmap_atomic() usage as done in ide-scsi.c Signed-off-by: Albert Lee diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 35ee35e..5e750c3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2748,7 +2748,6 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) struct page *page; unsigned int offset; unsigned char *buf; - unsigned long flags; if (qc->cursect == (qc->nsect - 1)) ap->hsm_task_state = HSM_ST_LAST; @@ -2762,14 +2761,21 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0); + if (PageHighMem(page)) { + unsigned long flags; + + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0); - /* do the actual data transfer */ - ata_data_xfer(ap, buf + offset, ATA_SECT_SIZE, do_write); + /* do the actual data transfer */ + ata_data_xfer(ap, buf + offset, ATA_SECT_SIZE, do_write); - kunmap_atomic(buf, KM_IRQ0); - local_irq_restore(flags); + kunmap_atomic(buf, KM_IRQ0); + local_irq_restore(flags); + } else { + buf = page_address(page); + ata_data_xfer(ap, buf + offset, ATA_SECT_SIZE, do_write); + } qc->cursect++; qc->cursg_ofs++; @@ -2908,7 +2914,6 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) struct page *page; unsigned char *buf; unsigned int offset, count; - unsigned long flags; if (qc->curbytes + bytes >= qc->nbytes) ap->hsm_task_state = HSM_ST_LAST; @@ -2954,14 +2959,21 @@ next_sg: DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0); + if (PageHighMem(page)) { + unsigned long flags; + + local_irq_save(flags); + buf = kmap_atomic(page, KM_IRQ0); - /* do the actual data transfer */ - ata_data_xfer(ap, buf + offset, count, do_write); + /* do the actual data transfer */ + ata_data_xfer(ap, buf + offset, count, do_write); - kunmap_atomic(buf, KM_IRQ0); - local_irq_restore(flags); + kunmap_atomic(buf, KM_IRQ0); + local_irq_restore(flags); + } else { + buf = page_address(page); + ata_data_xfer(ap, buf + offset, count, do_write); + } bytes -= count; qc->curbytes += count; -- cgit v0.10.2 From e33b9dfa3008fcaa908dc0c8c472a812c400f839 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 9 Oct 2005 09:51:46 -0400 Subject: [libata irq-pio] build fix diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 5e750c3..9eb24d3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -72,6 +72,7 @@ static int ata_choose_xfer_mode(struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void ata_pio_error(struct ata_port *ap); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; -- cgit v0.10.2 From be697c3f137c9ed808753bbbc5d7751c6e5303fc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 18 Oct 2005 21:27:34 -0400 Subject: [libata pdc_adma] update for removal of ATA_FLAG_NOINTR diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 53b8db4..f3ba6b4 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -481,13 +481,13 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) for (port_no = 0; port_no < host_set->n_ports; ++port_no) { struct ata_port *ap; ap = host_set->ports[port_no]; - if (ap && (!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)))) { + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { struct ata_queued_cmd *qc; struct adma_port_priv *pp = ap->private_data; if (!pp || pp->state != adma_state_mmio) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ u8 status = ata_chk_status(ap); -- cgit v0.10.2 From 94ec1ef1cf29e137e5c79372e432b040c6604be6 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 30 Oct 2005 02:15:08 -0500 Subject: [libata pdc_adma] fix for new irq-driven PIO code diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 309b205..6a9d0dc 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -457,13 +457,13 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) continue; handled = 1; adma_enter_reg_mode(ap); - if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) + if (ap->flags & ATA_FLAG_PORT_DISABLED) continue; pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { if ((status & (aPERR | aPSD | aUIRQ))) drv_stat = ATA_ERR; else if (pp->pkt[0] != cDONE) -- cgit v0.10.2 From 467b16d4bebe8d251ca974eaa5da50b315206e9d Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 1 Nov 2005 19:19:01 +0800 Subject: [PATCH] libata irq-pio: misc fixes - ata_pio_block(): add ata_altstatus(ap) to prevent reading device status before it is valid - remove the unnecessary HSM_ST_IDLE state from ata_pio_task() - raise BUG() when unknown state is found in ata_pio_task() Signed-off-by: Albert Lee ============ Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ce18de9..15736e3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3317,6 +3317,8 @@ static void ata_pio_block(struct ata_port *ap) ata_pio_sector(qc); } + + ata_altstatus(ap); /* flush */ } static void ata_pio_error(struct ata_port *ap) @@ -3344,9 +3346,6 @@ fsm_start: qc_completed = 0; switch (ap->hsm_task_state) { - case HSM_ST_IDLE: - return; - case HSM_ST: ata_pio_block(ap); break; @@ -3364,6 +3363,10 @@ fsm_start: case HSM_ST_ERR: ata_pio_error(ap); return; + + default: + BUG(); + return; } if (timeout) -- cgit v0.10.2 From e27486db89ef04d5df1727c52362fa3d50cff241 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 1 Nov 2005 19:24:49 +0800 Subject: [PATCH] libata irq-pio: merge the ata_dataout_task workqueue with ata_pio_task workqueue - remove ap->dataout_task from struct ata_port - let ata_pio_task() handle the HSM_ST_FIRST state. - rename ata_dataout_task() to ata_pio_first_block() - replace the ata_dataout_task workqueue with ata_pio_task workqueue Signed-off-by: Albert Lee ======== Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 15736e3..96b8bba 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3056,8 +3056,8 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) } /** - * ata_dataout_task - Write first data block to hardware - * @_data: Port to which ATA/ATAPI device is attached. + * ata_pio_first_block - Write first data block to hardware + * @ap: Port to which ATA/ATAPI device is attached. * * When device has indicated its readiness to accept * the data, this function sends out the CDB or @@ -3070,9 +3070,8 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) * Kernel thread context (may sleep) */ -static void ata_dataout_task(void *_data) +static void ata_pio_first_block(struct ata_port *ap) { - struct ata_port *ap = _data; struct ata_queued_cmd *qc; u8 status; unsigned long flags; @@ -3346,6 +3345,10 @@ fsm_start: qc_completed = 0; switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + ata_pio_first_block(ap); + return; + case HSM_ST: ata_pio_block(ap); break; @@ -3796,10 +3799,10 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - queue_work(ata_wq, &ap->dataout_task); + queue_work(ata_wq, &ap->pio_task); /* always send first data block using - * the ata_dataout_task() codepath. + * the ata_pio_task() codepath. */ } else { /* PIO data in protocol */ @@ -3826,7 +3829,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - queue_work(ata_wq, &ap->dataout_task); + queue_work(ata_wq, &ap->pio_task); break; case ATA_PROT_ATAPI_DMA: @@ -3838,7 +3841,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - queue_work(ata_wq, &ap->dataout_task); + queue_work(ata_wq, &ap->pio_task); break; default: @@ -4426,7 +4429,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; - INIT_WORK(&ap->dataout_task, ata_dataout_task, ap); INIT_WORK(&ap->pio_task, ata_pio_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) diff --git a/include/linux/libata.h b/include/linux/libata.h index ad0451d..70ae140 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -346,8 +346,6 @@ struct ata_port { struct ata_host_stats stats; struct ata_host_set *host_set; - struct work_struct dataout_task; - struct work_struct pio_task; unsigned int hsm_task_state; unsigned long pio_task_timeout; -- cgit v0.10.2 From fbcdd80b0d5bde06f3483b9a13f9599a0452431c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 1 Nov 2005 19:30:05 +0800 Subject: [PATCH] libata irq-pio: eliminate unnecessary queuing in ata_pio_first_block() - change the return value of ata_pio_complete() 0 <-> 1 - add return value for ata_pio_first_block() - rename variable "qc_completed" to "has_next" in ata_pio_task() - use has_next to eliminate unnecessary queuing in ata_pio_first_block() Signed-off-by: Albert Lee ========== Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 96b8bba..2e0e6cc 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2790,7 +2790,8 @@ static unsigned long ata_pio_poll(struct ata_port *ap) * None. (executing in kernel thread context) * * RETURNS: - * Non-zero if qc completed, zero otherwise. + * Zero if qc completed. + * Non-zero if has next. */ static int ata_pio_complete (struct ata_port *ap) @@ -2812,14 +2813,14 @@ static int ata_pio_complete (struct ata_port *ap) if (drv_stat & (ATA_BUSY | ATA_DRQ)) { ap->hsm_task_state = HSM_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return 0; + return 1; } } drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { ap->hsm_task_state = HSM_ST_ERR; - return 0; + return 1; } qc = ata_qc_from_tag(ap, ap->active_tag); @@ -2831,7 +2832,7 @@ static int ata_pio_complete (struct ata_port *ap) /* another command may start at this point */ - return 1; + return 0; } @@ -3068,27 +3069,42 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) * * LOCKING: * Kernel thread context (may sleep) + * + * RETURNS: + * Zero if irq handler takes over + * Non-zero if has next (polling). */ -static void ata_pio_first_block(struct ata_port *ap) +static int ata_pio_first_block(struct ata_port *ap) { struct ata_queued_cmd *qc; u8 status; unsigned long flags; + int has_next; qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); assert(qc->flags & ATA_QCFLAG_ACTIVE); + /* if polling, we will stay in the work queue after sending the data. + * otherwise, interrupt handler takes over after sending the data. + */ + has_next = (qc->tf.flags & ATA_TFLAG_POLLING); + /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) + if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) { + ap->hsm_task_state = HSM_ST_TMOUT; goto err_out; + } /* make sure DRQ is set */ status = ata_chk_status(ap); - if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) { + /* device status error */ + ap->hsm_task_state = HSM_ST_ERR; goto err_out; + } /* Send the CDB (atapi) or the first data block (ata pio out). * During the state transition, interrupt handler shouldn't @@ -3112,18 +3128,15 @@ static void ata_pio_first_block(struct ata_port *ap) /* send CDB */ atapi_send_cdb(ap, qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + /* if polling, ata_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. */ - if (qc->tf.flags & ATA_TFLAG_POLLING) - queue_work(ata_wq, &ap->pio_task); - - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - return; + return has_next; err_out: - ata_pio_error(ap); + return 1; /* has next */ } /** @@ -3338,23 +3351,23 @@ static void ata_pio_task(void *_data) { struct ata_port *ap = _data; unsigned long timeout; - int qc_completed; + int has_next; fsm_start: timeout = 0; - qc_completed = 0; + has_next = 1; switch (ap->hsm_task_state) { case HSM_ST_FIRST: - ata_pio_first_block(ap); - return; + has_next = ata_pio_first_block(ap); + break; case HSM_ST: ata_pio_block(ap); break; case HSM_ST_LAST: - qc_completed = ata_pio_complete(ap); + has_next = ata_pio_complete(ap); break; case HSM_ST_POLL: @@ -3374,7 +3387,7 @@ fsm_start: if (timeout) queue_delayed_work(ata_wq, &ap->pio_task, timeout); - else if (!qc_completed) + else if (has_next) goto fsm_start; } -- cgit v0.10.2 From 07f6f7d074e68d56d82e7cc5c65096033ac8dc56 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 1 Nov 2005 19:33:20 +0800 Subject: [PATCH] libata irq-pio: add read/write multiple support - add is_multi_taskfile() to ata.h - initialize ata_device->multi_count with device identify data - use ata_pio_sectors() to support r/w multiple commands Signed-off-by: Albert Lee ======== Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 2e0e6cc..59a4a26 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1261,6 +1261,12 @@ retry: } + if (dev->id[59] & 0x100) { + dev->multi_count = dev->id[59] & 0xff; + DPRINTK("ata%u: dev %u multi count %u\n", + ap->id, device, dev->multi_count); + } + ap->host->max_cmd_len = 16; } @@ -2804,7 +2810,7 @@ static int ata_pio_complete (struct ata_port *ap) * we enter, BSY will be cleared in a chk-status or two. If not, * the drive is probably seeking or something. Snooze for a couple * msecs, then chk-status again. If still busy, fall back to - * HSM_ST_POLL state. + * HSM_ST_LAST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { @@ -3021,6 +3027,32 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) } /** + * ata_pio_sectors - Transfer one or many 512-byte sectors. + * @qc: Command on going + * + * Transfer one or many ATA_SECT_SIZE of data from/to the + * ATA device for the DRQ request. + * + * LOCKING: + * Inherited from caller. + */ + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + if (is_multi_taskfile(&qc->tf)) { + /* READ/WRITE MULTIPLE */ + unsigned int nsect; + + assert(qc->dev->multi_count); + + nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count); + while (nsect--) + ata_pio_sector(qc); + } else + ata_pio_sector(qc); +} + +/** * atapi_send_cdb - Write CDB bytes to hardware * @ap: Port to which ATAPI device is attached. * @qc: Taskfile currently active @@ -3118,11 +3150,11 @@ static int ata_pio_first_block(struct ata_port *ap) * send first data block. */ - /* ata_pio_sector() might change the state to HSM_ST_LAST. - * so, the state is changed here before ata_pio_sector(). + /* ata_pio_sectors() might change the state to HSM_ST_LAST. + * so, the state is changed here before ata_pio_sectors(). */ ap->hsm_task_state = HSM_ST; - ata_pio_sector(qc); + ata_pio_sectors(qc); ata_altstatus(ap); /* flush */ } else /* send CDB */ @@ -3327,7 +3359,7 @@ static void ata_pio_block(struct ata_port *ap) return; } - ata_pio_sector(qc); + ata_pio_sectors(qc); } ata_altstatus(ap); /* flush */ @@ -4213,7 +4245,7 @@ fsm_start: goto fsm_start; } - ata_pio_sector(qc); + ata_pio_sectors(qc); if (ap->hsm_task_state == HSM_ST_LAST && (!(qc->tf.flags & ATA_TFLAG_WRITE))) { diff --git a/include/linux/ata.h b/include/linux/ata.h index d54da33..f512104 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -293,6 +293,14 @@ static inline int is_atapi_taskfile(const struct ata_taskfile *tf) (tf->protocol == ATA_PROT_ATAPI_DMA); } +static inline int is_multi_taskfile(struct ata_taskfile *tf) +{ + return (tf->command == ATA_CMD_READ_MULTI) || + (tf->command == ATA_CMD_WRITE_MULTI) || + (tf->command == ATA_CMD_READ_MULTI_EXT) || + (tf->command == ATA_CMD_WRITE_MULTI_EXT); +} + static inline int ata_ok(u8 status) { return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) -- cgit v0.10.2 From d67e7ebb2a15bf0429c55f2fc1c4b02808367874 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 18 Nov 2005 11:55:00 -0500 Subject: [libata sata_mv] IRQ PIO build fix diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 9687646..6dc2a61 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1220,8 +1220,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, handled++; } - if (ap && - (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) + if (ap && (ap->flags & ATA_FLAG_PORT_DISABLED)) continue; err_mask = ac_err_mask(ata_status); @@ -1242,7 +1241,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, VPRINTK("port %u IRQ found for qc, " "ata_status 0x%x\n", port,ata_status); /* mark qc status appropriately */ - if (!(qc->tf.ctl & ATA_NIEN)) + if (!(qc->tf.flags & ATA_TFLAG_POLLING)) ata_qc_complete(qc, err_mask); } } -- cgit v0.10.2 From 278efe950988e72e2d0cea35059438fc27035d13 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 6 Dec 2005 05:01:27 -0500 Subject: [libata] irq-pio: fix breakage related to err_mask merge diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 82f566c..657537f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4336,7 +4336,8 @@ fsm_start: ap->id, status, host_stat); ap->hsm_task_state = HSM_ST_IDLE; - ata_qc_complete(qc, status | ATA_ERR); + qc->err_mask |= __ac_err_mask(status); + ata_qc_complete(qc); break; default: goto idle_irq; diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ef148ac..1704416 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1244,7 +1244,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, /* mark qc status appropriately */ if (!(qc->tf.flags & ATA_TFLAG_POLLING)) { qc->err_mask |= err_mask; - ata_qc_complete(qc, err_mask); + ata_qc_complete(qc); } } } -- cgit v0.10.2 From 3d0a59c02303df01848537b3bf938dc11e9a0ded Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 13 Dec 2005 22:28:19 -0500 Subject: [libata sata_promise] irq_pio: fix merge bug diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index b4cbc9d..e358380 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -70,6 +70,10 @@ enum { PDC_HAS_PATA = (1 << 1), /* PDC20375 has PATA */ PDC_RESET = (1 << 11), /* HDMA reset */ + + PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | + ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | + ATA_FLAG_PIO_POLLING, }; @@ -162,9 +166,7 @@ static const struct ata_port_info pdc_port_info[] = { /* board_2037x */ { .sht = &pdc_ata_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO | - ATA_FLAG_PIO_POLLING, + .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -174,9 +176,7 @@ static const struct ata_port_info pdc_port_info[] = { /* board_20319 */ { .sht = &pdc_ata_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO | - ATA_FLAG_PIO_POLLING, + .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -186,9 +186,7 @@ static const struct ata_port_info pdc_port_info[] = { /* board_20619 */ { .sht = &pdc_ata_sht, - .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | - ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS | - ATA_FLAG_PIO_POLLING, + .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ -- cgit v0.10.2 From a4f16610081001640ffe0314024bc31c10f69757 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 26 Dec 2005 16:40:53 +0800 Subject: [PATCH] libata-dev: determine err_mask when error is found Changes: - Determine err_mask directly when an error is found. - Remove "qc->err_mask |= __ac_err_mask(status);" in ata_host_intr() Signed-off-by: Albert Lee ============ Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 4a61061..41f76b9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3265,6 +3265,7 @@ static int ata_pio_first_block(struct ata_port *ap) /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) { + qc->err_mask |= AC_ERR_ATA_BUS; ap->hsm_task_state = HSM_ST_TMOUT; goto err_out; } @@ -3273,6 +3274,7 @@ static int ata_pio_first_block(struct ata_port *ap) status = ata_chk_status(ap); if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) { /* device status error */ + qc->err_mask |= AC_ERR_ATA_BUS; ap->hsm_task_state = HSM_ST_ERR; goto err_out; } @@ -4288,6 +4290,12 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* before we do anything else, clear DMA-Start bit */ ap->ops->bmdma_stop(qc); + + if (unlikely(host_stat & ATA_DMA_ERR)) { + /* error when transfering data to/from memory */ + qc->err_mask |= AC_ERR_HOST_BUS; + ap->hsm_task_state = HSM_ST_ERR; + } } break; case HSM_ST: @@ -4313,8 +4321,10 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ap->ops->irq_clear(ap); /* check error */ - if (unlikely((status & ATA_ERR) || (host_stat & ATA_DMA_ERR))) + if (unlikely(status & (ATA_ERR | ATA_DF))) { + qc->err_mask |= AC_ERR_DEV; ap->hsm_task_state = HSM_ST_ERR; + } fsm_start: switch (ap->hsm_task_state) { @@ -4326,6 +4336,7 @@ fsm_start: /* check device status */ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { /* Wrong status. Let EH handle this */ + qc->err_mask |= AC_ERR_ATA_BUS; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4354,6 +4365,7 @@ fsm_start: /* ATA PIO protocol */ if (unlikely((status & ATA_DRQ) == 0)) { /* handle BSY=0, DRQ=0 as error */ + qc->err_mask |= AC_ERR_ATA_BUS; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4375,6 +4387,7 @@ fsm_start: case HSM_ST_LAST: if (unlikely(status & ATA_DRQ)) { /* handle DRQ=1 as error */ + qc->err_mask |= AC_ERR_ATA_BUS; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4394,8 +4407,12 @@ fsm_start: printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", ap->id, status, host_stat); + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + assert(qc->err_mask); + ap->hsm_task_state = HSM_ST_IDLE; - qc->err_mask |= __ac_err_mask(status); ata_qc_complete(qc); break; default: -- cgit v0.10.2 From 000080c3499cd5037e60c08a8053efb9e48aa9c0 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 26 Dec 2005 16:48:00 +0800 Subject: [PATCH] libata-dev: filter out noisy ATAPI error messages Changes: - Filter out ATAPI packet command error messages in ata_pio_error() - Filter out ATAPI packet command error messages in ata_host_intr() Signed-off-by: Albert Lee ====== Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 41f76b9..911151d 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3520,11 +3520,12 @@ static void ata_pio_error(struct ata_port *ap) { struct ata_queued_cmd *qc; - printk(KERN_WARNING "ata%u: PIO error\n", ap->id); - qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); + if (qc->tf.command != ATA_CMD_PACKET) + printk(KERN_WARNING "ata%u: PIO error\n", ap->id); + /* make sure qc->err_mask is available to * know what's wrong and recover */ @@ -4404,8 +4405,9 @@ fsm_start: break; case HSM_ST_ERR: - printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", - ap->id, status, host_stat); + if (qc->tf.command != ATA_CMD_PACKET) + printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", + ap->id, status, host_stat); /* make sure qc->err_mask is available to * know what's wrong and recover -- cgit v0.10.2 From aef9d533da2eb7a5700a8c8700f2597c35cc50d1 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 8 Feb 2006 16:37:43 +0800 Subject: [PATCH] libata-dev: Fix array index value in ata_rwcmd_protocol() Signed-off-by: Albert Lee === Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 6daba4e..dab13ed 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -611,7 +611,7 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc) } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) { /* Unable to use DMA due to host limitation */ tf->protocol = ATA_PROT_PIO; - index = dev->multi_count ? 0 : 4; + index = dev->multi_count ? 0 : 8; } else { tf->protocol = ATA_PROT_DMA; index = 16; -- cgit v0.10.2 From 20ea079e5883ab2b82fa5e576957f52e4e5c252c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 8 Feb 2006 16:48:49 +0800 Subject: [PATCH] libata-dev: Use new ata_queue_pio_task() for PIO polling task - Use new ata_queue_pio_task() for PIO polling task. - Remove the unused ata_queue_packet_task() function. (irq-pio had merged the 2 queues into one.) Signed-off-by: Albert Lee === Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index dab13ed..bbce162 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1073,12 +1073,6 @@ static unsigned int ata_pio_modes(const struct ata_device *adev) } static inline void -ata_queue_packet_task(struct ata_port *ap) -{ - queue_work(ata_wq, &ap->packet_task); -} - -static inline void ata_queue_pio_task(struct ata_port *ap) { queue_work(ata_wq, &ap->pio_task); @@ -3971,7 +3965,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_LAST; if (qc->tf.flags & ATA_TFLAG_POLLING) - queue_work(ata_wq, &ap->pio_task); + ata_queue_pio_task(ap); break; @@ -4024,7 +4018,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_queue_packet_task(ap); + ata_queue_pio_task(ap); break; case ATA_PROT_ATAPI_DMA: @@ -4036,7 +4030,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_queue_packet_task(ap); + ata_queue_pio_task(ap); break; default: -- cgit v0.10.2 From 555a8965069b8e34292cbccc3ad8f619b96815fe Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 8 Feb 2006 16:50:29 +0800 Subject: [PATCH] libata-dev: Use new AC_ERR_* flags - Use new AC_ERR_* flags as done in Tejun's patches - In ata_qc_timeout(), replace ac_err_mask(drv_stat) with AC_ERR_TIMEOUT. This makes time out handler always report error to upper layer. Otherwise if the drv_stat looks good, libata might falsely report OK to the upper layer. Signed-off-by: Albert Lee === Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index bbce162..415c64f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3315,7 +3315,7 @@ static int ata_pio_first_block(struct ata_port *ap) /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) { - qc->err_mask |= AC_ERR_ATA_BUS; + qc->err_mask |= AC_ERR_TIMEOUT; ap->hsm_task_state = HSM_ST_TMOUT; goto err_out; } @@ -3324,7 +3324,7 @@ static int ata_pio_first_block(struct ata_port *ap) status = ata_chk_status(ap); if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) { /* device status error */ - qc->err_mask |= AC_ERR_ATA_BUS; + qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto err_out; } @@ -3684,7 +3684,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - qc->err_mask |= ac_err_mask(drv_stat); + qc->err_mask |= AC_ERR_TIMEOUT; break; } @@ -4365,7 +4365,7 @@ fsm_start: /* check device status */ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { /* Wrong status. Let EH handle this */ - qc->err_mask |= AC_ERR_ATA_BUS; + qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4394,7 +4394,7 @@ fsm_start: /* ATA PIO protocol */ if (unlikely((status & ATA_DRQ) == 0)) { /* handle BSY=0, DRQ=0 as error */ - qc->err_mask |= AC_ERR_ATA_BUS; + qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4416,7 +4416,7 @@ fsm_start: case HSM_ST_LAST: if (unlikely(status & ATA_DRQ)) { /* handle DRQ=1 as error */ - qc->err_mask |= AC_ERR_ATA_BUS; + qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } -- cgit v0.10.2 From 332b5a52f2f96bc2d13bbe594a430318c0ee4425 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 8 Feb 2006 16:51:34 +0800 Subject: [PATCH] libata-dev: Minor comment fix Signed-off-by: Albert Lee === Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 415c64f..ff31b0b 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4510,19 +4510,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) return IRQ_RETVAL(handled); } -/** - * ata_port_start - Set port up for dma. - * @ap: Port to initialize - * - * Called just after data structures for each port are - * initialized. Allocates space for PRD table. - * - * May be used as the port_start() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ - /* * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, * without filling any other registers @@ -4613,6 +4600,19 @@ int ata_device_suspend(struct ata_port *ap, struct ata_device *dev) return 0; } +/** + * ata_port_start - Set port up for dma. + * @ap: Port to initialize + * + * Called just after data structures for each port are + * initialized. Allocates space for PRD table. + * + * May be used as the port_start() entry in ata_port_operations. + * + * LOCKING: + * Inherited from caller. + */ + int ata_port_start (struct ata_port *ap) { struct device *dev = ap->host_set->dev; -- cgit v0.10.2 From 41232d3ecac9df8eb94ff27330eb84b8baccc6b7 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 9 Feb 2006 04:52:55 -0500 Subject: [libata] build fix after merging some pre-packet_task-removal code diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c93bb1b..59d8dd0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1087,10 +1087,10 @@ ata_queue_delayed_pio_task(struct ata_port *ap, unsigned long delay) } /** - * ata_flush_pio_tasks - Flush pio_task and packet_task + * ata_flush_pio_tasks - Flush pio_task * @ap: the target ata_port * - * After this function completes, pio_task and packet_task are + * After this function completes, pio_task is * guranteed not to be running or scheduled. * * LOCKING: @@ -1117,7 +1117,6 @@ static void ata_flush_pio_tasks(struct ata_port *ap) * Cancel and flush. */ tmp |= cancel_delayed_work(&ap->pio_task); - tmp |= cancel_delayed_work(&ap->packet_task); if (!tmp) { DPRINTK("flush #2\n"); flush_workqueue(ata_wq); -- cgit v0.10.2 From 587005de144acd3007b8e7f2a2a7c6add157c155 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 11 Feb 2006 18:17:32 -0500 Subject: [libata irq-pio] s/assert/WARN_ON/ diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 3fd55ef..bfe0a00 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3226,7 +3226,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) /* READ/WRITE MULTIPLE */ unsigned int nsect; - assert(qc->dev->multi_count); + WARN_ON(qc->dev->multi_count == 0); nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count); while (nsect--) @@ -3251,7 +3251,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) { /* send SCSI cdb */ DPRINTK("send cdb\n"); - assert(ap->cdb_len >= 12); + WARN_ON(ap->cdb_len < 12); ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); ata_altstatus(ap); /* flush */ @@ -3298,8 +3298,8 @@ static int ata_pio_first_block(struct ata_port *ap) int has_next; qc = ata_qc_from_tag(ap, ap->active_tag); - assert(qc != NULL); - assert(qc->flags & ATA_QCFLAG_ACTIVE); + WARN_ON(qc == NULL); + WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); /* if polling, we will stay in the work queue after sending the data. * otherwise, interrupt handler takes over after sending the data. @@ -3945,7 +3945,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_DMA: - assert(!(qc->tf.flags & ATA_TFLAG_POLLING)); + WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ @@ -3997,7 +3997,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_ATAPI_DMA: - assert(!(qc->tf.flags & ATA_TFLAG_POLLING)); + WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ @@ -4415,7 +4415,7 @@ fsm_start: /* make sure qc->err_mask is available to * know what's wrong and recover */ - assert(qc->err_mask); + WARN_ON(qc->err_mask == 0); ap->hsm_task_state = HSM_ST_IDLE; ata_qc_complete(qc); -- cgit v0.10.2 From db024d5398cd332023896caf70530564b15ec88e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 13 Feb 2006 00:23:57 -0500 Subject: [libata] build fix after cdb_len move diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 5ab220e..d1803c9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3282,9 +3282,9 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) { /* send SCSI cdb */ DPRINTK("send cdb\n"); - WARN_ON(ap->cdb_len < 12); + WARN_ON(qc->dev->cdb_len < 12); - ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); + ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1); ata_altstatus(ap); /* flush */ switch (qc->tf.protocol) { -- cgit v0.10.2 From a5fd79ccd60b7c9cc0221dfaaa950933eff6af99 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 20 Feb 2006 05:21:14 -0500 Subject: sata_vsc build fix diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 2d448e8..5845758 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -229,7 +229,7 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); - } else { + else { printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__); ata_chk_status(ap); handled++; -- cgit v0.10.2 From c2956a3b0d1c17b38da369811a6ce93eb7a01a04 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 3 Mar 2006 10:34:05 +0800 Subject: [PATCH] libata-dev: recognize WRITE_MULTI_FUA_EXT for r/w multiple Recognize ATA_CMD_WRITE_MULTI_FUA_EXT as r/w multiple commands. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/include/linux/ata.h b/include/linux/ata.h index 4699523..e7b0c21 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -314,7 +314,8 @@ static inline int is_multi_taskfile(struct ata_taskfile *tf) return (tf->command == ATA_CMD_READ_MULTI) || (tf->command == ATA_CMD_WRITE_MULTI) || (tf->command == ATA_CMD_READ_MULTI_EXT) || - (tf->command == ATA_CMD_WRITE_MULTI_EXT); + (tf->command == ATA_CMD_WRITE_MULTI_EXT) || + (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT); } static inline int ata_ok(u8 status) -- cgit v0.10.2 From 46e202ec1feeac3cb722cd3410d62a9a00891388 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 11 Mar 2006 19:25:47 -0500 Subject: libata: irq-pio build fixes diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 5060a1a..1a00c80 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3809,7 +3809,7 @@ fsm_start: if (timeout) ata_port_queue_task(ap, ata_pio_task, ap, timeout); - else if (!qc_completed) + else if (has_next) goto fsm_start; } @@ -3866,7 +3866,8 @@ static void atapi_packet_task(void *_data) * finished. Hence, the following locking. */ spin_lock_irqsave(&ap->host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; +#warning FIXME + /* ap->flags &= ~ATA_FLAG_NOINTR; */ ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1); if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) ap->ops->bmdma_start(qc); /* initiate bmdma */ @@ -4200,7 +4201,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_LAST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_queue_pio_task(ap); + ata_port_queue_task(ap, ata_pio_task, ap, 0); break; -- cgit v0.10.2 From 84ac69e8bf9f36eb0166817373336d14fa58f5cc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 24 Mar 2006 09:27:49 -0500 Subject: [libata] irq-pio: fix build breakage diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 8c818d4..9f621a9 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -229,14 +229,13 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, handled++; } - if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); - } else if (is_vsc_sata_int_err(i, int_status)) { + else if (is_vsc_sata_int_err(i, int_status)) { /* * On some chips (i.e. Intel 31244), an error * interrupt will sneak in at initialization -- cgit v0.10.2 From cf2f7689f94ee02e52d5331bc1a87421a67a882c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:37:53 +0800 Subject: [PATCH] libata-dev: Remove trailing whitespaces Remove trailing whitespaces. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c3c4263..7641828 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4397,7 +4397,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, fsm_start: switch (ap->hsm_task_state) { case HSM_ST_FIRST: - /* Some pre-ATAPI-4 devices assert INTRQ + /* Some pre-ATAPI-4 devices assert INTRQ * at this state when ready to receive CDB. */ @@ -4422,7 +4422,7 @@ fsm_start: ap->hsm_task_state = HSM_ST_LAST; goto fsm_start; } - + atapi_pio_bytes(qc); if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) @@ -4476,7 +4476,7 @@ fsm_start: printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", ap->id, status, host_stat); - /* make sure qc->err_mask is available to + /* make sure qc->err_mask is available to * know what's wrong and recover */ WARN_ON(qc->err_mask == 0); -- cgit v0.10.2 From 13ee4628ce68d1e54df01cc31239c8887c59e65d Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:39:34 +0800 Subject: [PATCH] libata-dev: Fix merge problem with upstream Fix merge problem with upstream. Changes: 1. add missing dev->cdb_len = 16 for ATA devices 2. use ata_pio_task instead of atapi_packet_task Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 7641828..9ef5b8a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1299,6 +1299,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, ap->id, device, dev->multi_count); } + dev->cdb_len = 16; } /* ATAPI-specific feature tests */ @@ -4288,7 +4289,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_port_queue_task(ap, atapi_packet_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, ap, 0); break; case ATA_PROT_ATAPI_DMA: @@ -4300,7 +4301,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_port_queue_task(ap, atapi_packet_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, ap, 0); break; default: -- cgit v0.10.2 From 19d5d7309a928eb86f58b37165a2d501621ae3c0 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:41:43 +0800 Subject: [PATCH] libata-dev: Remove atapi_packet_task() atapi_packet_task() was replaced by ata_pio_task(). Remove the unused atapi_packet_task(). Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9ef5b8a..0eb75e2 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3850,79 +3850,6 @@ fsm_start: } /** - * atapi_packet_task - Write CDB bytes to hardware - * @_data: Port to which ATAPI device is attached. - * - * When device has indicated its readiness to accept - * a CDB, this function is called. Send the CDB. - * If DMA is to be performed, exit immediately. - * Otherwise, we are in polling mode, so poll - * status under operation succeeds or fails. - * - * LOCKING: - * Kernel thread context (may sleep) - */ - -static void atapi_packet_task(void *_data) -{ - struct ata_port *ap = _data; - struct ata_queued_cmd *qc; - u8 status; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); - - /* sleep-wait for BSY to clear */ - DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) { - qc->err_mask |= AC_ERR_TIMEOUT; - goto err_out; - } - - /* make sure DRQ is set */ - status = ata_chk_status(ap); - if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) { - qc->err_mask |= AC_ERR_HSM; - goto err_out; - } - - /* send SCSI cdb */ - DPRINTK("send cdb\n"); - WARN_ON(qc->dev->cdb_len < 12); - - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { - unsigned long flags; - - /* Once we're done issuing command and kicking bmdma, - * irq handler takes over. To not lose irq, we need - * to clear NOINTR flag before sending cdb, but - * interrupt handler shouldn't be invoked before we're - * finished. Hence, the following locking. - */ - spin_lock_irqsave(&ap->host_set->lock, flags); -#warning FIXME - /* ap->flags &= ~ATA_FLAG_NOINTR; */ - ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1); - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) - ap->ops->bmdma_start(qc); /* initiate bmdma */ - spin_unlock_irqrestore(&ap->host_set->lock, flags); - } else { - ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1); - - /* PIO commands are handled by polling */ - ap->hsm_task_state = HSM_ST; - ata_port_queue_task(ap, ata_pio_task, ap, 0); - } - - return; - -err_out: - ata_poll_qc_complete(qc); -} - -/** * ata_qc_timeout - Handle timeout of queued command * @qc: Command that timed out * -- cgit v0.10.2 From e2cec77117a6e4fcbac2601e2f7b0b3f4f5a4c84 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:43:49 +0800 Subject: [PATCH] libata-dev: Move out the HSM code from ata_host_intr() Move out the irq-pio HSM code from ata_host_intr() to the new ata_hsm_move() function verbatim. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 0eb75e2..7214530 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3805,6 +3805,111 @@ static void ata_pio_error(struct ata_port *ap) ata_poll_qc_complete(qc); } +static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status) +{ + /* check error */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + qc->err_mask |= AC_ERR_DEV; + ap->hsm_task_state = HSM_ST_ERR; + } + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + + /* check device status */ + if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { + /* Wrong status. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + atapi_send_cdb(ap, qc); + + break; + + case HSM_ST: + /* complete command or read/write the data register */ + if (qc->tf.protocol == ATA_PROT_ATAPI) { + /* ATAPI PIO protocol */ + if ((status & ATA_DRQ) == 0) { + /* no more data to transfer */ + ap->hsm_task_state = HSM_ST_LAST; + goto fsm_start; + } + + atapi_pio_bytes(qc); + + if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) + /* bad ireason reported by device */ + goto fsm_start; + + } else { + /* ATA PIO protocol */ + if (unlikely((status & ATA_DRQ) == 0)) { + /* handle BSY=0, DRQ=0 as error */ + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + /* all data read */ + ata_altstatus(ap); + status = ata_chk_status(ap); + goto fsm_start; + } + } + + ata_altstatus(ap); /* flush */ + break; + + case HSM_ST_LAST: + if (unlikely(status & ATA_DRQ)) { + /* handle DRQ=1 as error */ + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* no more data to transfer */ + DPRINTK("ata%u: command complete, drv_stat 0x%x\n", + ap->id, status); + + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + qc->err_mask |= ac_err_mask(status); + ata_qc_complete(qc); + break; + + case HSM_ST_ERR: + if (qc->tf.command != ATA_CMD_PACKET) + printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", + ap->id, status, host_stat); + + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + WARN_ON(qc->err_mask == 0); + + ap->hsm_task_state = HSM_ST_IDLE; + ata_qc_complete(qc); + break; + default: + goto idle_irq; + } + +} + static void ata_pio_task(void *_data) { struct ata_port *ap = _data; @@ -4316,106 +4421,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* ack bmdma irq events */ ap->ops->irq_clear(ap); - /* check error */ - if (unlikely(status & (ATA_ERR | ATA_DF))) { - qc->err_mask |= AC_ERR_DEV; - ap->hsm_task_state = HSM_ST_ERR; - } - -fsm_start: - switch (ap->hsm_task_state) { - case HSM_ST_FIRST: - /* Some pre-ATAPI-4 devices assert INTRQ - * at this state when ready to receive CDB. - */ - - /* check device status */ - if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { - /* Wrong status. Let EH handle this */ - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - atapi_send_cdb(ap, qc); - - break; - - case HSM_ST: - /* complete command or read/write the data register */ - if (qc->tf.protocol == ATA_PROT_ATAPI) { - /* ATAPI PIO protocol */ - if ((status & ATA_DRQ) == 0) { - /* no more data to transfer */ - ap->hsm_task_state = HSM_ST_LAST; - goto fsm_start; - } - - atapi_pio_bytes(qc); - - if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) - /* bad ireason reported by device */ - goto fsm_start; - - } else { - /* ATA PIO protocol */ - if (unlikely((status & ATA_DRQ) == 0)) { - /* handle BSY=0, DRQ=0 as error */ - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - ata_pio_sectors(qc); - - if (ap->hsm_task_state == HSM_ST_LAST && - (!(qc->tf.flags & ATA_TFLAG_WRITE))) { - /* all data read */ - ata_altstatus(ap); - status = ata_chk_status(ap); - goto fsm_start; - } - } - - ata_altstatus(ap); /* flush */ - break; - - case HSM_ST_LAST: - if (unlikely(status & ATA_DRQ)) { - /* handle DRQ=1 as error */ - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - /* no more data to transfer */ - DPRINTK("ata%u: command complete, drv_stat 0x%x\n", - ap->id, status); - - ap->hsm_task_state = HSM_ST_IDLE; - - /* complete taskfile transaction */ - qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); - break; - - case HSM_ST_ERR: - if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", - ap->id, status, host_stat); - - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - WARN_ON(qc->err_mask == 0); - - ap->hsm_task_state = HSM_ST_IDLE; - ata_qc_complete(qc); - break; - default: - goto idle_irq; - } - + ata_hsm_move(ap, qc, status); return 1; /* irq handled */ idle_irq: -- cgit v0.10.2 From 6912ccd5a4a095d71fd7215ef2abea877c8fed6f Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:45:49 +0800 Subject: [PATCH] libata-dev: Minor fix for ata_hsm_move() to work with ata_host_intr() Minor fix for ata_hsm_move() to work with ata_host_intr(). Changes: - WARN_ON() and comment fix - Make the HSM_ST_LAST device status checking more rigid. - Treat unknown HSM state as BUG(). Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 7214530..094c790 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3808,6 +3808,8 @@ static void ata_pio_error(struct ata_port *ap) static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, u8 status) { + WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + /* check error */ if (unlikely(status & (ATA_ERR | ATA_DF))) { qc->err_mask |= AC_ERR_DEV; @@ -3817,10 +3819,6 @@ static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, fsm_start: switch (ap->hsm_task_state) { case HSM_ST_FIRST: - /* Some pre-ATAPI-4 devices assert INTRQ - * at this state when ready to receive CDB. - */ - /* check device status */ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { /* Wrong status. Let EH handle this */ @@ -3873,9 +3871,8 @@ fsm_start: break; case HSM_ST_LAST: - if (unlikely(status & ATA_DRQ)) { - /* handle DRQ=1 as error */ - qc->err_mask |= AC_ERR_HSM; + if (unlikely(!ata_ok(status))) { + qc->err_mask |= __ac_err_mask(status); ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -3884,17 +3881,18 @@ fsm_start: DPRINTK("ata%u: command complete, drv_stat 0x%x\n", ap->id, status); + WARN_ON(qc->err_mask); + ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - qc->err_mask |= ac_err_mask(status); ata_qc_complete(qc); break; case HSM_ST_ERR: if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_ERR "ata%u: command error, drv_stat 0x%x host_stat 0x%x\n", - ap->id, status, host_stat); + printk(KERN_ERR "ata%u: command error, drv_stat 0x%x\n", + ap->id, status); /* make sure qc->err_mask is available to * know what's wrong and recover @@ -3905,7 +3903,7 @@ fsm_start: ata_qc_complete(qc); break; default: - goto idle_irq; + BUG(); } } @@ -4371,6 +4369,10 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* Check whether we are expecting interrupt in this state */ switch (ap->hsm_task_state) { case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + /* Check the ATA_DFLAG_CDB_INTR flag is enough here. * The flag was turned on only for atapi devices. * No need to check is_atapi_taskfile(&qc->tf) again. -- cgit v0.10.2 From bb5cb290f095f17f88c912e3da35adf5b2d9500b Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:48:02 +0800 Subject: [PATCH] libata-dev: Let ata_hsm_move() work with both irq-pio and polling pio Let ata_hsm_move() work with both irq-pio and polling pio codepath. Changes: - add a new parameter "in_wq" for polling pio - add return value "poll_next" to tell polling pio task whether the HSM is finished - merge code from ata_pio_first_block() to the HSM_ST_FIRST state. - call ata_poll_qc_complete() if called from the workqueue Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 094c790..33b39d3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3805,11 +3805,36 @@ static void ata_pio_error(struct ata_port *ap) ata_poll_qc_complete(qc); } -static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status) +/** + * ata_hsm_move - move the HSM to the next state. + * @ap: the target ata_port + * @qc: qc on going + * @status: current device status + * @in_wq: 1 if called from workqueue, 0 otherwise + * + * RETURNS: + * 1 when poll next status needed, 0 otherwise. + */ + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) { + unsigned long flags = 0; + int poll_next; + WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + /* Make sure ata_qc_issue_prot() does not throw things + * like DMA polling into the workqueue. Notice that + * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). + */ + WARN_ON(in_wq != ((qc->tf.flags & ATA_TFLAG_POLLING) || + (ap->hsm_task_state == HSM_ST_FIRST && + ((qc->tf.protocol == ATA_PROT_PIO && + (qc->tf.flags & ATA_TFLAG_WRITE)) || + (is_atapi_taskfile(&qc->tf) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)))))); + /* check error */ if (unlikely(status & (ATA_ERR | ATA_DF))) { qc->err_mask |= AC_ERR_DEV; @@ -3819,6 +3844,14 @@ static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, fsm_start: switch (ap->hsm_task_state) { case HSM_ST_FIRST: + /* Send first data block or PACKET CDB */ + + /* If polling, we will stay in the work queue after + * sending the data. Otherwise, interrupt handler + * takes over after sending the data. + */ + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + /* check device status */ if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { /* Wrong status. Let EH handle this */ @@ -3827,8 +3860,36 @@ fsm_start: goto fsm_start; } - atapi_send_cdb(ap, qc); + /* Send the CDB (atapi) or the first data block (ata pio out). + * During the state transition, interrupt handler shouldn't + * be invoked before the data transfer is complete and + * hsm_task_state is changed. Hence, the following locking. + */ + if (in_wq) + spin_lock_irqsave(&ap->host_set->lock, flags); + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + ata_altstatus(ap); /* flush */ + } else + /* send CDB */ + atapi_send_cdb(ap, qc); + + if (in_wq) + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + /* if polling, ata_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ break; case HSM_ST: @@ -3868,6 +3929,7 @@ fsm_start: } ata_altstatus(ap); /* flush */ + poll_next = 1; break; case HSM_ST_LAST: @@ -3886,7 +3948,12 @@ fsm_start: ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - ata_qc_complete(qc); + if (in_wq) + ata_poll_qc_complete(qc); + else + ata_qc_complete(qc); + + poll_next = 0; break; case HSM_ST_ERR: @@ -3900,12 +3967,20 @@ fsm_start: WARN_ON(qc->err_mask == 0); ap->hsm_task_state = HSM_ST_IDLE; - ata_qc_complete(qc); + + if (in_wq) + ata_poll_qc_complete(qc); + else + ata_qc_complete(qc); + + poll_next = 0; break; default: + poll_next = 0; BUG(); } + return poll_next; } static void ata_pio_task(void *_data) @@ -4423,7 +4498,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* ack bmdma irq events */ ap->ops->irq_clear(ap); - ata_hsm_move(ap, qc, status); + ata_hsm_move(ap, qc, status, 0); return 1; /* irq handled */ idle_irq: -- cgit v0.10.2 From a1af37344f669d0fefa8c8a9e37eb6a7c086a2c2 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:50:15 +0800 Subject: [PATCH] libata-dev: Convert ata_pio_task() to use the new ata_hsm_move() Convert ata_pio_task() to use the new ata_hsm_move(). Changes: - refactor ata_pio_task() to poll device status register and - call the new ata_hsm_move() when device indicates it is not BSY. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 33b39d3..eeeeda0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3986,44 +3986,40 @@ fsm_start: static void ata_pio_task(void *_data) { struct ata_port *ap = _data; - unsigned long timeout; - int has_next; + struct ata_queued_cmd *qc; + u8 status; + int poll_next; fsm_start: - timeout = 0; - has_next = 1; + WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); - switch (ap->hsm_task_state) { - case HSM_ST_FIRST: - has_next = ata_pio_first_block(ap); - break; - - case HSM_ST: - ata_pio_block(ap); - break; - - case HSM_ST_LAST: - has_next = ata_pio_complete(ap); - break; - - case HSM_ST_POLL: - case HSM_ST_LAST_POLL: - timeout = ata_pio_poll(ap); - break; - - case HSM_ST_TMOUT: - case HSM_ST_ERR: - ata_pio_error(ap); - return; + qc = ata_qc_from_tag(ap, ap->active_tag); + WARN_ON(qc == NULL); - default: - BUG(); - return; + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * a chk-status or two. If not, the drive is probably seeking + * or something. Snooze for a couple msecs, then + * chk-status again. If still busy, queue delayed work. + */ + status = ata_busy_wait(ap, ATA_BUSY, 5); + if (status & ATA_BUSY) { + msleep(2); + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ata_port_queue_task(ap, ata_pio_task, ap, ATA_SHORT_PAUSE); + return; + } } - if (timeout) - ata_port_queue_task(ap, ata_pio_task, ap, timeout); - else if (has_next) + /* move the HSM */ + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) goto fsm_start; } -- cgit v0.10.2 From 27cdadef6dfe0d0614653919a110fc75ab1650ce Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:53:57 +0800 Subject: [PATCH] libata-dev: Cleanup unused enums/functions Cleanup the following unused functions: - ata_pio_poll() - ata_pio_complete() - ata_pio_first_block() - ata_pio_block() - ata_pio_error() ap->pio_task_timeout and other enums. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index eeeeda0..ef0d0dd 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -67,7 +67,6 @@ static void ata_set_mode(struct ata_port *ap); static unsigned int ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev); -static void ata_pio_error(struct ata_port *ap); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -3132,114 +3131,6 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc) } /** - * ata_pio_poll - poll using PIO, depending on current state - * @ap: the target ata_port - * - * LOCKING: - * None. (executing in kernel thread context) - * - * RETURNS: - * timeout value to use - */ - -static unsigned long ata_pio_poll(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 status; - unsigned int poll_state = HSM_ST_UNKNOWN; - unsigned int reg_state = HSM_ST_UNKNOWN; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - switch (ap->hsm_task_state) { - case HSM_ST: - case HSM_ST_POLL: - poll_state = HSM_ST_POLL; - reg_state = HSM_ST; - break; - case HSM_ST_LAST: - case HSM_ST_LAST_POLL: - poll_state = HSM_ST_LAST_POLL; - reg_state = HSM_ST_LAST; - break; - default: - BUG(); - break; - } - - status = ata_chk_status(ap); - if (status & ATA_BUSY) { - if (time_after(jiffies, ap->pio_task_timeout)) { - qc->err_mask |= AC_ERR_TIMEOUT; - ap->hsm_task_state = HSM_ST_TMOUT; - return 0; - } - ap->hsm_task_state = poll_state; - return ATA_SHORT_PAUSE; - } - - ap->hsm_task_state = reg_state; - return 0; -} - -/** - * ata_pio_complete - check if drive is busy or idle - * @ap: the target ata_port - * - * LOCKING: - * None. (executing in kernel thread context) - * - * RETURNS: - * Zero if qc completed. - * Non-zero if has next. - */ - -static int ata_pio_complete (struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 drv_stat; - - /* - * This is purely heuristic. This is a fast path. Sometimes when - * we enter, BSY will be cleared in a chk-status or two. If not, - * the drive is probably seeking or something. Snooze for a couple - * msecs, then chk-status again. If still busy, fall back to - * HSM_ST_LAST_POLL state. - */ - drv_stat = ata_busy_wait(ap, ATA_BUSY, 10); - if (drv_stat & ATA_BUSY) { - msleep(2); - drv_stat = ata_busy_wait(ap, ATA_BUSY, 10); - if (drv_stat & ATA_BUSY) { - ap->hsm_task_state = HSM_ST_LAST_POLL; - ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return 1; - } - } - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - drv_stat = ata_wait_idle(ap); - if (!ata_ok(drv_stat)) { - qc->err_mask |= __ac_err_mask(drv_stat); - ap->hsm_task_state = HSM_ST_ERR; - return 1; - } - - ap->hsm_task_state = HSM_ST_IDLE; - - WARN_ON(qc->err_mask); - ata_poll_qc_complete(qc); - - /* another command may start at this point */ - - return 0; -} - - -/** * swap_buf_le16 - swap halves of 16-bit words in place * @buf: Buffer to swap * @buf_words: Number of 16-bit words in buffer. @@ -3497,91 +3388,6 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) } /** - * ata_pio_first_block - Write first data block to hardware - * @ap: Port to which ATA/ATAPI device is attached. - * - * When device has indicated its readiness to accept - * the data, this function sends out the CDB or - * the first data block by PIO. - * After this, - * - If polling, ata_pio_task() handles the rest. - * - Otherwise, interrupt handler takes over. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * Zero if irq handler takes over - * Non-zero if has next (polling). - */ - -static int ata_pio_first_block(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 status; - unsigned long flags; - int has_next; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); - - /* if polling, we will stay in the work queue after sending the data. - * otherwise, interrupt handler takes over after sending the data. - */ - has_next = (qc->tf.flags & ATA_TFLAG_POLLING); - - /* sleep-wait for BSY to clear */ - DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) { - qc->err_mask |= AC_ERR_TIMEOUT; - ap->hsm_task_state = HSM_ST_TMOUT; - goto err_out; - } - - /* make sure DRQ is set */ - status = ata_chk_status(ap); - if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) { - /* device status error */ - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto err_out; - } - - /* Send the CDB (atapi) or the first data block (ata pio out). - * During the state transition, interrupt handler shouldn't - * be invoked before the data transfer is complete and - * hsm_task_state is changed. Hence, the following locking. - */ - spin_lock_irqsave(&ap->host_set->lock, flags); - - if (qc->tf.protocol == ATA_PROT_PIO) { - /* PIO data out protocol. - * send first data block. - */ - - /* ata_pio_sectors() might change the state to HSM_ST_LAST. - * so, the state is changed here before ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST; - ata_pio_sectors(qc); - ata_altstatus(ap); /* flush */ - } else - /* send CDB */ - atapi_send_cdb(ap, qc); - - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - /* if polling, ata_pio_task() handles the rest. - * otherwise, interrupt handler takes over from here. - */ - return has_next; - -err_out: - return 1; /* has next */ -} - -/** * __atapi_pio_bytes - Transfer data from/to the ATAPI device. * @qc: Command on going * @bytes: number of bytes @@ -3721,91 +3527,6 @@ err_out: } /** - * ata_pio_block - start PIO on a block - * @ap: the target ata_port - * - * LOCKING: - * None. (executing in kernel thread context) - */ - -static void ata_pio_block(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 status; - - /* - * This is purely heuristic. This is a fast path. - * Sometimes when we enter, BSY will be cleared in - * a chk-status or two. If not, the drive is probably seeking - * or something. Snooze for a couple msecs, then - * chk-status again. If still busy, fall back to - * HSM_ST_POLL state. - */ - status = ata_busy_wait(ap, ATA_BUSY, 5); - if (status & ATA_BUSY) { - msleep(2); - status = ata_busy_wait(ap, ATA_BUSY, 10); - if (status & ATA_BUSY) { - ap->hsm_task_state = HSM_ST_POLL; - ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return; - } - } - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - /* check error */ - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - ap->hsm_task_state = HSM_ST_ERR; - return; - } - - /* transfer data if any */ - if (is_atapi_taskfile(&qc->tf)) { - /* DRQ=0 means no more data to transfer */ - if ((status & ATA_DRQ) == 0) { - ap->hsm_task_state = HSM_ST_LAST; - return; - } - - atapi_pio_bytes(qc); - } else { - /* handle BSY=0, DRQ=0 as error */ - if ((status & ATA_DRQ) == 0) { - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - return; - } - - ata_pio_sectors(qc); - } - - ata_altstatus(ap); /* flush */ -} - -static void ata_pio_error(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_WARNING "ata%u: PIO error\n", ap->id); - - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - WARN_ON(qc->err_mask == 0); - - ap->hsm_task_state = HSM_ST_IDLE; - - ata_poll_qc_complete(qc); -} - -/** * ata_hsm_move - move the HSM to the next state. * @ap: the target ata_port * @qc: qc on going diff --git a/include/linux/libata.h b/include/linux/libata.h index 70ca99b..0eb71c1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -162,13 +162,8 @@ enum { ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */ /* various lengths of time */ - ATA_TMOUT_PIO = 30 * HZ, ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */ ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */ - ATA_TMOUT_DATAOUT = 30 * HZ, - ATA_TMOUT_DATAOUT_QUICK = 5 * HZ, - ATA_TMOUT_CDB = 30 * HZ, - ATA_TMOUT_CDB_QUICK = 5 * HZ, ATA_TMOUT_INTERNAL = 30 * HZ, ATA_TMOUT_INTERNAL_QUICK = 5 * HZ, @@ -216,11 +211,8 @@ enum { enum hsm_task_states { HSM_ST_UNKNOWN, /* state unknown */ HSM_ST_IDLE, /* no command on going */ - HSM_ST_POLL, /* same as HSM_ST, waits longer */ - HSM_ST_TMOUT, /* timeout */ HSM_ST, /* (waiting the device to) transfer data */ HSM_ST_LAST, /* (waiting the device to) complete command */ - HSM_ST_LAST_POLL, /* same as HSM_ST_LAST, waits longer */ HSM_ST_ERR, /* error */ HSM_ST_FIRST, /* (waiting the device to) write CDB or first data block */ @@ -409,7 +401,6 @@ struct ata_port { struct work_struct port_task; unsigned int hsm_task_state; - unsigned long pio_task_timeout; u32 msg_enable; struct list_head eh_done_q; -- cgit v0.10.2 From c2bbc551615c21a4c280c797987dbb50f2701594 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:56:55 +0800 Subject: [PATCH] libata-dev: ata_check_atapi_dma() fix for ATA_FLAG_PIO_POLLING LLDDs ata_check_atapi_dma() fix for LLDDs with the ATA_FLAG_PIO_POLLING flag. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ef0d0dd..61c120d 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2883,6 +2883,15 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) if (ap->ops->check_atapi_dma) rc = ap->ops->check_atapi_dma(qc); + /* We don't support polling DMA. + * Use PIO if the LLDD handles only interrupts in + * the HSM_ST_LAST state and the ATAPI device + * generates CDB interrupts. + */ + if ((ap->flags & ATA_FLAG_PIO_POLLING) && + (qc->dev->flags & ATA_DFLAG_CDB_INTR)) + rc = 1; + return rc; } /** @@ -4038,6 +4047,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_ATAPI_DMA: if (qc->dev->flags & ATA_DFLAG_CDB_INTR) + /* see ata_check_atapi_dma() */ BUG(); break; default: -- cgit v0.10.2 From c234fb00ea8999076728137d96603b713ad8b53f Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:58:38 +0800 Subject: [PATCH] libata-dev: Make the the in_wq check as an inline function Make the the in_wq check easier to read as an inline function. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 61c120d..27078c0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3536,6 +3536,33 @@ err_out: } /** + * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue. + * @ap: the target ata_port + * @qc: qc on going + * + * RETURNS: + * 1 if ok in workqueue, 0 otherwise. + */ + +static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + if (qc->tf.flags & ATA_TFLAG_POLLING) + return 1; + + if (ap->hsm_task_state == HSM_ST_FIRST) { + if (qc->tf.protocol == ATA_PROT_PIO && + (qc->tf.flags & ATA_TFLAG_WRITE)) + return 1; + + if (is_atapi_taskfile(&qc->tf) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + } + + return 0; +} + +/** * ata_hsm_move - move the HSM to the next state. * @ap: the target ata_port * @qc: qc on going @@ -3558,12 +3585,7 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, * like DMA polling into the workqueue. Notice that * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). */ - WARN_ON(in_wq != ((qc->tf.flags & ATA_TFLAG_POLLING) || - (ap->hsm_task_state == HSM_ST_FIRST && - ((qc->tf.protocol == ATA_PROT_PIO && - (qc->tf.flags & ATA_TFLAG_WRITE)) || - (is_atapi_taskfile(&qc->tf) && - !(qc->dev->flags & ATA_DFLAG_CDB_INTR)))))); + WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc)); /* check error */ if (unlikely(status & (ATA_ERR | ATA_DF))) { -- cgit v0.10.2 From 999bb6f4260f9499fdeab3f8fdcd8b9013eca39e Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 18:07:48 +0800 Subject: [PATCH] libata-dev: irq-pio minor fixes (respin) irq-pio minor fixes for printk() and comments. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 27078c0..d68f5d5 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1295,7 +1295,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, if (dev->id[59] & 0x100) { dev->multi_count = dev->id[59] & 0xff; DPRINTK("ata%u: dev %u multi count %u\n", - ap->id, device, dev->multi_count); + ap->id, dev->devno, dev->multi_count); } dev->cdb_len = 16; @@ -3594,6 +3594,9 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, } fsm_start: + DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, ap->hsm_task_state, status); + switch (ap->hsm_task_state) { case HSM_ST_FIRST: /* Send first data block or PACKET CDB */ @@ -3720,6 +3723,7 @@ fsm_start: ap->hsm_task_state = HSM_ST_IDLE; + /* complete taskfile transaction */ if (in_wq) ata_poll_qc_complete(qc); else @@ -4241,9 +4245,6 @@ inline unsigned int ata_host_intr (struct ata_port *ap, if (unlikely(status & ATA_BUSY)) goto idle_irq; - DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", - ap->id, qc->tf.protocol, ap->hsm_task_state, status); - /* ack bmdma irq events */ ap->ops->irq_clear(ap); -- cgit v0.10.2 From 71601958f73b952281f2b02e16d1f11c99ee0a8b Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 18:11:12 +0800 Subject: [PATCH] libata-dev: fix the device err check sequence (respin) Current irq-pio checks ERR bit and stops on ERR before it does anything else. This behavior doesn't look right. The DRQ bit should take higher precedence than the ERR bit. Changes: - Let the HSM do the data transfer whenever the device asks for DRQ bit, even if the ERR bit is set. - For DRQ=1 ERR=1, don't trust the data Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index d68f5d5..59cb129 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3587,12 +3587,6 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, */ WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc)); - /* check error */ - if (unlikely(status & (ATA_ERR | ATA_DF))) { - qc->err_mask |= AC_ERR_DEV; - ap->hsm_task_state = HSM_ST_ERR; - } - fsm_start: DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", ap->id, qc->tf.protocol, ap->hsm_task_state, status); @@ -3615,6 +3609,17 @@ fsm_start: goto fsm_start; } + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * Anyway, we respect DRQ here and let HSM go on + * without changing hsm_task_state to HSM_ST_ERR. + */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", + ap->id, status); + qc->err_mask |= AC_ERR_DEV; + } + /* Send the CDB (atapi) or the first data block (ata pio out). * During the state transition, interrupt handler shouldn't * be invoked before the data transfer is complete and @@ -3657,6 +3662,17 @@ fsm_start: goto fsm_start; } + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * Anyway, we respect DRQ here and let HSM go on + * without changing hsm_task_state to HSM_ST_ERR. + */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", + ap->id, status); + qc->err_mask |= AC_ERR_DEV; + } + atapi_pio_bytes(qc); if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) @@ -3672,6 +3688,22 @@ fsm_start: goto fsm_start; } + /* Some devices may ask for data transfer (DRQ=1) + * alone with ERR=1 for PIO reads. + * We respect DRQ here and let HSM go on without + * changing hsm_task_state to HSM_ST_ERR. + */ + if (unlikely(status & (ATA_ERR | ATA_DF))) { + /* For writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + WARN_ON(qc->tf.flags & ATA_TFLAG_WRITE); + + /* data might be corrputed */ + qc->err_mask |= AC_ERR_DEV; + } + ata_pio_sectors(qc); if (ap->hsm_task_state == HSM_ST_LAST && -- cgit v0.10.2 From 52a3220599647ba429fcbca2388ec35b850fa72f Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 18:18:15 +0800 Subject: [PATCH] libata-dev: wait idle after reading the last data block Some CD-ROM drives are slow to clear DRQ, after the last data block is read by PIO. Use ata_wait_idle() after reading the last data block. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 59cb129..5fdc314 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3710,7 +3710,7 @@ fsm_start: (!(qc->tf.flags & ATA_TFLAG_WRITE))) { /* all data read */ ata_altstatus(ap); - status = ata_chk_status(ap); + status = ata_wait_idle(ap); goto fsm_start; } } -- cgit v0.10.2 From 08a556db919f67e1e4d33ae8d40f7222da34d994 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 31 Mar 2006 13:29:04 +0800 Subject: [PATCH] libata-dev: print out information for ATAPI devices with CDB interrupts print out information for ATAPI devices with CDB interrupts Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index a14187e..f18742e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1305,6 +1305,8 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, /* ATAPI-specific feature tests */ else if (dev->class == ATA_DEV_ATAPI) { + char *cdb_intr_string = ""; + rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); @@ -1313,13 +1315,16 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, } dev->cdb_len = (unsigned int) rc; - if (ata_id_cdb_intr(dev->id)) + if (ata_id_cdb_intr(dev->id)) { dev->flags |= ATA_DFLAG_CDB_INTR; + cdb_intr_string = ", CDB intr"; + } /* print device info to dmesg */ if (print_info) - printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", - ap->id, dev->devno, ata_mode_string(xfer_mask)); + printk(KERN_INFO "ata%u: dev %u ATAPI, max %s%s\n", + ap->id, dev->devno, ata_mode_string(xfer_mask), + cdb_intr_string); } ap->host->max_cmd_len = 0; -- cgit v0.10.2 From eee6c32f5f114f9b9f2d94862f0dc0d3ff523864 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 1 Apr 2006 17:38:43 +0800 Subject: [PATCH] libata-dev: handle DRQ=1 ERR=1 (revised) Handle DRQ=1 ERR=1 situation. Revised according to what IDE try_to_flush_leftover_data() does. Changes: - For ATA PIO writes and ATAPI devices, just stop the HSM and let EH handle it. - For ATA PIO reads, read only one block of junk data and then let EH handle it. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 6fc25f6..da13dec 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3640,13 +3640,16 @@ fsm_start: /* Device should not ask for data transfer (DRQ=1) * when it finds something wrong. - * Anyway, we respect DRQ here and let HSM go on - * without changing hsm_task_state to HSM_ST_ERR. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. */ if (unlikely(status & (ATA_ERR | ATA_DF))) { printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", ap->id, status); qc->err_mask |= AC_ERR_DEV; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; } /* Send the CDB (atapi) or the first data block (ata pio out). @@ -3693,13 +3696,16 @@ fsm_start: /* Device should not ask for data transfer (DRQ=1) * when it finds something wrong. - * Anyway, we respect DRQ here and let HSM go on - * without changing hsm_task_state to HSM_ST_ERR. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. */ if (unlikely(status & (ATA_ERR | ATA_DF))) { printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", ap->id, status); qc->err_mask |= AC_ERR_DEV; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; } atapi_pio_bytes(qc); @@ -3717,20 +3723,32 @@ fsm_start: goto fsm_start; } - /* Some devices may ask for data transfer (DRQ=1) - * alone with ERR=1 for PIO reads. - * We respect DRQ here and let HSM go on without - * changing hsm_task_state to HSM_ST_ERR. + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. */ if (unlikely(status & (ATA_ERR | ATA_DF))) { - /* For writes, ERR=1 DRQ=1 doesn't make - * sense since the data block has been - * transferred to the device. - */ - WARN_ON(qc->tf.flags & ATA_TFLAG_WRITE); - /* data might be corrputed */ qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + ata_altstatus(ap); + status = ata_wait_idle(ap); + } + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; } ata_pio_sectors(qc); -- cgit v0.10.2 From c13b56a1130bbfacfb588de100e5a248383805a6 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 2 Apr 2006 10:34:24 -0400 Subject: [libata] irq-pio: Fix merge mistake diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9de48dd..fc3e57f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4125,101 +4125,6 @@ fsm_start: } /** - * ata_qc_timeout - Handle timeout of queued command - * @qc: Command that timed out - * - * Some part of the kernel (currently, only the SCSI layer) - * has noticed that the active command on port @ap has not - * completed after a specified length of time. Handle this - * condition by disabling DMA (if necessary) and completing - * transactions, with error if necessary. - * - * This also handles the case of the "lost interrupt", where - * for some reason (possibly hardware bug, possibly driver bug) - * an interrupt was not delivered to the driver, even though the - * transaction completed successfully. - * - * LOCKING: - * Inherited from SCSI layer (none, can sleep) - */ - -static void ata_qc_timeout(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_host_set *host_set = ap->host_set; - u8 host_stat = 0, drv_stat; - unsigned long flags; - - DPRINTK("ENTER\n"); - - ap->hsm_task_state = HSM_ST_IDLE; - - spin_lock_irqsave(&host_set->lock, flags); - - switch (qc->tf.protocol) { - - case ATA_PROT_DMA: - case ATA_PROT_ATAPI_DMA: - host_stat = ap->ops->bmdma_status(ap); - - /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(qc); - - /* fall through */ - - default: - ata_altstatus(ap); - drv_stat = ata_chk_status(ap); - - /* ack bmdma irq events */ - ap->ops->irq_clear(ap); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", - ap->id, qc->tf.command, drv_stat, host_stat); - - ap->hsm_task_state = HSM_ST_IDLE; - - /* complete taskfile transaction */ - qc->err_mask |= AC_ERR_TIMEOUT; - break; - } - - spin_unlock_irqrestore(&host_set->lock, flags); - - ata_eh_qc_complete(qc); - - DPRINTK("EXIT\n"); -} - -/** - * ata_eng_timeout - Handle timeout of queued command - * @ap: Port on which timed-out command is active - * - * Some part of the kernel (currently, only the SCSI layer) - * has noticed that the active command on port @ap has not - * completed after a specified length of time. Handle this - * condition by disabling DMA (if necessary) and completing - * transactions, with error if necessary. - * - * This also handles the case of the "lost interrupt", where - * for some reason (possibly hardware bug, possibly driver bug) - * an interrupt was not delivered to the driver, even though the - * transaction completed successfully. - * - * LOCKING: - * Inherited from SCSI layer (none, can sleep) - */ - -void ata_eng_timeout(struct ata_port *ap) -{ - DPRINTK("ENTER\n"); - - ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag)); - - DPRINTK("EXIT\n"); -} - -/** * ata_qc_new - Request an available ATA command, for queueing * @ap: Port associated with device @dev * @dev: Device from whom we request an available command structure diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index e73f561..011e083 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -137,6 +137,7 @@ int ata_scsi_error(struct Scsi_Host *host) * LOCKING: * Inherited from SCSI layer (none, can sleep) */ + static void ata_qc_timeout(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -171,8 +172,10 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", ap->id, qc->tf.command, drv_stat, host_stat); + ap->hsm_task_state = HSM_ST_IDLE; + /* complete taskfile transaction */ - qc->err_mask |= ac_err_mask(drv_stat); + qc->err_mask |= AC_ERR_TIMEOUT; break; } -- cgit v0.10.2 From 4332a771f4d2f23a6d3beff3dd5405e79775a211 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 3 Apr 2006 17:43:24 +0800 Subject: [PATCH] libata-dev: irq-pio minor fix irq-pio minor fix: - remove the redundant hsm_task_state = HSM_ST_IDLE - add devno to printk() as done in upstream Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 5653729..d270b23 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4043,8 +4043,8 @@ fsm_start: } /* no more data to transfer */ - DPRINTK("ata%u: command complete, drv_stat 0x%x\n", - ap->id, status); + DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n", + ap->id, qc->dev->devno, status); WARN_ON(qc->err_mask); @@ -4061,8 +4061,8 @@ fsm_start: case HSM_ST_ERR: if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_ERR "ata%u: command error, drv_stat 0x%x\n", - ap->id, status); + printk(KERN_ERR "ata%u: dev %u command error, drv_stat 0x%x\n", + ap->id, qc->dev->devno, status); /* make sure qc->err_mask is available to * know what's wrong and recover diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 011e083..9a8eea1 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -137,7 +137,6 @@ int ata_scsi_error(struct Scsi_Host *host) * LOCKING: * Inherited from SCSI layer (none, can sleep) */ - static void ata_qc_timeout(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -172,8 +171,6 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", ap->id, qc->tf.command, drv_stat, host_stat); - ap->hsm_task_state = HSM_ST_IDLE; - /* complete taskfile transaction */ qc->err_mask |= AC_ERR_TIMEOUT; break; -- cgit v0.10.2 From 31ce6daefe2d312e31ee06b0b3301b1cb7878c04 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 3 Apr 2006 18:31:44 +0800 Subject: [PATCH] libata-dev: irq-pio minor fix 2 irq-pio minor fix 2: - Use qc as data for ata_pio_task(). Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index d270b23..57b3240 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4097,9 +4097,6 @@ static void ata_pio_task(void *_data) fsm_start: WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - /* * This is purely heuristic. This is a fast path. * Sometimes when we enter, BSY will be cleared in @@ -4112,7 +4109,7 @@ fsm_start: msleep(2); status = ata_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ata_port_queue_task(ap, ata_pio_task, ap, ATA_SHORT_PAUSE); + ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE); return; } } @@ -4347,7 +4344,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_LAST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_port_queue_task(ap, ata_pio_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); break; @@ -4369,7 +4366,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - ata_port_queue_task(ap, ata_pio_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); /* always send first data block using * the ata_pio_task() codepath. @@ -4379,7 +4376,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_port_queue_task(ap, ata_pio_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); /* if polling, ata_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. @@ -4400,7 +4397,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_port_queue_task(ap, ata_pio_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); break; case ATA_PROT_ATAPI_DMA: @@ -4412,7 +4409,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_port_queue_task(ap, ata_pio_task, ap, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); break; default: -- cgit v0.10.2 From 89f48c4d67dd875cf2216d4402bf77eda41fbdd9 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Mon, 15 May 2006 20:57:18 +0900 Subject: [PATCH] SCSI: Introduce scsi_req_abort_cmd (REPOST) Introduce scsi_req_abort_cmd(struct scsi_cmnd *). This function requests that SCSI Core start recovery for the command by deleting the timer and adding the command to the eh queue. It can be called by either LLDDs or SCSI Core. LLDDs who implement their own error recovery MAY ignore the timeout event if they generated scsi_req_abort_cmd. First post: http://marc.theaimsgroup.com/?l=linux-scsi&m=113833937421677&w=2 Signed-off-by: Luben Tuikov Signed-off-by: Tejun Heo diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 73994e2..dae4f08 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -720,6 +720,24 @@ void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq) static DEFINE_PER_CPU(struct list_head, scsi_done_q); /** + * scsi_req_abort_cmd -- Request command recovery for the specified command + * cmd: pointer to the SCSI command of interest + * + * This function requests that SCSI Core start recovery for the + * command by deleting the timer and adding the command to the eh + * queue. It can be called by either LLDDs or SCSI Core. LLDDs who + * implement their own error recovery MAY ignore the timeout event if + * they generated scsi_req_abort_cmd. + */ +void scsi_req_abort_cmd(struct scsi_cmnd *cmd) +{ + if (!scsi_delete_timer(cmd)) + return; + scsi_times_out(cmd); +} +EXPORT_SYMBOL(scsi_req_abort_cmd); + +/** * scsi_done - Enqueue the finished SCSI command into the done queue. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 1ace1b9..88c6c4da 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -151,5 +151,6 @@ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); extern void scsi_put_command(struct scsi_cmnd *); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); +extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); #endif /* _SCSI_SCSI_CMND_H */ -- cgit v0.10.2 From ee7863bc68fa6ad6fe7cfcc0e5ebe9efe0c0664e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:20 +0900 Subject: [PATCH] SCSI: implement shost->host_eh_scheduled libata needs to invoke EH without scmd. This patch adds shost->host_eh_scheduled to implement such behavior. Currently the only user of this feature is libata and no general interface is defined. This patch simply adds handling for host_eh_scheduled where needed and exports scsi_eh_wakeup() to modules. The rest is upto libata. This is the result of the following discussion. http://thread.gmane.org/gmane.linux.scsi/23853/focus=9760 In short, SCSI host is not supposed to know about exceptions unrelated to specific device or command. Such exceptions should be handled by transport layer proper. However, the distinction is not essential to ATA and libata is planning to depart from SCSI, so, for the time being, libata will be using SCSI EH to handle such exceptions. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1c75646..9ca71cb 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -56,6 +56,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost) printk("Waking error handler thread\n")); } } +EXPORT_SYMBOL_GPL(scsi_eh_wakeup); /** * scsi_eh_scmd_add - add scsi cmd to error handling. @@ -1517,7 +1518,7 @@ int scsi_error_handler(void *data) */ set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { - if (shost->host_failed == 0 || + if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || shost->host_failed != shost->host_busy) { SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d sleeping\n", diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7b0f9a3..c55d195 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -566,7 +566,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, flags); shost->host_busy--; if (unlikely(scsi_host_in_recovery(shost) && - shost->host_failed)) + (shost->host_failed || shost->host_eh_scheduled))) scsi_eh_wakeup(shost); spin_unlock(shost->host_lock); spin_lock(sdev->request_queue->queue_lock); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 27c4827..0b39081 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -63,7 +63,6 @@ extern int scsi_delete_timer(struct scsi_cmnd *); extern void scsi_times_out(struct scsi_cmnd *cmd); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); -extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); /* scsi_lib.c */ diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index d160880..212c983 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -35,6 +35,7 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr) } +extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q); extern void scsi_eh_flush_done_q(struct list_head *done_q); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index de6ce54..a42efd6 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -472,6 +472,7 @@ struct Scsi_Host { */ unsigned int host_busy; /* commands actually active on low-level */ unsigned int host_failed; /* commands that failed. */ + unsigned int host_eh_scheduled; /* EH scheduled without command */ unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ int resetting; /* if set, it means that last_reset is a valid value */ -- cgit v0.10.2 From c44078c03f018c8cc9d7463b0db4c6c7fb316792 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:21 +0900 Subject: [PATCH] libata: silly fix in ata_scsi_start_stop_xlat() Don't directly access &qc->tf when tf == &qc->tf. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 9871f82..b0c83c2 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -748,7 +748,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, tf->nsect = 1; /* 1 sector, lba=0 */ if (qc->dev->flags & ATA_DFLAG_LBA) { - qc->tf.flags |= ATA_TFLAG_LBA; + tf->flags |= ATA_TFLAG_LBA; tf->lbah = 0x0; tf->lbam = 0x0; -- cgit v0.10.2 From 3c567b7d1137633f3ff67cd1df94abc5fd497a85 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:23 +0900 Subject: [PATCH] libata: rename ata_down_sata_spd_limit() and friends Rename ata_down_sata_spd_limit() and friends to sata_down_spd_limit() and likewise for simplicity & consistency. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 509178c..196c09f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1465,7 +1465,7 @@ static int ata_bus_probe(struct ata_port *ap) tries[dev->devno] = 0; break; case -EIO: - ata_down_sata_spd_limit(ap); + sata_down_spd_limit(ap); /* fall through */ default: tries[dev->devno]--; @@ -1640,12 +1640,12 @@ void ata_port_disable(struct ata_port *ap) } /** - * ata_down_sata_spd_limit - adjust SATA spd limit downward + * sata_down_spd_limit - adjust SATA spd limit downward * @ap: Port to adjust SATA spd limit for * * Adjust SATA spd limit of @ap downward. Note that this * function only adjusts the limit. The change must be applied - * using ata_set_sata_spd(). + * using sata_set_spd(). * * LOCKING: * Inherited from caller. @@ -1653,7 +1653,7 @@ void ata_port_disable(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure */ -int ata_down_sata_spd_limit(struct ata_port *ap) +int sata_down_spd_limit(struct ata_port *ap) { u32 spd, mask; int highbit; @@ -1683,7 +1683,7 @@ int ata_down_sata_spd_limit(struct ata_port *ap) return 0; } -static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) +static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) { u32 spd, limit; @@ -1699,7 +1699,7 @@ static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) } /** - * ata_set_sata_spd_needed - is SATA spd configuration needed + * sata_set_spd_needed - is SATA spd configuration needed * @ap: Port in question * * Test whether the spd limit in SControl matches @@ -1713,7 +1713,7 @@ static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) * RETURNS: * 1 if SATA spd configuration is needed, 0 otherwise. */ -int ata_set_sata_spd_needed(struct ata_port *ap) +int sata_set_spd_needed(struct ata_port *ap) { u32 scontrol; @@ -1722,11 +1722,11 @@ int ata_set_sata_spd_needed(struct ata_port *ap) scontrol = scr_read(ap, SCR_CONTROL); - return __ata_set_sata_spd_needed(ap, &scontrol); + return __sata_set_spd_needed(ap, &scontrol); } /** - * ata_set_sata_spd - set SATA spd according to spd limit + * sata_set_spd - set SATA spd according to spd limit * @ap: Port to set SATA spd for * * Set SATA spd of @ap according to sata_spd_limit. @@ -1738,7 +1738,7 @@ int ata_set_sata_spd_needed(struct ata_port *ap) * 0 if spd doesn't need to be changed, 1 if spd has been * changed. -EOPNOTSUPP if SCR registers are inaccessible. */ -int ata_set_sata_spd(struct ata_port *ap) +int sata_set_spd(struct ata_port *ap) { u32 scontrol; @@ -1746,7 +1746,7 @@ int ata_set_sata_spd(struct ata_port *ap) return -EOPNOTSUPP; scontrol = scr_read(ap, SCR_CONTROL); - if (!__ata_set_sata_spd_needed(ap, &scontrol)) + if (!__sata_set_spd_needed(ap, &scontrol)) return 0; scr_write(ap, SCR_CONTROL, scontrol); @@ -2464,7 +2464,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) DPRINTK("ENTER\n"); - if (ata_set_sata_spd_needed(ap)) { + if (sata_set_spd_needed(ap)) { /* SATA spec says nothing about how to reconfigure * spd. To be on the safe side, turn off phy during * reconfiguration. This works for at least ICH7 AHCI @@ -2474,7 +2474,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) scontrol = (scontrol & 0x0f0) | 0x302; scr_write_flush(ap, SCR_CONTROL, scontrol); - ata_set_sata_spd(ap); + sata_set_spd(ap); } /* issue phy wake/reset */ @@ -2657,7 +2657,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, if (probeinit) probeinit(ap); - if (softreset && !ata_set_sata_spd_needed(ap)) { + if (softreset && !sata_set_spd_needed(ap)) { rc = ata_do_reset(ap, softreset, postreset, classes); if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN) goto done; @@ -2677,7 +2677,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, break; } - if (ata_down_sata_spd_limit(ap)) + if (sata_down_spd_limit(ap)) goto done; printk(KERN_INFO "ata%u: hardreset failed, will retry " @@ -5113,7 +5113,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_port_probe); -EXPORT_SYMBOL_GPL(ata_set_sata_spd); +EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 3f8b0a8..26975df 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -51,8 +51,8 @@ extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen); -extern int ata_down_sata_spd_limit(struct ata_port *ap); -extern int ata_set_sata_spd_needed(struct ata_port *ap); +extern int sata_down_spd_limit(struct ata_port *ap); +extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index e9fd869..8c16725 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -528,7 +528,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) u32 tmp; /* sil24 does the right thing(tm) without any protection */ - ata_set_sata_spd(ap); + sata_set_spd(ap); tout_msec = 100; if (sata_dev_present(ap)) diff --git a/include/linux/libata.h b/include/linux/libata.h index d35b1e3..0b67aaf 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -504,7 +504,7 @@ extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); -extern int ata_set_sata_spd(struct ata_port *ap); +extern int sata_set_spd(struct ata_port *ap); extern int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, -- cgit v0.10.2 From e4fac92ae744cd5d5c3c1774825788e6b91a5965 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:25 +0900 Subject: [PATCH] ahci: hardreset classification fix AHCI calls ata_dev_classify() even when no device is attached which results in false class code. Fix it. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index d23f002..c332554 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -670,7 +670,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) rc = sata_std_hardreset(ap, class); ahci_start_engine(ap); - if (rc == 0) + if (rc == 0 && sata_dev_present(ap)) *class = ahci_dev_classify(ap); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; -- cgit v0.10.2 From e23befe9018319dc218e2e51c20ce480e6b45eeb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:27 +0900 Subject: [PATCH] libata: unexport ata_scsi_error() While moving ata_scsi_error() from LLDD sht to libata transportt, EXPORT_SYMBOL_GPL() entry was left out. Kill it. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 196c09f..85a0042 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5161,7 +5161,6 @@ EXPORT_SYMBOL_GPL(ata_device_resume); EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); -EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); -- cgit v0.10.2 From 6cd727b14f1a6cdcb088d1067c1ba0ba124806a7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:28 +0900 Subject: [PATCH] libata: kill duplicate prototypes Kill duplicate prototypes for ata_eh_qc_complete/retry() in libata.h. Signed-off-by: Tejun Heo diff --git a/include/linux/libata.h b/include/linux/libata.h index 0b67aaf..220b9d7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -530,8 +530,6 @@ extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); -extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); 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_scsi_device_resume(struct scsi_device *); -- cgit v0.10.2 From f8c2c4202d86e14ca03b7adc7ebcb30fc74b24e1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:30 +0900 Subject: [PATCH] libata: fix ->phy_reset class code handling in ata_bus_probe() ata_bus_probe() doesn't clear dev->class after ->phy_reset(). This can result in falsely enabled devices if probing fails. Clear dev->class to ATA_DEV_UNKNOWN after fetching it. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 85a0042..1669dae 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1397,9 +1397,11 @@ static int ata_bus_probe(struct ata_port *ap) } else { ap->ops->phy_reset(ap); - if (!(ap->flags & ATA_FLAG_DISABLED)) - for (i = 0; i < ATA_MAX_DEVICES; i++) + for (i = 0; i < ATA_MAX_DEVICES; i++) { + if (!(ap->flags & ATA_FLAG_DISABLED)) classes[i] = ap->device[i].class; + ap->device[i].class = ATA_DEV_UNKNOWN; + } ata_port_probe(ap); } -- cgit v0.10.2 From 7401abf2f44695ef44eef47d5deba1c20214a063 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:32 +0900 Subject: [PATCH] libata: clear ap->active_tag atomically w.r.t. command completion ap->active_tag was cleared in ata_qc_free(). This left ap->active_tag dangling after ata_qc_complete(). Spurious interrupts inbetween could incorrectly access the qc. Clear active_tag in ata_qc_complete(). This change is necessary for later EH changes. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1669dae..86cd0e0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4083,8 +4083,6 @@ void ata_qc_free(struct ata_queued_cmd *qc) qc->flags = 0; tag = qc->tag; if (likely(ata_tag_valid(tag))) { - if (tag == ap->active_tag) - ap->active_tag = ATA_TAG_POISON; qc->tag = ATA_TAG_POISON; clear_bit(tag, &ap->qactive); } @@ -4098,6 +4096,9 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); + /* command should be marked inactive atomically with qc completion */ + qc->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) -- cgit v0.10.2 From 158693031d7c58a355ec1852052a4fca75fd3bda Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:33 +0900 Subject: [PATCH] libata: hold host_set lock while finishing internal qc Hold host_set lock while finishing internal qc. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 86cd0e0..13bce43 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1031,6 +1031,9 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, spin_unlock_irqrestore(&ap->host_set->lock, flags); } + /* finish up */ + spin_lock_irqsave(&ap->host_set->lock, flags); + *tf = qc->tf; err_mask = qc->err_mask; @@ -1052,6 +1055,8 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, ata_port_probe(ap); } + spin_unlock_irqrestore(&ap->host_set->lock, flags); + return err_mask; } -- cgit v0.10.2 From fe635c7e91036282e4fd0cc5b4eebc712e43270d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:35 +0900 Subject: [PATCH] libata: use preallocated buffers It's not a very good idea to allocate memory during EH. Use statically allocated buffer for dev->id[] and add 512byte buffer ap->sector_buf. This buffer is owned by EH (or probing) and to be used as temporary buffer for various purposes (IDENTIFY, NCQ log page 10h, PM GSCR block). Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 13bce43..af55861 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1099,7 +1099,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * @dev: target device * @p_class: pointer to class of the target device (may be changed) * @post_reset: is this read ID post-reset? - * @p_id: read IDENTIFY page (newly allocated) + * @id: buffer to read IDENTIFY data into * * Read ID data from the specified device. ATA_CMD_ID_ATA is * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI @@ -1113,12 +1113,11 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * 0 on success, -errno otherwise. */ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, - unsigned int *p_class, int post_reset, u16 **p_id) + unsigned int *p_class, int post_reset, u16 *id) { unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; - u16 *id; const char *reason; int rc; @@ -1126,13 +1125,6 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ - id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL); - if (id == NULL) { - rc = -ENOMEM; - reason = "out of memory"; - goto err_out; - } - retry: ata_tf_init(ap, &tf, dev->devno); @@ -1194,13 +1186,12 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, } *p_class = class; - *p_id = id; + return 0; err_out: printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n", ap->id, dev->devno, reason); - kfree(id); return rc; } @@ -1425,9 +1416,7 @@ static int ata_bus_probe(struct ata_port *ap) if (!ata_dev_enabled(dev)) continue; - kfree(dev->id); - dev->id = NULL; - rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id); + rc = ata_dev_read_id(ap, dev, &dev->class, 1, dev->id); if (rc) goto fail; @@ -2788,7 +2777,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, int post_reset) { unsigned int class = dev->class; - u16 *id = NULL; + u16 *id = (void *)ap->sector_buf; int rc; if (!ata_dev_enabled(dev)) { @@ -2796,8 +2785,8 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, goto fail; } - /* allocate & read ID data */ - rc = ata_dev_read_id(ap, dev, &class, post_reset, &id); + /* read ID data */ + rc = ata_dev_read_id(ap, dev, &class, post_reset, id); if (rc) goto fail; @@ -2807,8 +2796,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, goto fail; } - kfree(dev->id); - dev->id = id; + memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ rc = ata_dev_configure(ap, dev, 0); @@ -2818,7 +2806,6 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, fail: printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n", ap->id, dev->devno, rc); - kfree(id); return rc; } @@ -4873,14 +4860,11 @@ void ata_host_set_remove(struct ata_host_set *host_set) int ata_scsi_release(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - int i; DPRINTK("ENTER\n"); ap->ops->port_disable(ap); ata_host_remove(ap, 0); - for (i = 0; i < ATA_MAX_DEVICES; i++) - kfree(ap->device[i].id); DPRINTK("EXIT\n"); return 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index 220b9d7..0e1a3be 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -360,7 +360,7 @@ struct ata_device { unsigned long flags; /* ATA_DFLAG_xxx */ unsigned int class; /* ATA_DEV_xxx */ unsigned int devno; /* 0 or 1 */ - u16 *id; /* IDENTIFY xxx DEVICE data */ + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u8 pio_mode; u8 dma_mode; u8 xfer_mode; @@ -425,6 +425,8 @@ struct ata_port { struct list_head eh_done_q; void *private_data; + + u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ }; struct ata_port_operations { -- cgit v0.10.2 From 3adcebb2b59d590d572844815c906ca30477b14a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:37 +0900 Subject: [PATCH] libata: move ->set_mode() handling into ata_set_mode() Move ->set_mode() handlng into ata_set_mode(). Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index af55861..1efe8a1 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1426,20 +1426,7 @@ static int ata_bus_probe(struct ata_port *ap) } /* configure transfer mode */ - if (ap->ops->set_mode) { - /* FIXME: make ->set_mode handle no device case and - * return error code and failing device on failure as - * ata_set_mode() does. - */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) { - ap->ops->set_mode(ap); - break; - } - rc = 0; - } else - rc = ata_set_mode(ap, &dev); - + rc = ata_set_mode(ap, &dev); if (rc) { down_xfermask = 1; goto fail; @@ -1997,6 +1984,20 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) struct ata_device *dev; int i, rc = 0, used_dma = 0, found = 0; + /* has private set_mode? */ + if (ap->ops->set_mode) { + /* FIXME: make ->set_mode handle no device case and + * return error code and failing device on failure. + */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + if (ata_dev_enabled(&ap->device[i])) { + ap->ops->set_mode(ap); + break; + } + } + return 0; + } + /* step 1: calculate xfer_mask */ for (i = 0; i < ATA_MAX_DEVICES; i++) { unsigned int pio_mask, dma_mask; -- cgit v0.10.2 From 96bd39ec295e49443c8b0c25a6b69fdace18780f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:38 +0900 Subject: [PATCH] libata: remove postreset handling from ata_do_reset() Make ata_do_reset() deal only with reset. postreset is now the responsibility of the caller. This is simpler and eases later prereset addition. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1efe8a1..19ae3fa 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2585,7 +2585,7 @@ int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes) } int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, - ata_postreset_fn_t postreset, unsigned int *classes) + unsigned int *classes) { int i, rc; @@ -2609,9 +2609,6 @@ int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, if (classes[i] == ATA_DEV_UNKNOWN) classes[i] = ATA_DEV_NONE; - if (postreset) - postreset(ap, classes); - return 0; } @@ -2655,7 +2652,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, probeinit(ap); if (softreset && !sata_set_spd_needed(ap)) { - rc = ata_do_reset(ap, softreset, postreset, classes); + rc = ata_do_reset(ap, softreset, classes); if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN) goto done; printk(KERN_INFO "ata%u: softreset failed, will try " @@ -2667,7 +2664,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, goto done; while (1) { - rc = ata_do_reset(ap, hardreset, postreset, classes); + rc = ata_do_reset(ap, hardreset, classes); if (rc == 0) { if (classes[0] != ATA_DEV_UNKNOWN) goto done; @@ -2688,12 +2685,16 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, ap->id); ssleep(5); - rc = ata_do_reset(ap, softreset, postreset, classes); + rc = ata_do_reset(ap, softreset, classes); } done: - if (rc == 0 && classes[0] == ATA_DEV_UNKNOWN) - rc = -ENODEV; + if (rc == 0) { + if (postreset) + postreset(ap, classes); + if (classes[0] == ATA_DEV_UNKNOWN) + rc = -ENODEV; + } return rc; } diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 26975df..6442c2f 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -57,7 +57,7 @@ extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, - ata_postreset_fn_t postreset, unsigned int *classes); + unsigned int *classes); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); -- cgit v0.10.2 From e61e067227bc76b4d9411a50d735c9d87f27b0e2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:40 +0900 Subject: [PATCH] libata: implement qc->result_tf Add qc->result_tf and ATA_QCFLAG_RESULT_TF. This moves the responsibility of loading result TF from post-compltion path to qc execution path. qc->result_tf is loaded if explicitly requested or the qc failsa. This allows more efficient completion implementation and correct handling of result TF for controllers which don't have global TF representation such as sil3124/32. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 19ae3fa..51cb9ca 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -955,7 +955,6 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) { struct completion *waiting = qc->private_data; - qc->ap->ops->tf_read(qc->ap, &qc->tf); complete(waiting); } @@ -997,6 +996,7 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, qc->tf = *tf; if (cdb) memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; qc->dma_dir = dma_dir; if (dma_dir != DMA_NONE) { ata_sg_init_one(qc, buf, buflen); @@ -1034,7 +1034,7 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, /* finish up */ spin_lock_irqsave(&ap->host_set->lock, flags); - *tf = qc->tf; + *tf = qc->result_tf; err_mask = qc->err_mask; ata_qc_free(qc); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index b0c83c2..ce90b63 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -537,7 +537,7 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; - struct ata_taskfile *tf = &qc->tf; + struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; unsigned char *desc = sb + 8; @@ -608,7 +608,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) void ata_gen_fixed_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; - struct ata_taskfile *tf = &qc->tf; + struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); @@ -1199,14 +1199,11 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) */ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && ((cdb[2] & 0x20) || need_sense)) { - qc->ap->ops->tf_read(qc->ap, &qc->tf); ata_gen_ata_desc_sense(qc); } else { if (!need_sense) { cmd->result = SAM_STAT_GOOD; } else { - qc->ap->ops->tf_read(qc->ap, &qc->tf); - /* TODO: decide which descriptor format to use * for 48b LBA devices and call that here * instead of the fixed desc, which is only @@ -1217,10 +1214,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } } - if (need_sense) { - /* The ata_gen_..._sense routines fill in tf */ - ata_dump_status(qc->ap->id, &qc->tf); - } + if (need_sense) + ata_dump_status(qc->ap->id, &qc->result_tf); qc->scsidone(cmd); @@ -2004,7 +1999,6 @@ static void atapi_sense_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - qc->ap->ops->tf_read(qc->ap, &qc->tf); ata_gen_ata_desc_sense(qc); } @@ -2080,7 +2074,6 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - qc->ap->ops->tf_read(qc->ap, &qc->tf); ata_gen_ata_desc_sense(qc); } else { u8 *scsicmd = cmd->cmnd; @@ -2361,6 +2354,9 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) */ qc->nsect = cmd->bufflen / ATA_SECT_SIZE; + /* request result TF */ + qc->flags |= ATA_QCFLAG_RESULT_TF; + return 0; invalid_fld: diff --git a/include/linux/libata.h b/include/linux/libata.h index 0e1a3be..a4b8a41 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -162,7 +162,9 @@ enum { ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */ ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ - ATA_QCFLAG_EH_SCHEDULED = (1 << 4), /* EH scheduled */ + ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + + ATA_QCFLAG_EH_SCHEDULED = (1 << 16), /* EH scheduled */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ @@ -343,7 +345,7 @@ struct ata_queued_cmd { struct scatterlist *__sg; unsigned int err_mask; - + struct ata_taskfile result_tf; ata_qc_cb_t complete_fn; void *private_data; @@ -824,6 +826,10 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->err_mask = 0; ata_tf_init(qc->ap, &qc->tf, qc->dev->devno); + + /* init result_tf such that it indicates normal completion */ + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; } /** @@ -839,9 +845,15 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) */ static inline void ata_qc_complete(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; + if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED)) return; + /* read result TF if failed or requested */ + if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) + ap->ops->tf_read(ap, &qc->result_tf); + __ata_qc_complete(qc); } -- cgit v0.10.2 From ce5f7f3d0cab82d6c16fcb64def8bfc0a3a85dd6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:42 +0900 Subject: [PATCH] sata_sil24: update TF image only when necessary Update TF image (pp->tf) only when necessary. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 8c16725..45b9e37 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -799,17 +799,9 @@ static inline void sil24_host_intr(struct ata_port *ap) if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); - /* - * !HOST_SSAT_ATTN guarantees successful completion, - * so reading back tf registers is unnecessary for - * most commands. TODO: read tf registers for - * commands which require these values on successful - * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER, - * DEVICE RESET and READ PORT MULTIPLIER (any more?). - */ - sil24_update_tf(ap); - if (qc) { + if (qc->flags & ATA_QCFLAG_RESULT_TF) + sil24_update_tf(ap); qc->err_mask |= ac_err_mask(pp->tf.command); ata_qc_complete(qc); } -- cgit v0.10.2 From 838df6284c54447efae956fb9c243d8ba4ab0f47 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:44 +0900 Subject: [PATCH] libata: init ap->cbl to ATA_CBL_SATA early Init ap->cbl to ATA_CBL_SATA in ata_host_init(). This is necessary for soon-to-follow SCR handling function changes. LLDDs are free to change ap->cbl during probing. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 51cb9ca..f29d43c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2370,8 +2370,7 @@ void ata_std_probeinit(struct ata_port *ap) if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) { u32 spd; - /* set cable type and resume link */ - ap->cbl = ATA_CBL_SATA; + /* resume link */ sata_phy_resume(ap); /* init sata_spd_limit to the current value */ @@ -4586,7 +4585,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; - ap->cbl = ATA_CBL_NONE; ap->sata_spd_limit = UINT_MAX; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; @@ -4594,6 +4592,11 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, INIT_WORK(&ap->port_task, NULL, NULL); INIT_LIST_HEAD(&ap->eh_done_q); + /* set cable type */ + ap->cbl = ATA_CBL_NONE; + if (ap->flags & ATA_FLAG_SATA) + ap->cbl = ATA_CBL_SATA; + for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; dev->devno = i; -- cgit v0.10.2 From 34bf21704c848fe00c516d1c8f163db08b70b137 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:46 +0900 Subject: [PATCH] libata: implement new SCR handling and port on/offline functions Implement ata_scr_{valid|read|write|write_flush}() and ata_port_{online|offline}(). These functions replace scr_{read|write}() and sata_dev_present(). Major difference between between the new SCR functions and the old ones is that the new ones have a way to signal error to the caller. This makes handling SCR-available and SCR-unavailable cases in the same path easier. Also, it eases later PM implementation where SCR access can fail due to various reasons. ata_port_{online|offline}() functions return 1 only when they are affirmitive of the condition. e.g. if SCR is unaccessible or presence cannot be determined for other reasons, these functions return 0. So, ata_port_online() != !ata_port_offline(). This distinction is useful in many exception handling cases. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f29d43c..b9c5cbf 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4365,6 +4365,143 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) return IRQ_RETVAL(handled); } +/** + * sata_scr_valid - test whether SCRs are accessible + * @ap: ATA port to test SCR accessibility for + * + * Test whether SCRs are accessible for @ap. + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if SCRs are accessible, 0 otherwise. + */ +int sata_scr_valid(struct ata_port *ap) +{ + return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read; +} + +/** + * sata_scr_read - read SCR register of the specified port + * @ap: ATA port to read SCR for + * @reg: SCR to read + * @val: Place to store read value + * + * Read SCR register @reg of @ap into *@val. This function is + * guaranteed to succeed if the cable type of the port is SATA + * and the port implements ->scr_read. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success, negative errno on failure. + */ +int sata_scr_read(struct ata_port *ap, int reg, u32 *val) +{ + if (sata_scr_valid(ap)) { + *val = ap->ops->scr_read(ap, reg); + return 0; + } + return -EOPNOTSUPP; +} + +/** + * sata_scr_write - write SCR register of the specified port + * @ap: ATA port to write SCR for + * @reg: SCR to write + * @val: value to write + * + * Write @val to SCR register @reg of @ap. This function is + * guaranteed to succeed if the cable type of the port is SATA + * and the port implements ->scr_read. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success, negative errno on failure. + */ +int sata_scr_write(struct ata_port *ap, int reg, u32 val) +{ + if (sata_scr_valid(ap)) { + ap->ops->scr_write(ap, reg, val); + return 0; + } + return -EOPNOTSUPP; +} + +/** + * sata_scr_write_flush - write SCR register of the specified port and flush + * @ap: ATA port to write SCR for + * @reg: SCR to write + * @val: value to write + * + * This function is identical to sata_scr_write() except that this + * function performs flush after writing to the register. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success, negative errno on failure. + */ +int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) +{ + if (sata_scr_valid(ap)) { + ap->ops->scr_write(ap, reg, val); + ap->ops->scr_read(ap, reg); + return 0; + } + return -EOPNOTSUPP; +} + +/** + * ata_port_online - test whether the given port is online + * @ap: ATA port to test + * + * Test whether @ap is online. Note that this function returns 0 + * if online status of @ap cannot be obtained, so + * ata_port_online(ap) != !ata_port_offline(ap). + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if the port online status is available and online. + */ +int ata_port_online(struct ata_port *ap) +{ + u32 sstatus; + + if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3) + return 1; + return 0; +} + +/** + * ata_port_offline - test whether the given port is offline + * @ap: ATA port to test + * + * Test whether @ap is offline. Note that this function returns + * 0 if offline status of @ap cannot be obtained, so + * ata_port_online(ap) != !ata_port_offline(ap). + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if the port offline status is available and offline. + */ +int ata_port_offline(struct ata_port *ap) +{ + u32 sstatus; + + if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3) + return 1; + return 0; +} /* * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, @@ -5133,6 +5270,12 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); +EXPORT_SYMBOL_GPL(sata_scr_valid); +EXPORT_SYMBOL_GPL(sata_scr_read); +EXPORT_SYMBOL_GPL(sata_scr_write); +EXPORT_SYMBOL_GPL(sata_scr_write_flush); +EXPORT_SYMBOL_GPL(ata_port_online); +EXPORT_SYMBOL_GPL(ata_port_offline); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); EXPORT_SYMBOL_GPL(ata_scsi_simulate); diff --git a/include/linux/libata.h b/include/linux/libata.h index a4b8a41..47b9715 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -536,6 +536,12 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_scsi_release(struct Scsi_Host *host); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); +extern int sata_scr_valid(struct ata_port *ap); +extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val); +extern int sata_scr_write(struct ata_port *ap, int reg, u32 val); +extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val); +extern int ata_port_online(struct ata_port *ap); +extern int ata_port_offline(struct ata_port *ap); 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 *); -- cgit v0.10.2 From 81952c5497b40ae56835bd0d6537f8c6bdea07e7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:47 +0900 Subject: [PATCH] libata: use new SCR and on/offline functions Use new SCR and on/offline functions. Note that for LLDD which know it implements SCR callbacks, SCR functions are guaranteed to succeed and ata_port_online() == !ata_port_offline(). Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c332554..c2298fb 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -567,7 +567,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) DPRINTK("ENTER\n"); - if (!sata_dev_present(ap)) { + if (ata_port_offline(ap)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; return 0; @@ -640,7 +640,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) msleep(150); *class = ATA_DEV_NONE; - if (sata_dev_present(ap)) { + if (ata_port_online(ap)) { if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { rc = -EIO; reason = "device not ready"; @@ -670,7 +670,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) rc = sata_std_hardreset(ap, class); ahci_start_engine(ap); - if (rc == 0 && sata_dev_present(ap)) + if (rc == 0 && ata_port_online(ap)) *class = ahci_dev_classify(ap); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index b9c5cbf..56f0af2 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1494,13 +1494,11 @@ static void sata_print_link_status(struct ata_port *ap) { u32 sstatus, scontrol, tmp; - if (!ap->ops->scr_read) + if (sata_scr_read(ap, SCR_STATUS, &sstatus)) return; + sata_scr_read(ap, SCR_CONTROL, &scontrol); - sstatus = scr_read(ap, SCR_STATUS); - scontrol = scr_read(ap, SCR_CONTROL); - - if (sata_dev_present(ap)) { + if (ata_port_online(ap)) { tmp = (sstatus >> 4) & 0xf; printk(KERN_INFO "ata%u: SATA link up %s (SStatus %X SControl %X)\n", @@ -1531,17 +1529,18 @@ void __sata_phy_reset(struct ata_port *ap) if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ - scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(ap, SCR_CONTROL, 0x301); /* Couldn't find anything in SATA I/II specs, but * AHCI-1.1 10.4.2 says at least 1 ms. */ mdelay(1); } - scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */ + /* phy wake/clear reset */ + sata_scr_write_flush(ap, SCR_CONTROL, 0x300); /* wait for phy to become ready, if necessary */ do { msleep(200); - sstatus = scr_read(ap, SCR_STATUS); + sata_scr_read(ap, SCR_STATUS, &sstatus); if ((sstatus & 0xf) != 1) break; } while (time_before(jiffies, timeout)); @@ -1550,7 +1549,7 @@ void __sata_phy_reset(struct ata_port *ap) sata_print_link_status(ap); /* TODO: phy layer with polling, timeouts, etc. */ - if (sata_dev_present(ap)) + if (!ata_port_offline(ap)) ata_port_probe(ap); else ata_port_disable(ap); @@ -1638,11 +1637,12 @@ void ata_port_disable(struct ata_port *ap) */ int sata_down_spd_limit(struct ata_port *ap) { - u32 spd, mask; - int highbit; + u32 sstatus, spd, mask; + int rc, highbit; - if (ap->cbl != ATA_CBL_SATA || !ap->ops->scr_read) - return -EOPNOTSUPP; + rc = sata_scr_read(ap, SCR_STATUS, &sstatus); + if (rc) + return rc; mask = ap->sata_spd_limit; if (mask <= 1) @@ -1650,7 +1650,7 @@ int sata_down_spd_limit(struct ata_port *ap) highbit = fls(mask) - 1; mask &= ~(1 << highbit); - spd = (scr_read(ap, SCR_STATUS) >> 4) & 0xf; + spd = (sstatus >> 4) & 0xf; if (spd <= 1) return -EINVAL; spd--; @@ -1700,11 +1700,9 @@ int sata_set_spd_needed(struct ata_port *ap) { u32 scontrol; - if (ap->cbl != ATA_CBL_SATA || !ap->ops->scr_read) + if (sata_scr_read(ap, SCR_CONTROL, &scontrol)) return 0; - scontrol = scr_read(ap, SCR_CONTROL); - return __sata_set_spd_needed(ap, &scontrol); } @@ -1719,20 +1717,22 @@ int sata_set_spd_needed(struct ata_port *ap) * * RETURNS: * 0 if spd doesn't need to be changed, 1 if spd has been - * changed. -EOPNOTSUPP if SCR registers are inaccessible. + * changed. Negative errno if SCR registers are inaccessible. */ int sata_set_spd(struct ata_port *ap) { u32 scontrol; + int rc; - if (ap->cbl != ATA_CBL_SATA || !ap->ops->scr_read) - return -EOPNOTSUPP; + if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + return rc; - scontrol = scr_read(ap, SCR_CONTROL); if (!__sata_set_spd_needed(ap, &scontrol)) return 0; - scr_write(ap, SCR_CONTROL, scontrol); + if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + return rc; + return 1; } @@ -2336,20 +2336,26 @@ static int sata_phy_resume(struct ata_port *ap) { unsigned long timeout = jiffies + (HZ * 5); u32 scontrol, sstatus; + int rc; + + if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + return rc; - scontrol = scr_read(ap, SCR_CONTROL); scontrol = (scontrol & 0x0f0) | 0x300; - scr_write_flush(ap, SCR_CONTROL, scontrol); + + if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + return rc; /* Wait for phy to become ready, if necessary. */ do { msleep(200); - sstatus = scr_read(ap, SCR_STATUS); + if ((rc = sata_scr_read(ap, SCR_STATUS, &sstatus))) + return rc; if ((sstatus & 0xf) != 1) return 0; } while (time_before(jiffies, timeout)); - return -1; + return -EBUSY; } /** @@ -2367,21 +2373,20 @@ static int sata_phy_resume(struct ata_port *ap) */ void ata_std_probeinit(struct ata_port *ap) { - if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) { - u32 spd; - - /* resume link */ - sata_phy_resume(ap); + u32 scontrol; - /* init sata_spd_limit to the current value */ - spd = (scr_read(ap, SCR_CONTROL) & 0xf0) >> 4; - if (spd) - ap->sata_spd_limit &= (1 << spd) - 1; + /* resume link */ + sata_phy_resume(ap); - /* wait for device */ - if (sata_dev_present(ap)) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + /* init sata_spd_limit to the current value */ + if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { + int spd = (scontrol >> 4) & 0xf; + ap->sata_spd_limit &= (1 << spd) - 1; } + + /* wait for device */ + if (ata_port_online(ap)) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); } /** @@ -2406,7 +2411,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) DPRINTK("ENTER\n"); - if (ap->ops->scr_read && !sata_dev_present(ap)) { + if (ata_port_offline(ap)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -2457,6 +2462,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) int sata_std_hardreset(struct ata_port *ap, unsigned int *class) { u32 scontrol; + int rc; DPRINTK("ENTER\n"); @@ -2466,17 +2472,25 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) * reconfiguration. This works for at least ICH7 AHCI * and Sil3124. */ - scontrol = scr_read(ap, SCR_CONTROL); + if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + return rc; + scontrol = (scontrol & 0x0f0) | 0x302; - scr_write_flush(ap, SCR_CONTROL, scontrol); + + if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + return rc; sata_set_spd(ap); } /* issue phy wake/reset */ - scontrol = scr_read(ap, SCR_CONTROL); + if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + return rc; + scontrol = (scontrol & 0x0f0) | 0x301; - scr_write_flush(ap, SCR_CONTROL, scontrol); + + if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) + return rc; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. @@ -2487,7 +2501,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) sata_phy_resume(ap); /* TODO: phy layer with polling, timeouts, etc. */ - if (!sata_dev_present(ap)) { + if (ata_port_offline(ap)) { *class = ATA_DEV_NONE; DPRINTK("EXIT, link offline\n"); return 0; @@ -2527,8 +2541,7 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) DPRINTK("ENTER\n"); /* print link status */ - if (ap->cbl == ATA_CBL_SATA) - sata_print_link_status(ap); + sata_print_link_status(ap); /* re-enable interrupts */ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ @@ -2575,7 +2588,7 @@ int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes) ata_reset_fn_t hardreset; hardreset = NULL; - if (ap->cbl == ATA_CBL_SATA && ap->ops->scr_read) + if (sata_scr_valid(ap)) hardreset = sata_std_hardreset; return ata_drive_probe_reset(ap, ata_std_probeinit, diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 181917a..748569b 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1309,8 +1309,8 @@ static void mv_err_intr(struct ata_port *ap) edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); if (EDMA_ERR_SERR & edma_err_cause) { - serr = scr_read(ap, SCR_ERROR); - scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(ap, SCR_ERROR, &serr); + sata_scr_write_flush(ap, SCR_ERROR, serr); } if (EDMA_ERR_SELF_DIS & edma_err_cause) { struct mv_port_priv *pp = ap->private_data; @@ -1934,15 +1934,16 @@ static void __mv_phy_reset(struct ata_port *ap, int can_sleep) /* Issue COMRESET via SControl */ comreset_retry: - scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(ap, SCR_CONTROL, 0x301); __msleep(1, can_sleep); - scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(ap, SCR_CONTROL, 0x300); __msleep(20, can_sleep); timeout = jiffies + msecs_to_jiffies(200); do { - sstatus = scr_read(ap, SCR_STATUS) & 0x3; + sata_scr_read(ap, SCR_STATUS, &sstatus); + sstatus &= 0x3; if ((sstatus == 3) || (sstatus == 0)) break; @@ -1959,11 +1960,12 @@ comreset_retry: "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); - if (sata_dev_present(ap)) { + if (ata_port_online(ap)) { ata_port_probe(ap); } else { + sata_scr_read(ap, SCR_STATUS, &sstatus); printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n", - ap->id, scr_read(ap, SCR_STATUS)); + ap->id, sstatus); ata_port_disable(ap); return; } diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 45b9e37..bedc787 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -464,7 +464,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) DPRINTK("ENTER\n"); - if (!sata_dev_present(ap)) { + if (ata_port_offline(ap)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; goto out; @@ -531,7 +531,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) sata_set_spd(ap); tout_msec = 100; - if (sata_dev_present(ap)) + if (ata_port_online(ap)) tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); @@ -544,7 +544,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) msleep(100); if (tmp & PORT_CS_DEV_RST) { - if (!sata_dev_present(ap)) + if (ata_port_offline(ap)) return 0; reason = "link not ready"; goto err; -- cgit v0.10.2 From a0ab51cefc95cb7756c4914603fea2b1a0f813c5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:49 +0900 Subject: [PATCH] libata: kill old SCR functions and sata_dev_present() Kill now unused scr_{read|write|write_flush}() and sata_dev_present(). Signed-off-by: Tejun Heo diff --git a/include/linux/libata.h b/include/linux/libata.h index 47b9715..cd467cd 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -939,28 +939,6 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) return status; } -static inline u32 scr_read(struct ata_port *ap, unsigned int reg) -{ - return ap->ops->scr_read(ap, reg); -} - -static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val) -{ - ap->ops->scr_write(ap, reg, val); -} - -static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, - u32 val) -{ - ap->ops->scr_write(ap, reg, val); - (void) ap->ops->scr_read(ap, reg); -} - -static inline unsigned int sata_dev_present(struct ata_port *ap) -{ - return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; -} - static inline int ata_try_flush_cache(const struct ata_device *dev) { return ata_id_wcache_enabled(dev->id) || -- cgit v0.10.2 From 38d87234d6c47ca487fc6344100323d5adc6f32c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:51 +0900 Subject: [PATCH] libata: add dev->ap Add dev->ap which points back to the port the device belongs to. This makes it unnecessary to pass @ap for silly reasons (e.g. printks). Also, this change is necessary to accomodate later PM support which will introduce ATA link inbetween port and device. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 56f0af2..31b65e0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4749,6 +4749,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; + dev->ap = ap; dev->devno = i; dev->pio_mask = UINT_MAX; dev->mwdma_mask = UINT_MAX; diff --git a/include/linux/libata.h b/include/linux/libata.h index cd467cd..ac2d2cc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -358,6 +358,7 @@ struct ata_host_stats { }; struct ata_device { + struct ata_port *ap; u64 n_sectors; /* size of device, if ATA */ unsigned long flags; /* ATA_DFLAG_xxx */ unsigned int class; /* ATA_DEV_xxx */ -- cgit v0.10.2 From 3373efd89dead4ce7818d685729e0431448357c9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:53 +0900 Subject: [PATCH] libata: use dev->ap Use dev->ap where possible and eliminate superflous @ap from functions and structures. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2298fb..f6e4c8e 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -597,7 +597,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) /* restart engine */ ahci_start_engine(ap); - ata_tf_init(ap, &tf, 0); + ata_tf_init(ap->device, &tf); fis = pp->cmd_tbl; /* issue the first D2H Register FIS */ diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 31b65e0..4ced962 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -61,13 +61,10 @@ #include "libata.h" -static unsigned int ata_dev_init_params(struct ata_port *ap, - struct ata_device *dev, - u16 heads, - u16 sectors); -static unsigned int ata_dev_set_xfermode(struct ata_port *ap, - struct ata_device *dev); -static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static unsigned int ata_dev_set_xfermode(struct ata_device *dev); +static void ata_dev_xfermask(struct ata_device *dev); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -412,11 +409,11 @@ static const char *sata_spd_string(unsigned int spd) return spd_str[spd - 1]; } -void ata_dev_disable(struct ata_port *ap, struct ata_device *dev) +void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev)) { printk(KERN_WARNING "ata%u: dev %u disabled\n", - ap->id, dev->devno); + dev->ap->id, dev->devno); dev->class++; } } @@ -960,7 +957,6 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) /** * ata_exec_internal - execute libata internal command - * @ap: Port to which the command is sent * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command @@ -978,10 +974,11 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) * None. Should be called with kernel context, might sleep. */ -unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, +unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen) { + struct ata_port *ap = dev->ap; u8 command = tf->command; struct ata_queued_cmd *qc; DECLARE_COMPLETION(wait); @@ -990,7 +987,7 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, spin_lock_irqsave(&ap->host_set->lock, flags); - qc = ata_qc_new_init(ap, dev); + qc = ata_qc_new_init(dev); BUG_ON(qc == NULL); qc->tf = *tf; @@ -1095,7 +1092,6 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) /** * ata_dev_read_id - Read ID data from the specified device - * @ap: port on which target device resides * @dev: target device * @p_class: pointer to class of the target device (may be changed) * @post_reset: is this read ID post-reset? @@ -1112,9 +1108,10 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * RETURNS: * 0 on success, -errno otherwise. */ -static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, - unsigned int *p_class, int post_reset, u16 *id) +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + int post_reset, u16 *id) { + struct ata_port *ap = dev->ap; unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; @@ -1126,7 +1123,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ retry: - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); switch (class) { case ATA_DEV_ATA: @@ -1143,7 +1140,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, tf.protocol = ATA_PROT_PIO; - err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_FROM_DEVICE, + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { rc = -EIO; @@ -1170,7 +1167,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, * Some drives were very specific about that exact sequence. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { - err_mask = ata_dev_init_params(ap, dev, id[3], id[6]); + err_mask = ata_dev_init_params(dev, id[3], id[6]); if (err_mask) { rc = -EIO; reason = "INIT_DEV_PARAMS failed"; @@ -1195,15 +1192,13 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, return rc; } -static inline u8 ata_dev_knobble(const struct ata_port *ap, - struct ata_device *dev) +static inline u8 ata_dev_knobble(struct ata_device *dev) { - return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); + return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } /** * ata_dev_configure - Configure the specified ATA/ATAPI device - * @ap: Port on which target device resides * @dev: Target device to configure * @print_info: Enable device info printout * @@ -1216,9 +1211,9 @@ static inline u8 ata_dev_knobble(const struct ata_port *ap, * RETURNS: * 0 on success, -errno otherwise */ -static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, - int print_info) +static int ata_dev_configure(struct ata_device *dev, int print_info) { + struct ata_port *ap = dev->ap; const u16 *id = dev->id; unsigned int xfer_mask; int i, rc; @@ -1331,7 +1326,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, ap->device[i].cdb_len); /* limit bridge transfers to udma5, 200 sectors */ - if (ata_dev_knobble(ap, dev)) { + if (ata_dev_knobble(dev)) { if (print_info) printk(KERN_INFO "ata%u(%u): applying bridge limits\n", ap->id, dev->devno); @@ -1416,11 +1411,11 @@ static int ata_bus_probe(struct ata_port *ap) if (!ata_dev_enabled(dev)) continue; - rc = ata_dev_read_id(ap, dev, &dev->class, 1, dev->id); + rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); if (rc) goto fail; - rc = ata_dev_configure(ap, dev, 1); + rc = ata_dev_configure(dev, 1); if (rc) goto fail; } @@ -1453,13 +1448,13 @@ static int ata_bus_probe(struct ata_port *ap) default: tries[dev->devno]--; if (down_xfermask && - ata_down_xfermask_limit(ap, dev, tries[dev->devno] == 1)) + ata_down_xfermask_limit(dev, tries[dev->devno] == 1)) tries[dev->devno] = 0; } if (!tries[dev->devno]) { - ata_down_xfermask_limit(ap, dev, 1); - ata_dev_disable(ap, dev); + ata_down_xfermask_limit(dev, 1); + ata_dev_disable(dev); } goto retry; @@ -1586,15 +1581,15 @@ void sata_phy_reset(struct ata_port *ap) /** * ata_dev_pair - return other device on cable - * @ap: port * @adev: device * * Obtain the other device on the same cable, or if none is * present NULL is returned */ -struct ata_device *ata_dev_pair(struct ata_port *ap, struct ata_device *adev) +struct ata_device *ata_dev_pair(struct ata_device *adev) { + struct ata_port *ap = adev->ap; struct ata_device *pair = &ap->device[1 - adev->devno]; if (!ata_dev_enabled(pair)) return NULL; @@ -1886,7 +1881,6 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, /** * ata_down_xfermask_limit - adjust dev xfer masks downward - * @ap: Port associated with device @dev * @dev: Device to adjust xfer masks * @force_pio0: Force PIO0 * @@ -1900,9 +1894,9 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, * RETURNS: * 0 on success, negative errno on failure */ -int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, - int force_pio0) +int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) { + struct ata_port *ap = dev->ap; unsigned long xfer_mask; int highbit; @@ -1934,8 +1928,9 @@ int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, return -EINVAL; } -static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_port *ap = dev->ap; unsigned int err_mask; int rc; @@ -1943,7 +1938,7 @@ static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) if (dev->xfer_shift == ATA_SHIFT_PIO) dev->flags |= ATA_DFLAG_PIO; - err_mask = ata_dev_set_xfermode(ap, dev); + err_mask = ata_dev_set_xfermode(dev); if (err_mask) { printk(KERN_ERR "ata%u: failed to set xfermode (err_mask=0x%x)\n", @@ -1951,7 +1946,7 @@ static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) return -EIO; } - rc = ata_dev_revalidate(ap, dev, 0); + rc = ata_dev_revalidate(dev, 0); if (rc) return rc; @@ -2007,7 +2002,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) if (!ata_dev_enabled(dev)) continue; - ata_dev_xfermask(ap, dev); + ata_dev_xfermask(dev); pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0); dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); @@ -2060,7 +2055,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) if (!ata_dev_enabled(dev)) continue; - rc = ata_dev_set_mode(ap, dev); + rc = ata_dev_set_mode(dev); if (rc) goto out; } @@ -2712,7 +2707,6 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, /** * ata_dev_same_device - Determine whether new ID matches configured device - * @ap: port on which the device to compare against resides * @dev: device to compare against * @new_class: class of the new device * @new_id: IDENTIFY page of the new device @@ -2727,9 +2721,10 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, * RETURNS: * 1 if @dev matches @new_class and @new_id, 0 otherwise. */ -static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev, - unsigned int new_class, const u16 *new_id) +static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, + const u16 *new_id) { + struct ata_port *ap = dev->ap; const u16 *old_id = dev->id; unsigned char model[2][41], serial[2][21]; u64 new_n_sectors; @@ -2774,7 +2769,6 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev, /** * ata_dev_revalidate - Revalidate ATA device - * @ap: port on which the device to revalidate resides * @dev: device to revalidate * @post_reset: is this revalidation after reset? * @@ -2787,9 +2781,9 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev, * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, - int post_reset) +int ata_dev_revalidate(struct ata_device *dev, int post_reset) { + struct ata_port *ap = dev->ap; unsigned int class = dev->class; u16 *id = (void *)ap->sector_buf; int rc; @@ -2800,12 +2794,12 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, } /* read ID data */ - rc = ata_dev_read_id(ap, dev, &class, post_reset, id); + rc = ata_dev_read_id(dev, &class, post_reset, id); if (rc) goto fail; /* is the device still there? */ - if (!ata_dev_same_device(ap, dev, class, id)) { + if (!ata_dev_same_device(dev, class, id)) { rc = -ENODEV; goto fail; } @@ -2813,7 +2807,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ - rc = ata_dev_configure(ap, dev, 0); + rc = ata_dev_configure(dev, 0); if (rc == 0) return 0; @@ -2895,7 +2889,6 @@ static int ata_dma_blacklisted(const struct ata_device *dev) /** * ata_dev_xfermask - Compute supported xfermask of the given device - * @ap: Port on which the device to compute xfermask for resides * @dev: Device to compute xfermask for * * Compute supported xfermask of @dev and store it in @@ -2910,8 +2903,9 @@ static int ata_dma_blacklisted(const struct ata_device *dev) * LOCKING: * None. */ -static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) +static void ata_dev_xfermask(struct ata_device *dev) { + struct ata_port *ap = dev->ap; struct ata_host_set *hs = ap->host_set; unsigned long xfer_mask; int i; @@ -2964,7 +2958,6 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) /** * ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command - * @ap: Port associated with device @dev * @dev: Device to which command will be sent * * Issue SET FEATURES - XFER MODE command to device @dev @@ -2977,8 +2970,7 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) * 0 on success, AC_ERR_* mask otherwise. */ -static unsigned int ata_dev_set_xfermode(struct ata_port *ap, - struct ata_device *dev) +static unsigned int ata_dev_set_xfermode(struct ata_device *dev) { struct ata_taskfile tf; unsigned int err_mask; @@ -2986,14 +2978,14 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); tf.command = ATA_CMD_SET_FEATURES; tf.feature = SETFEATURES_XFER; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; tf.nsect = dev->xfer_mode; - err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -3001,8 +2993,9 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, /** * ata_dev_init_params - Issue INIT DEV PARAMS command - * @ap: Port associated with device @dev * @dev: Device to which command will be sent + * @heads: Number of heads + * @sectors: Number of sectors * * LOCKING: * Kernel thread context (may sleep) @@ -3010,11 +3003,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, * RETURNS: * 0 on success, AC_ERR_* mask otherwise. */ - -static unsigned int ata_dev_init_params(struct ata_port *ap, - struct ata_device *dev, - u16 heads, - u16 sectors) +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) { struct ata_taskfile tf; unsigned int err_mask; @@ -3026,14 +3016,14 @@ static unsigned int ata_dev_init_params(struct ata_port *ap, /* set up init dev params taskfile */ DPRINTK("init dev params \n"); - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); tf.command = ATA_CMD_INIT_DEV_PARAMS; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; tf.nsect = sectors; tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ - err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4045,16 +4035,15 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) /** * ata_qc_new_init - Request an available ATA command, and initialize it - * @ap: Port associated with device @dev * @dev: Device from whom we request an available command structure * * LOCKING: * None. */ -struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, - struct ata_device *dev) +struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev) { + struct ata_port *ap = dev->ap; struct ata_queued_cmd *qc; qc = ata_qc_new(ap); @@ -4520,19 +4509,18 @@ int ata_port_offline(struct ata_port *ap) * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, * without filling any other registers */ -static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev, - u8 cmd) +static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) { struct ata_taskfile tf; int err; - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); tf.command = cmd; tf.flags |= ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; - err = ata_exec_internal(ap, dev, &tf, NULL, DMA_NONE, NULL, 0); + err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); if (err) printk(KERN_ERR "%s: ata command failed: %d\n", __FUNCTION__, err); @@ -4540,7 +4528,7 @@ static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev, return err; } -static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev) +static int ata_flush_cache(struct ata_device *dev) { u8 cmd; @@ -4552,22 +4540,21 @@ static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev) else cmd = ATA_CMD_FLUSH; - return ata_do_simple_cmd(ap, dev, cmd); + return ata_do_simple_cmd(dev, cmd); } -static int ata_standby_drive(struct ata_port *ap, struct ata_device *dev) +static int ata_standby_drive(struct ata_device *dev) { - return ata_do_simple_cmd(ap, dev, ATA_CMD_STANDBYNOW1); + return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); } -static int ata_start_drive(struct ata_port *ap, struct ata_device *dev) +static int ata_start_drive(struct ata_device *dev) { - return ata_do_simple_cmd(ap, dev, ATA_CMD_IDLEIMMEDIATE); + return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE); } /** * ata_device_resume - wakeup a previously suspended devices - * @ap: port the device is connected to * @dev: the device to resume * * Kick the drive back into action, by sending it an idle immediate @@ -4575,39 +4562,42 @@ static int ata_start_drive(struct ata_port *ap, struct ata_device *dev) * and host. * */ -int ata_device_resume(struct ata_port *ap, struct ata_device *dev) +int ata_device_resume(struct ata_device *dev) { + struct ata_port *ap = dev->ap; + if (ap->flags & ATA_FLAG_SUSPENDED) { struct ata_device *failed_dev; ap->flags &= ~ATA_FLAG_SUSPENDED; while (ata_set_mode(ap, &failed_dev)) - ata_dev_disable(ap, failed_dev); + ata_dev_disable(failed_dev); } if (!ata_dev_enabled(dev)) return 0; if (dev->class == ATA_DEV_ATA) - ata_start_drive(ap, dev); + ata_start_drive(dev); return 0; } /** * ata_device_suspend - prepare a device for suspend - * @ap: port the device is connected to * @dev: the device to suspend * * Flush the cache on the drive, if appropriate, then issue a * standbynow command. */ -int ata_device_suspend(struct ata_port *ap, struct ata_device *dev, pm_message_t state) +int ata_device_suspend(struct ata_device *dev, pm_message_t state) { + struct ata_port *ap = dev->ap; + if (!ata_dev_enabled(dev)) return 0; if (dev->class == ATA_DEV_ATA) - ata_flush_cache(ap, dev); + ata_flush_cache(dev); if (state.event != PM_EVENT_FREEZE) - ata_standby_drive(ap, dev); + ata_standby_drive(dev); ap->flags |= ATA_FLAG_SUSPENDED; return 0; } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index ce90b63..fcbf64e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -302,7 +302,6 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) /** * ata_scsi_qc_new - acquire new ata_queued_cmd reference - * @ap: ATA port to which the new command is attached * @dev: ATA device to which the new command is attached * @cmd: SCSI command that originated this ATA command * @done: SCSI command completion function @@ -321,14 +320,13 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) * RETURNS: * Command allocated, or %NULL if none available. */ -struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, - struct ata_device *dev, +struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct ata_queued_cmd *qc; - qc = ata_qc_new_init(ap, dev); + qc = ata_qc_new_init(dev); if (qc) { qc->scsicmd = cmd; qc->scsidone = done; @@ -398,7 +396,7 @@ int ata_scsi_device_resume(struct scsi_device *sdev) struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = &ap->device[sdev->id]; - return ata_device_resume(ap, dev); + return ata_device_resume(dev); } int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) @@ -406,7 +404,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = &ap->device[sdev->id]; - return ata_device_suspend(ap, dev, state); + return ata_device_suspend(dev, state); } /** @@ -1224,7 +1222,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) /** * 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 * @cmd: SCSI command to execute * @done: SCSI command completion function @@ -1247,17 +1244,16 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * spin_lock_irqsave(host_set lock) */ -static void 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) +static void 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; VPRINTK("ENTER\n"); - qc = ata_scsi_qc_new(ap, dev, cmd, done); + qc = ata_scsi_qc_new(dev, cmd, done); if (!qc) goto err_mem; @@ -1266,7 +1262,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, cmd->sc_data_direction == DMA_TO_DEVICE) { if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", - ap->id, dev->devno); + dev->ap->id, dev->devno); goto err_did; } @@ -2433,19 +2429,20 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, #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 void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *), + struct ata_device *dev) { 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); + ata_scsi_translate(dev, cmd, done, xlat_func); else - ata_scsi_simulate(ap, dev, cmd, done); + ata_scsi_simulate(dev, cmd, done); } else - ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); + ata_scsi_translate(dev, cmd, done, atapi_xlat); } /** @@ -2483,7 +2480,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) dev = ata_scsi_find_dev(ap, scsidev); if (likely(dev)) - __ata_scsi_queuecmd(cmd, done, ap, dev); + __ata_scsi_queuecmd(cmd, done, dev); else { cmd->result = (DID_BAD_TARGET << 16); done(cmd); @@ -2496,7 +2493,6 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) /** * ata_scsi_simulate - simulate SCSI command on ATA device - * @ap: port the device is connected to * @dev: the target device * @cmd: SCSI command being sent to device. * @done: SCSI command completion function. @@ -2508,14 +2504,12 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) * spin_lock_irqsave(host_set lock) */ -void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, +void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; - args.ap = ap; args.dev = dev; args.id = dev->id; args.cmd = cmd; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 6442c2f..c9ff83b 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -32,7 +32,6 @@ #define DRV_VERSION "1.30" /* must be exactly four chars */ struct ata_scsi_args { - struct ata_port *ap; struct ata_device *dev; u16 *id; struct scsi_cmnd *cmd; @@ -43,18 +42,16 @@ struct ata_scsi_args { extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; -extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, - struct ata_device *dev); +extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); -extern void ata_dev_disable(struct ata_port *ap, struct ata_device *dev); +extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); -extern unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, +extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); -extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, - int force_pio0); +extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes); diff --git a/include/linux/libata.h b/include/linux/libata.h index ac2d2cc..8154b36 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -518,8 +518,7 @@ extern void ata_std_probeinit(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); -extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, - int post_reset); +extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); #ifdef CONFIG_PCI @@ -545,8 +544,8 @@ extern int ata_port_online(struct ata_port *ap); extern int ata_port_offline(struct ata_port *ap); 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 *); -extern int ata_device_suspend(struct ata_port *, struct ata_device *, pm_message_t state); +extern int ata_device_resume(struct ata_device *); +extern int ata_device_suspend(struct ata_device *, pm_message_t state); extern int ata_ratelimit(void); extern unsigned int ata_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, @@ -592,15 +591,13 @@ extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void __ata_qc_complete(struct ata_queued_cmd *qc); -extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *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, struct block_device *bdev, sector_t capacity, int geom[]); extern int ata_scsi_slave_config(struct scsi_device *sdev); -extern struct ata_device *ata_dev_pair(struct ata_port *ap, - struct ata_device *adev); +extern struct ata_device *ata_dev_pair(struct ata_device *adev); /* * Timing helpers @@ -812,12 +809,12 @@ static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap, return NULL; } -static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, unsigned int device) +static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) { memset(tf, 0, sizeof(*tf)); - tf->ctl = ap->ctl; - if (device == 0) + tf->ctl = dev->ap->ctl; + if (dev->devno == 0) tf->device = ATA_DEVICE_OBS; else tf->device = ATA_DEVICE_OBS | ATA_DEV1; @@ -832,7 +829,7 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->nbytes = qc->curbytes = 0; qc->err_mask = 0; - ata_tf_init(qc->ap, &qc->tf, qc->dev->devno); + ata_tf_init(qc->dev, &qc->tf); /* init result_tf such that it indicates normal completion */ qc->result_tf.command = ATA_DRDY; -- cgit v0.10.2 From 61440db61fe4945ad9f7b32b4d6a22b17174aa1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:55 +0900 Subject: [PATCH] libata: implement ATA printk helpers Implement ata_{port|dev}_printk() which prefixes the message with proper identification string. This change is necessary for later PM support because devices and links should be identified differently depending on how they are attached. This also helps unifying device id strings. Currently, there are two forms in use (P is the port number D device number) - 'ataP(D):', and 'ataP: dev D '. These macros also make it harder to forget proper ID string (e.g. printing only port number when a device is in question). Debug message handling can be integrated into these printk macros by passing debug type and level via @lv. Signed-off-by: Tejun Heo diff --git a/include/linux/libata.h b/include/linux/libata.h index 8154b36..91e10e6 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -650,7 +650,18 @@ extern void ata_eng_timeout(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); +/* + * printk helpers + */ +#define ata_port_printk(ap, lv, fmt, args...) \ + printk(lv"ata%u: "fmt, (ap)->id , ##args) + +#define ata_dev_printk(dev, lv, fmt, args...) \ + printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args) +/* + * qc helpers + */ static inline int ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc) { -- cgit v0.10.2 From f15a1dafed22d5037e0feea7528e1eeb28a1a7a3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:56 +0900 Subject: [PATCH] libata: use ATA printk helpers Use ATA printk helpers. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index f6e4c8e..a4fb8d0 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -655,8 +655,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) fail_restart: ahci_start_engine(ap); fail: - printk(KERN_ERR "ata%u: softreset failed (%s)\n", - ap->id, reason); + ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); return rc; } @@ -798,9 +797,8 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) if ((ap->device[0].class != ATA_DEV_ATAPI) || ((irq_stat & PORT_IRQ_TF_ERR) == 0)) - printk(KERN_WARNING "ata%u: port reset, " + ata_port_printk(ap, KERN_WARNING, "port reset, " "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", - ap->id, irq_stat, readl(mmio + HOST_IRQ_STAT), readl(port_mmio + PORT_IRQ_STAT), @@ -840,7 +838,7 @@ static void ahci_eng_timeout(struct ata_port *ap) struct ata_queued_cmd *qc; unsigned long flags; - printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id); + ata_port_printk(ap, KERN_WARNING, "handling error/timeout\n"); spin_lock_irqsave(&host_set->lock, flags); diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 62dabf7..af1d46e 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -484,7 +484,7 @@ static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes) struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) { - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); + ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); return 0; } @@ -565,7 +565,7 @@ static unsigned int piix_sata_probe (struct ata_port *ap) static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes) { if (!piix_sata_probe(ap)) { - printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id); + ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n"); return 0; } diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 4ced962..9a97ebd 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -412,8 +412,7 @@ static const char *sata_spd_string(unsigned int spd) void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev)) { - printk(KERN_WARNING "ata%u: dev %u disabled\n", - dev->ap->id, dev->devno); + ata_dev_printk(dev, KERN_WARNING, "disabled\n"); dev->class++; } } @@ -1021,8 +1020,9 @@ unsigned ata_exec_internal(struct ata_device *dev, if (qc->flags & ATA_QCFLAG_ACTIVE) { qc->err_mask = AC_ERR_TIMEOUT; ata_qc_complete(qc); - printk(KERN_WARNING "ata%u: qc timeout (cmd 0x%x)\n", - ap->id, command); + + ata_dev_printk(dev, KERN_WARNING, + "qc timeout (cmd 0x%x)\n", command); } spin_unlock_irqrestore(&ap->host_set->lock, flags); @@ -1187,8 +1187,8 @@ static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, return 0; err_out: - printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n", - ap->id, dev->devno, reason); + ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY " + "(%s, err_mask=0x%x)\n", reason, err_mask); return rc; } @@ -1228,10 +1228,10 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) /* print device capabilities */ if (print_info) - printk(KERN_DEBUG "ata%u: dev %u cfg 49:%04x 82:%04x 83:%04x " - "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n", - ap->id, dev->devno, id[49], id[82], id[83], - id[84], id[85], id[86], id[87], id[88]); + ata_dev_printk(dev, KERN_DEBUG, "cfg 49:%04x 82:%04x 83:%04x " + "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n", + id[49], id[82], id[83], id[84], + id[85], id[86], id[87], id[88]); /* initialize to-be-configured parameters */ dev->flags &= ~ATA_DFLAG_CFG_MASK; @@ -1267,13 +1267,12 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) /* print device info to dmesg */ if (print_info) - printk(KERN_INFO "ata%u: dev %u ATA-%d, " - "max %s, %Lu sectors: %s\n", - ap->id, dev->devno, - ata_id_major_version(id), - ata_mode_string(xfer_mask), - (unsigned long long)dev->n_sectors, - lba_desc); + ata_dev_printk(dev, KERN_INFO, "ATA-%d, " + "max %s, %Lu sectors: %s\n", + ata_id_major_version(id), + ata_mode_string(xfer_mask), + (unsigned long long)dev->n_sectors, + lba_desc); } else { /* CHS */ @@ -1291,13 +1290,12 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) /* print device info to dmesg */ if (print_info) - printk(KERN_INFO "ata%u: dev %u ATA-%d, " - "max %s, %Lu sectors: CHS %u/%u/%u\n", - ap->id, dev->devno, - ata_id_major_version(id), - ata_mode_string(xfer_mask), - (unsigned long long)dev->n_sectors, - dev->cylinders, dev->heads, dev->sectors); + ata_dev_printk(dev, KERN_INFO, "ATA-%d, " + "max %s, %Lu sectors: CHS %u/%u/%u\n", + ata_id_major_version(id), + ata_mode_string(xfer_mask), + (unsigned long long)dev->n_sectors, + dev->cylinders, dev->heads, dev->sectors); } dev->cdb_len = 16; @@ -1307,7 +1305,8 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) else if (dev->class == ATA_DEV_ATAPI) { rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { - printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); + ata_dev_printk(dev, KERN_WARNING, + "unsupported CDB len\n"); rc = -EINVAL; goto err_out_nosup; } @@ -1315,8 +1314,8 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) /* print device info to dmesg */ if (print_info) - printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", - ap->id, dev->devno, ata_mode_string(xfer_mask)); + ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s\n", + ata_mode_string(xfer_mask)); } ap->host->max_cmd_len = 0; @@ -1328,8 +1327,8 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) /* limit bridge transfers to udma5, 200 sectors */ if (ata_dev_knobble(dev)) { if (print_info) - printk(KERN_INFO "ata%u(%u): applying bridge limits\n", - ap->id, dev->devno); + ata_dev_printk(dev, KERN_INFO, + "applying bridge limits\n"); dev->udma_mask &= ATA_UDMA5; dev->max_sectors = ATA_MAX_SECTORS; } @@ -1382,7 +1381,8 @@ static int ata_bus_probe(struct ata_port *ap) if (ap->ops->probe_reset) { rc = ap->ops->probe_reset(ap, classes); if (rc) { - printk("ata%u: reset failed (errno=%d)\n", ap->id, rc); + ata_port_printk(ap, KERN_ERR, + "reset failed (errno=%d)\n", rc); return rc; } } else { @@ -1495,13 +1495,13 @@ static void sata_print_link_status(struct ata_port *ap) if (ata_port_online(ap)) { tmp = (sstatus >> 4) & 0xf; - printk(KERN_INFO - "ata%u: SATA link up %s (SStatus %X SControl %X)\n", - ap->id, sata_spd_string(tmp), sstatus, scontrol); + ata_port_printk(ap, KERN_INFO, + "SATA link up %s (SStatus %X SControl %X)\n", + sata_spd_string(tmp), sstatus, scontrol); } else { - printk(KERN_INFO - "ata%u: SATA link down (SStatus %X SControl %X)\n", - ap->id, sstatus, scontrol); + ata_port_printk(ap, KERN_INFO, + "SATA link down (SStatus %X SControl %X)\n", + sstatus, scontrol); } } @@ -1655,8 +1655,8 @@ int sata_down_spd_limit(struct ata_port *ap) ap->sata_spd_limit = mask; - printk(KERN_WARNING "ata%u: limiting SATA link speed to %s\n", - ap->id, sata_spd_string(fls(mask))); + ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n", + sata_spd_string(fls(mask))); return 0; } @@ -1896,7 +1896,6 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, */ int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) { - struct ata_port *ap = dev->ap; unsigned long xfer_mask; int highbit; @@ -1919,8 +1918,8 @@ int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, &dev->udma_mask); - printk(KERN_WARNING "ata%u: dev %u limiting speed to %s\n", - ap->id, dev->devno, ata_mode_string(xfer_mask)); + ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n", + ata_mode_string(xfer_mask)); return 0; @@ -1930,7 +1929,6 @@ int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) static int ata_dev_set_mode(struct ata_device *dev) { - struct ata_port *ap = dev->ap; unsigned int err_mask; int rc; @@ -1940,9 +1938,8 @@ static int ata_dev_set_mode(struct ata_device *dev) err_mask = ata_dev_set_xfermode(dev); if (err_mask) { - printk(KERN_ERR - "ata%u: failed to set xfermode (err_mask=0x%x)\n", - ap->id, err_mask); + ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " + "(err_mask=0x%x)\n", err_mask); return -EIO; } @@ -1953,9 +1950,8 @@ static int ata_dev_set_mode(struct ata_device *dev) DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n", dev->xfer_shift, (int)dev->xfer_mode); - printk(KERN_INFO "ata%u: dev %u configured for %s\n", - ap->id, dev->devno, - ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode))); + ata_dev_printk(dev, KERN_INFO, "configured for %s\n", + ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode))); return 0; } @@ -2023,8 +2019,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) continue; if (!dev->pio_mode) { - printk(KERN_WARNING "ata%u: dev %u no PIO support\n", - ap->id, dev->devno); + ata_dev_printk(dev, KERN_WARNING, "no PIO support\n"); rc = -EINVAL; goto out; } @@ -2123,8 +2118,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap, } if (status & ATA_BUSY) - printk(KERN_WARNING "ata%u is slow to respond, " - "please be patient\n", ap->id); + ata_port_printk(ap, KERN_WARNING, + "port is slow to respond, please be patient\n"); timeout = timer_start + tmout; while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { @@ -2133,8 +2128,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap, } if (status & ATA_BUSY) { - printk(KERN_ERR "ata%u failed to respond (%lu secs)\n", - ap->id, tmout / HZ); + ata_port_printk(ap, KERN_ERR, "port failed to respond " + "(%lu secs)\n", tmout / HZ); return 1; } @@ -2227,7 +2222,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, * pulldown resistor. */ if (ata_check_status(ap) == 0xFF) { - printk(KERN_ERR "ata%u: SRST failed (status 0xFF)\n", ap->id); + ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n"); return AC_ERR_OTHER; } @@ -2321,7 +2316,7 @@ void ata_bus_reset(struct ata_port *ap) return; err_out: - printk(KERN_ERR "ata%u: disabling port\n", ap->id); + ata_port_printk(ap, KERN_ERR, "disabling port\n"); ap->ops->port_disable(ap); DPRINTK("EXIT\n"); @@ -2424,8 +2419,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) DPRINTK("about to softreset, devmask=%x\n", devmask); err_mask = ata_bus_softreset(ap, devmask); if (err_mask) { - printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n", - ap->id, err_mask); + ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", + err_mask); return -EIO; } @@ -2503,8 +2498,8 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) } if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { - printk(KERN_ERR - "ata%u: COMRESET failed (device not ready)\n", ap->id); + ata_port_printk(ap, KERN_ERR, + "COMRESET failed (device not ready)\n"); return -EIO; } @@ -2662,8 +2657,8 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, rc = ata_do_reset(ap, softreset, classes); if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN) goto done; - printk(KERN_INFO "ata%u: softreset failed, will try " - "hardreset in 5 secs\n", ap->id); + ata_port_printk(ap, KERN_INFO, "softreset failed, " + "will try hardreset in 5 secs\n"); ssleep(5); } @@ -2681,15 +2676,15 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, if (sata_down_spd_limit(ap)) goto done; - printk(KERN_INFO "ata%u: hardreset failed, will retry " - "in 5 secs\n", ap->id); + ata_port_printk(ap, KERN_INFO, "hardreset failed, " + "will retry in 5 secs\n"); ssleep(5); } if (softreset) { - printk(KERN_INFO "ata%u: hardreset succeeded without " - "classification, will retry softreset in 5 secs\n", - ap->id); + ata_port_printk(ap, KERN_INFO, + "hardreset succeeded without classification, " + "will retry softreset in 5 secs\n"); ssleep(5); rc = ata_do_reset(ap, softreset, classes); @@ -2724,15 +2719,13 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, const u16 *new_id) { - struct ata_port *ap = dev->ap; const u16 *old_id = dev->id; unsigned char model[2][41], serial[2][21]; u64 new_n_sectors; if (dev->class != new_class) { - printk(KERN_INFO - "ata%u: dev %u class mismatch %d != %d\n", - ap->id, dev->devno, dev->class, new_class); + ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n", + dev->class, new_class); return 0; } @@ -2743,24 +2736,22 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, new_n_sectors = ata_id_n_sectors(new_id); if (strcmp(model[0], model[1])) { - printk(KERN_INFO - "ata%u: dev %u model number mismatch '%s' != '%s'\n", - ap->id, dev->devno, model[0], model[1]); + ata_dev_printk(dev, KERN_INFO, "model number mismatch " + "'%s' != '%s'\n", model[0], model[1]); return 0; } if (strcmp(serial[0], serial[1])) { - printk(KERN_INFO - "ata%u: dev %u serial number mismatch '%s' != '%s'\n", - ap->id, dev->devno, serial[0], serial[1]); + ata_dev_printk(dev, KERN_INFO, "serial number mismatch " + "'%s' != '%s'\n", serial[0], serial[1]); return 0; } if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) { - printk(KERN_INFO - "ata%u: dev %u n_sectors mismatch %llu != %llu\n", - ap->id, dev->devno, (unsigned long long)dev->n_sectors, - (unsigned long long)new_n_sectors); + ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch " + "%llu != %llu\n", + (unsigned long long)dev->n_sectors, + (unsigned long long)new_n_sectors); return 0; } @@ -2783,9 +2774,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, */ int ata_dev_revalidate(struct ata_device *dev, int post_reset) { - struct ata_port *ap = dev->ap; unsigned int class = dev->class; - u16 *id = (void *)ap->sector_buf; + u16 *id = (void *)dev->ap->sector_buf; int rc; if (!ata_dev_enabled(dev)) { @@ -2812,8 +2802,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) return 0; fail: - printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n", - ap->id, dev->devno, rc); + ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc); return rc; } @@ -2941,8 +2930,8 @@ static void ata_dev_xfermask(struct ata_device *dev) } if (ata_dma_blacklisted(dev)) - printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, " - "disabling DMA\n", ap->id, dev->devno); + ata_dev_printk(dev, KERN_WARNING, + "device is on DMA blacklist, disabling DMA\n"); if (hs->flags & ATA_HOST_SIMPLEX) { if (hs->simplex_claimed) @@ -3733,8 +3722,8 @@ next_sg: unsigned int i; if (words) /* warning if bytes > 1 */ - printk(KERN_WARNING "ata%u: %u bytes trailing data\n", - ap->id, bytes); + ata_dev_printk(qc->dev, KERN_WARNING, + "%u bytes trailing data\n", bytes); for (i = 0; i < words; i++) ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); @@ -3817,8 +3806,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) return; err_out: - printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", - ap->id, dev->devno); + ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n"); qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; } @@ -3887,8 +3875,7 @@ static void ata_pio_error(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_WARNING "ata%u: dev %u PIO error\n", - ap->id, qc->dev->devno); + ata_dev_printk(qc->dev, KERN_WARNING, "PIO error\n"); /* make sure qc->err_mask is available to * know what's wrong and recover @@ -4314,7 +4301,7 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { ata_irq_ack(ap, 0); /* debug trap */ - printk(KERN_WARNING "ata%d: irq trap\n", ap->id); + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } #endif @@ -4522,8 +4509,8 @@ static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); if (err) - printk(KERN_ERR "%s: ata command failed: %d\n", - __FUNCTION__, err); + ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n", + __FUNCTION__, err); return err; } @@ -4863,15 +4850,14 @@ int ata_device_add(const struct ata_probe_ent *ent) (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ - printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " - "bmdma 0x%lX irq %lu\n", - ap->id, - ap->flags & ATA_FLAG_SATA ? 'S' : 'P', - ata_mode_string(xfer_mode_mask), - ap->ioaddr.cmd_addr, - ap->ioaddr.ctl_addr, - ap->ioaddr.bmdma_addr, - ent->irq); + ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX " + "ctl 0x%lX bmdma 0x%lX irq %lu\n", + ap->flags & ATA_FLAG_SATA ? 'S' : 'P', + ata_mode_string(xfer_mode_mask), + ap->ioaddr.cmd_addr, + ap->ioaddr.ctl_addr, + ap->ioaddr.bmdma_addr, + ent->irq); ata_chk_status(ap); host_set->ops->irq_clear(ap); @@ -4909,8 +4895,7 @@ int ata_device_add(const struct ata_probe_ent *ent) rc = scsi_add_host(ap->host, dev); if (rc) { - printk(KERN_ERR "ata%u: scsi_add_host failed\n", - ap->id); + ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n"); /* FIXME: do something useful here */ /* FIXME: handle unconditional calls to * scsi_scan_host and ata_host_remove, below, diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index c31b13f..959a1cd 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -167,8 +167,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) /* ack bmdma irq events */ ap->ops->irq_clear(ap); - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", - ap->id, qc->tf.command, drv_stat, host_stat); + ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, " + "stat 0x%x host_stat 0x%x\n", + qc->tf.command, drv_stat, host_stat); /* complete taskfile transaction */ qc->err_mask |= ac_err_mask(drv_stat); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index fcbf64e..a9b4083 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1261,8 +1261,8 @@ static void ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, if (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_TO_DEVICE) { if (unlikely(cmd->request_bufflen < 1)) { - printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", - dev->ap->id, dev->devno); + ata_dev_printk(dev, KERN_WARNING, + "WARNING: zero len r/w req\n"); goto err_did; } @@ -2200,8 +2200,9 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) if (!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) { if (unlikely(dev->class == ATA_DEV_ATAPI)) { - printk(KERN_WARNING "ata%u(%u): WARNING: ATAPI is %s, device ignored.\n", - ap->id, dev->devno, atapi_enabled ? "not supported with this driver" : "disabled"); + ata_dev_printk(dev, KERN_WARNING, + "WARNING: ATAPI is %s, device ignored.\n", + atapi_enabled ? "not supported with this driver" : "disabled"); return NULL; } } diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 748569b..e8d00f0 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -680,7 +680,7 @@ static void mv_stop_dma(struct ata_port *ap) } if (EDMA_EN & reg) { - printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id); + ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n"); /* FIXME: Consider doing a reset here to recover */ } } @@ -1964,8 +1964,8 @@ comreset_retry: ata_port_probe(ap); } else { sata_scr_read(ap, SCR_STATUS, &sstatus); - printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n", - ap->id, sstatus); + ata_port_printk(ap, KERN_INFO, + "no device found (phy stat %08x)\n", sstatus); ata_port_disable(ap); return; } @@ -2023,7 +2023,7 @@ static void mv_eng_timeout(struct ata_port *ap) { struct ata_queued_cmd *qc; - printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id); + ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n"); DPRINTK("All regs @ start of eng_timeout\n"); mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, to_pci_dev(ap->host_set->dev)); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index ddbc0c6..e9d61bc 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -435,7 +435,7 @@ static void pdc_eng_timeout(struct ata_port *ap) switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: - printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_port_printk(ap, KERN_ERR, "command timeout\n"); drv_stat = ata_wait_idle(ap); qc->err_mask |= __ac_err_mask(drv_stat); break; @@ -443,8 +443,9 @@ static void pdc_eng_timeout(struct ata_port *ap) default: drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); + ata_port_printk(ap, KERN_ERR, + "unknown timeout, cmd 0x%x stat 0x%x\n", + qc->tf.command, drv_stat); qc->err_mask |= ac_err_mask(drv_stat); break; diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index c933357..bfcece1 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -360,16 +360,16 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) if (slow_down || ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE))) { - printk(KERN_INFO "ata%u(%u): applying Seagate errata fix (mod15write workaround)\n", - ap->id, dev->devno); + ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix " + "(mod15write workaround)\n"); dev->max_sectors = 15; return; } /* limit to udma5 */ if (quirks & SIL_QUIRK_UDMA5MAX) { - printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n", - ap->id, dev->devno, model_num); + ata_dev_printk(dev, KERN_INFO, + "applying Maxtor errata fix %s\n", model_num); dev->udma_mask &= ATA_UDMA5; return; } diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index bedc787..ff96724 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -516,7 +516,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) return 0; err: - printk(KERN_ERR "ata%u: softreset failed (%s)\n", ap->id, reason); + ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); return -EIO; } @@ -561,7 +561,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) return 0; err: - printk(KERN_ERR "ata%u: hardreset failed (%s)\n", ap->id, reason); + ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } @@ -721,7 +721,7 @@ static void sil24_eng_timeout(struct ata_port *ap) qc = ata_qc_from_tag(ap, ap->active_tag); - printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_port_printk(ap, KERN_ERR, "command timeout\n"); qc->err_mask |= AC_ERR_TIMEOUT; ata_eh_qc_complete(qc); diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index a669d05..96d7b73 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -868,15 +868,16 @@ static void pdc_eng_timeout(struct ata_port *ap) switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: - printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_port_printk(ap, KERN_ERR, "command timeout\n"); qc->err_mask |= __ac_err_mask(ata_wait_idle(ap)); break; default: drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); + ata_port_printk(ap, KERN_ERR, + "unknown timeout, cmd 0x%x stat 0x%x\n", + qc->tf.command, drv_stat); qc->err_mask |= ac_err_mask(drv_stat); break; -- cgit v0.10.2 From 9ec957f2002bd2994be659bbc0ec28397fa251ee Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:58 +0900 Subject: [PATCH] libata-eh-fw: add flags and operations for new EH Add ATA_FLAG_EH_{PENDING|FROZEN}, ATA_ATA_QCFLAG_{FAILED|SENSE_VALID} and ops->freeze, thaw, error_handler, post_internal_cmd() for new EH. Signed-off-by: Tejun Heo diff --git a/include/linux/libata.h b/include/linux/libata.h index 91e10e6..e5d6d7f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -146,13 +146,16 @@ enum { 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_NOINTR = (1 << 16), /* FIXME: Remove this once + ATA_FLAG_NOINTR = (1 << 13), /* FIXME: Remove this once * proper HSM is in place. */ - ATA_FLAG_DEBUGMSG = (1 << 17), - ATA_FLAG_FLUSH_PORT_TASK = (1 << 18), /* flush port task */ + ATA_FLAG_DEBUGMSG = (1 << 14), + ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* flush port task */ - ATA_FLAG_DISABLED = (1 << 19), /* port is disabled, ignore it */ - ATA_FLAG_SUSPENDED = (1 << 20), /* port is suspended */ + ATA_FLAG_EH_PENDING = (1 << 16), /* EH pending */ + ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ + + ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */ + ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */ /* bits 24:31 of ap->flags are reserved for LLDD specific flags */ @@ -164,7 +167,9 @@ enum { ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ - ATA_QCFLAG_EH_SCHEDULED = (1 << 16), /* EH scheduled */ + ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ @@ -463,7 +468,15 @@ struct ata_port_operations { void (*qc_prep) (struct ata_queued_cmd *qc); unsigned int (*qc_issue) (struct ata_queued_cmd *qc); - void (*eng_timeout) (struct ata_port *ap); + /* Error handlers. ->error_handler overrides ->eng_timeout and + * indicates that new-style EH is in place. + */ + void (*eng_timeout) (struct ata_port *ap); /* obsolete */ + + void (*freeze) (struct ata_port *ap); + void (*thaw) (struct ata_port *ap); + void (*error_handler) (struct ata_port *ap); + void (*post_internal_cmd) (struct ata_queued_cmd *qc); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); void (*irq_clear) (struct ata_port *); -- cgit v0.10.2 From dc2b3515868a254b3d653d77844bff93c5d4c095 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:00 +0900 Subject: [PATCH] libata-eh-fw: clear SError in ata_std_postreset() Clear SError in ata_std_postreset(). This is to clear SError bits which get set during reset. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9a97ebd..de2cd61 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2528,11 +2528,17 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) */ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) { + u32 serror; + DPRINTK("ENTER\n"); /* print link status */ sata_print_link_status(ap); + /* clear SError */ + if (sata_scr_read(ap, SCR_ERROR, &serror) == 0) + sata_scr_write(ap, SCR_ERROR, serror); + /* re-enable interrupts */ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ ata_irq_on(ap); -- cgit v0.10.2 From 2ab7db1ff1d64a2ba389d0692d532f42a15f1f72 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:02 +0900 Subject: [PATCH] libata-eh-fw: use special reserved tag and qc for internal commands New EH may issue internal commands to recover from error while failed qc's are still hanging around. To allow such usage, reserve tag ATA_MAX_QUEUE-1 for internal command. This also makes it easy to tell whether a qc is for internal command or not. ata_tag_internal() test implements this test. To avoid breaking existing drivers, ata_exec_internal() uses ATA_TAG_INTERNAL only for drivers which implement ->error_handler. For drivers using old EH, tag 0 is used. Note that this makes ata_tag_internal() test valid only when ->error_handler is implemented. This is okay as drivers on old EH should not and does not have any reason to use ata_tag_internal(). Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index de2cd61..966abb5 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -980,15 +980,39 @@ unsigned ata_exec_internal(struct ata_device *dev, struct ata_port *ap = dev->ap; u8 command = tf->command; struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; DECLARE_COMPLETION(wait); unsigned long flags; unsigned int err_mask; spin_lock_irqsave(&ap->host_set->lock, flags); - qc = ata_qc_new_init(dev); - BUG_ON(qc == NULL); + /* initialize internal qc */ + /* XXX: Tag 0 is used for drivers with legacy EH as some + * drivers choke if any other tag is given. This breaks + * ata_tag_internal() test for those drivers. Don't use new + * EH stuff without converting to it. + */ + if (ap->ops->error_handler) + tag = ATA_TAG_INTERNAL; + else + tag = 0; + + if (test_and_set_bit(tag, &ap->qactive)) + BUG(); + qc = ata_qc_from_tag(ap, tag); + + qc->tag = tag; + qc->scsicmd = NULL; + qc->ap = ap; + qc->dev = dev; + ata_qc_reinit(qc); + + preempted_tag = ap->active_tag; + ap->active_tag = ATA_TAG_POISON; + + /* prepare & issue qc */ qc->tf = *tf; if (cdb) memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); @@ -1035,6 +1059,7 @@ unsigned ata_exec_internal(struct ata_device *dev, err_mask = qc->err_mask; ata_qc_free(qc); + ap->active_tag = preempted_tag; /* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition @@ -4014,7 +4039,8 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *qc = NULL; unsigned int i; - for (i = 0; i < ATA_MAX_QUEUE; i++) + /* 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)) { qc = ata_qc_from_tag(ap, i); break; diff --git a/include/linux/libata.h b/include/linux/libata.h index e5d6d7f..5a403e4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -108,7 +108,9 @@ enum { LIBATA_MAX_PRD = ATA_MAX_PRD / 2, ATA_MAX_PORTS = 8, ATA_DEF_QUEUE = 1, - ATA_MAX_QUEUE = 1, + /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */ + ATA_MAX_QUEUE = 2, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, ATA_MAX_SECTORS = 200, /* FIXME */ ATA_MAX_BUS = 2, ATA_DEF_BUSY_WAIT = 10000, @@ -717,6 +719,11 @@ static inline unsigned int ata_tag_valid(unsigned int tag) return (tag < ATA_MAX_QUEUE) ? 1 : 0; } +static inline unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + static inline unsigned int ata_class_enabled(unsigned int class) { return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI; -- cgit v0.10.2 From f69499f42caf74194df678c9c293f2ee0fe90bc3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:03 +0900 Subject: [PATCH] libata-eh-fw: update ata_qc_from_tag() to enforce normal/EH qc ownership New EH framework has clear distinction about who owns a qc. Every qc starts owned by normal execution path - PIO, interrupt or whatever. When an exception condition occurs which affects the qc, the qc gets scheduled for EH. Note that some events (say, link lost and regained, command timeout) may schedule qc's which are not directly related but could have been affected for EH too. Scheduling for EH is atomic w.r.t. ap->host_set->lock and once schedule for EH, normal execution path is not allowed to access the qc in whatever way. (PIO synchronization acts a bit different and will be dealt with later) This patch make ata_qc_from_tag() check whether a qc is active and owned by normal path before returning it. If conditions don't match, NULL is returned and thus access to the qc is denied. __ata_qc_from_tag() is the original ata_qc_from_tag() and is used by libata core/EH layers to access inactive/failed qc's. This change is applied only if the associated LLDD implements new EH as indicated by non-NULL ->error_handler Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 966abb5..1c34c14 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1001,7 +1001,7 @@ unsigned ata_exec_internal(struct ata_device *dev, if (test_and_set_bit(tag, &ap->qactive)) BUG(); - qc = ata_qc_from_tag(ap, tag); + qc = __ata_qc_from_tag(ap, tag); qc->tag = tag; qc->scsicmd = NULL; @@ -4042,7 +4042,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) /* 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)) { - qc = ata_qc_from_tag(ap, i); + qc = __ata_qc_from_tag(ap, i); break; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 5a403e4..bfcefdc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -832,14 +832,29 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) qc->tf.ctl |= ATA_NIEN; } -static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap, - unsigned int tag) +static inline struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) { if (likely(ata_tag_valid(tag))) return &ap->qcmd[tag]; return NULL; } +static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (unlikely(!qc) || !ap->ops->error_handler) + return qc; + + if ((qc->flags & (ATA_QCFLAG_ACTIVE | + ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE) + return qc; + + return NULL; +} + static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) { memset(tf, 0, sizeof(*tf)); -- cgit v0.10.2 From f686bcb8078ac7505ec88818886c2c72639f4fc5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:05 +0900 Subject: [PATCH] libata-eh-fw: implement new EH scheduling via error completion There are several ways a qc can get schedule for EH in new EH. This patch implements one of them - completing a qc with ATA_QCFLAG_FAILED set or with non-zero qc->err_mask. ALL such qc's are examined by EH. New EH schedules a qc for EH from completion iff ->error_handler is implemented, qc is marked as failed or qc->err_mask is non-zero and the command is not an internal command (internal cmd is handled via ->post_internal_cmd). The EH scheduling itself is performed by asking SCSI midlayer to schedule EH for the specified scmd. For drivers implementing old-EH, nothing changes. As this change makes ata_qc_complete() rather large, it's not inlined anymore and __ata_qc_complete() is exported to other parts of libata for later use. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1c34c14..1f5c327 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4123,6 +4123,66 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) qc->complete_fn(qc); } +/** + * ata_qc_complete - Complete an active ATA command + * @qc: Command to complete + * @err_mask: ATA Status register contents + * + * Indicate to the mid and upper layers that an ATA + * command has completed, with either an ok or not-ok status. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + /* XXX: New EH and old EH use different mechanisms to + * synchronize EH with regular execution path. + * + * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED. + * Normal execution path is responsible for not accessing a + * failed qc. libata core enforces the rule by returning NULL + * from ata_qc_from_tag() for failed qcs. + * + * Old EH depends on ata_qc_complete() nullifying completion + * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does + * not synchronize with interrupt handler. Only PIO task is + * taken care of. + */ + if (ap->ops->error_handler) { + WARN_ON(ap->flags & ATA_FLAG_FROZEN); + + if (unlikely(qc->err_mask)) + qc->flags |= ATA_QCFLAG_FAILED; + + if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { + if (!ata_tag_internal(qc->tag)) { + /* always fill result TF for failed qc */ + ap->ops->tf_read(ap, &qc->result_tf); + ata_qc_schedule_eh(qc); + return; + } + } + + /* read result TF if requested */ + if (qc->flags & ATA_QCFLAG_RESULT_TF) + ap->ops->tf_read(ap, &qc->result_tf); + + __ata_qc_complete(qc); + } else { + if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) + return; + + /* read result TF if failed or requested */ + if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) + ap->ops->tf_read(ap, &qc->result_tf); + + __ata_qc_complete(qc); + } +} + static inline int ata_should_dma_map(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -5245,7 +5305,7 @@ EXPORT_SYMBOL_GPL(ata_device_add); 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); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_tf_load); EXPORT_SYMBOL_GPL(ata_tf_read); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 959a1cd..471846f 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -210,6 +210,33 @@ void ata_eng_timeout(struct ata_port *ap) DPRINTK("EXIT\n"); } +/** + * ata_qc_schedule_eh - schedule qc for error handling + * @qc: command to schedule error handling for + * + * Schedule error handling for @qc. EH will kick in as soon as + * other commands are drained. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_schedule_eh(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + WARN_ON(!ap->ops->error_handler); + + qc->flags |= ATA_QCFLAG_FAILED; + qc->ap->flags |= ATA_FLAG_EH_PENDING; + + /* The following will fail if timeout has already expired. + * ata_scsi_error() takes care of such scmds on EH entry. + * Note that ATA_QCFLAG_FAILED is unconditionally set after + * this function completes. + */ + scsi_req_abort_cmd(qc->scsicmd); +} + static void ata_eh_scsidone(struct scsi_cmnd *scmd) { /* nada */ diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index c9ff83b..52622b7 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -57,6 +57,7 @@ extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); +extern void __ata_qc_complete(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); @@ -101,5 +102,6 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); +extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index bfcefdc..6023f32 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -605,7 +605,7 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); -extern void __ata_qc_complete(struct ata_queued_cmd *qc); +extern void ata_qc_complete(struct ata_queued_cmd *qc); 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, @@ -883,31 +883,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) } /** - * ata_qc_complete - Complete an active ATA command - * @qc: Command to complete - * @err_mask: ATA Status register contents - * - * Indicate to the mid and upper layers that an ATA - * command has completed, with either an ok or not-ok status. - * - * LOCKING: - * spin_lock_irqsave(host_set lock) - */ -static inline void ata_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED)) - return; - - /* read result TF if failed or requested */ - if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) - ap->ops->tf_read(ap, &qc->result_tf); - - __ata_qc_complete(qc); -} - -/** * ata_irq_on - Enable interrupts on a port. * @ap: Port on which interrupts are enabled. * -- cgit v0.10.2 From 7b70fc039824bc7303e4007a5f758f832de56611 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:07 +0900 Subject: [PATCH] libata-eh-fw: implement ata_port_schedule_eh() and ata_port_abort() ata_port_schedule_eh() directly schedules EH for @ap without associated qc. Once EH scheduled, no further qc is allowed and EH kicks in as soon as all currently active qc's are drained. ata_port_abort() schedules all currently active commands for EH by qc_completing them with ATA_QCFLAG_FAILED set. If ata_port_abort() doesn't find any qc to abort, it directly schedule EH using ata_port_schedule_eh(). These two functions provide ways to invoke EH for conditions which aren't directly related to any specfic qc. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1f5c327..9c97783 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5383,5 +5383,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); EXPORT_SYMBOL_GPL(ata_eng_timeout); +EXPORT_SYMBOL_GPL(ata_port_schedule_eh); +EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 471846f..037a561 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -237,6 +237,60 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) scsi_req_abort_cmd(qc->scsicmd); } +/** + * ata_port_schedule_eh - schedule error handling without a qc + * @ap: ATA port to schedule EH for + * + * Schedule error handling for @ap. EH will kick in as soon as + * all commands are drained. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_port_schedule_eh(struct ata_port *ap) +{ + WARN_ON(!ap->ops->error_handler); + + ap->flags |= ATA_FLAG_EH_PENDING; + ata_schedule_scsi_eh(ap->host); + + DPRINTK("port EH scheduled\n"); +} + +/** + * ata_port_abort - abort all qc's on the port + * @ap: ATA port to abort qc's for + * + * Abort all active qc's of @ap and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_port_abort(struct ata_port *ap) +{ + int tag, nr_aborted = 0; + + WARN_ON(!ap->ops->error_handler); + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); + + if (qc) { + qc->flags |= ATA_QCFLAG_FAILED; + ata_qc_complete(qc); + nr_aborted++; + } + } + + if (!nr_aborted) + ata_port_schedule_eh(ap); + + return nr_aborted; +} + static void ata_eh_scsidone(struct scsi_cmnd *scmd) { /* nada */ diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index a9b4083..fd7064b 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2596,3 +2596,26 @@ void ata_scsi_scan_host(struct ata_port *ap) } } +/** + * ata_schedule_scsi_eh - schedule EH for SCSI host + * @shost: SCSI host to invoke error handling on. + * + * Schedule SCSI EH without scmd. This is a hack. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + **/ +void ata_schedule_scsi_eh(struct Scsi_Host *shost) +{ + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + + if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || + scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { + shost->host_eh_scheduled++; + scsi_eh_wakeup(shost); + } + + spin_unlock_irqrestore(shost->host_lock, flags); +} diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 52622b7..b76ad7d 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -98,6 +98,7 @@ extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); +extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); diff --git a/include/linux/libata.h b/include/linux/libata.h index 6023f32..086e146 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -662,6 +662,10 @@ extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_ * EH */ extern void ata_eng_timeout(struct ata_port *ap); + +extern void ata_port_schedule_eh(struct ata_port *ap); +extern int ata_port_abort(struct ata_port *ap); + extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); -- cgit v0.10.2 From e318049949b07152d851dbfebbd93e560af45ebe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:09 +0900 Subject: [PATCH] libata-eh-fw: implement freeze/thaw Freezing is performed atomic w.r.t. host_set->lock and once frozen LLDD is not allowed to access the port or any qc on it. Also, libata makes sure that no new qc gets issued to a frozen port. A frozen port is thawed after a reset operation completes successfully, so reset methods must do its job while the port is frozen. During initialization all ports get frozen before requesting IRQ, so reset methods are always invoked on a frozen port. Optional ->freeze and ->thaw operations notify LLDD that the port is being frozen and thawed, respectively. LLDD can disable/enable hardware interrupt in these callbacks if the controller's IRQ mask can be changed dynamically. If the controller doesn't allow such operation, LLDD can check for frozen state in the interrupt handler and ack/clear interrupts unconditionally while frozen. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9c97783..63857a9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -987,6 +987,12 @@ unsigned ata_exec_internal(struct ata_device *dev, spin_lock_irqsave(&ap->host_set->lock, flags); + /* no internal command while frozen */ + if (ap->flags & ATA_FLAG_FROZEN) { + spin_unlock_irqrestore(&ap->host_set->lock, flags); + return AC_ERR_SYSTEM; + } + /* initialize internal qc */ /* XXX: Tag 0 is used for drivers with legacy EH as some @@ -2565,8 +2571,11 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) sata_scr_write(ap, SCR_ERROR, serror); /* re-enable interrupts */ - if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ - ata_irq_on(ap); + if (!ap->ops->error_handler) { + /* FIXME: hack. create a hook instead */ + if (ap->ioaddr.ctl_addr) + ata_irq_on(ap); + } /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -2681,6 +2690,8 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, { int rc = -EINVAL; + ata_eh_freeze_port(ap); + if (probeinit) probeinit(ap); @@ -2725,6 +2736,9 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, if (rc == 0) { if (postreset) postreset(ap, classes); + + ata_eh_thaw_port(ap); + if (classes[0] == ATA_DEV_UNKNOWN) rc = -ENODEV; } @@ -4039,6 +4053,10 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *qc = NULL; unsigned int i; + /* no command while frozen */ + if (unlikely(ap->flags & ATA_FLAG_FROZEN)) + return NULL; + /* 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)) { @@ -4953,6 +4971,7 @@ int ata_device_add(const struct ata_probe_ent *ent) ata_chk_status(ap); host_set->ops->irq_clear(ap); + ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */ count++; } @@ -5385,5 +5404,8 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_resume); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_port_abort); +EXPORT_SYMBOL_GPL(ata_port_freeze); +EXPORT_SYMBOL_GPL(ata_eh_freeze_port); +EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 037a561..cb4e2b8 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -291,6 +291,109 @@ int ata_port_abort(struct ata_port *ap) return nr_aborted; } +/** + * __ata_port_freeze - freeze port + * @ap: ATA port to freeze + * + * This function is called when HSM violation or some other + * condition disrupts normal operation of the port. Frozen port + * is not allowed to perform any operation until the port is + * thawed, which usually follows a successful reset. + * + * ap->ops->freeze() callback can be used for freezing the port + * hardware-wise (e.g. mask interrupt and stop DMA engine). If a + * port cannot be frozen hardware-wise, the interrupt handler + * must ack and clear interrupts unconditionally while the port + * is frozen. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +static void __ata_port_freeze(struct ata_port *ap) +{ + WARN_ON(!ap->ops->error_handler); + + if (ap->ops->freeze) + ap->ops->freeze(ap); + + ap->flags |= ATA_FLAG_FROZEN; + + DPRINTK("ata%u port frozen\n", ap->id); +} + +/** + * ata_port_freeze - abort & freeze port + * @ap: ATA port to freeze + * + * Abort and freeze @ap. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted commands. + */ +int ata_port_freeze(struct ata_port *ap) +{ + int nr_aborted; + + WARN_ON(!ap->ops->error_handler); + + nr_aborted = ata_port_abort(ap); + __ata_port_freeze(ap); + + return nr_aborted; +} + +/** + * ata_eh_freeze_port - EH helper to freeze port + * @ap: ATA port to freeze + * + * Freeze @ap. + * + * LOCKING: + * None. + */ +void ata_eh_freeze_port(struct ata_port *ap) +{ + unsigned long flags; + + if (!ap->ops->error_handler) + return; + + spin_lock_irqsave(&ap->host_set->lock, flags); + __ata_port_freeze(ap); + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +/** + * ata_port_thaw_port - EH helper to thaw port + * @ap: ATA port to thaw + * + * Thaw frozen port @ap. + * + * LOCKING: + * None. + */ +void ata_eh_thaw_port(struct ata_port *ap) +{ + unsigned long flags; + + if (!ap->ops->error_handler) + return; + + spin_lock_irqsave(&ap->host_set->lock, flags); + + ap->flags &= ~ATA_FLAG_FROZEN; + + if (ap->ops->thaw) + ap->ops->thaw(ap); + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + DPRINTK("ata%u port thawed\n", ap->id); +} + static void ata_eh_scsidone(struct scsi_cmnd *scmd) { /* nada */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 086e146..6758b4d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -665,6 +665,10 @@ extern void ata_eng_timeout(struct ata_port *ap); extern void ata_port_schedule_eh(struct ata_port *ap); extern int ata_port_abort(struct ata_port *ap); +extern int ata_port_freeze(struct ata_port *ap); + +extern void ata_eh_freeze_port(struct ata_port *ap); +extern void ata_eh_thaw_port(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); -- cgit v0.10.2 From dafadcde8d4dc5ea8c742faa7ff4403336b542b8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:11 +0900 Subject: [PATCH] libata-eh-fw: implement new EH scheduling from PIO PIO executes without holding host_set lock, so it cannot be synchronized using the same mechanism as interrupt driven execution. port_task framework makes sure that EH is not entered until PIO task is flushed, so PIO task can be sure the qc in progress won't go away underneath it. One thing it cannot be sure of is whether the qc has already been scheduled for EH by another exception condition while host_set lock was released. This patch makes ata_poll_qc-complete() handle such conditions properly and make it freeze the port if HSM violation is detected during PIO execution. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 63857a9..35ae5b4 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3430,16 +3430,31 @@ skip_map: * LOCKING: * None. (grabs host lock) */ - void ata_poll_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned long flags; spin_lock_irqsave(&ap->host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; - ata_irq_on(ap); - ata_qc_complete(qc); + + if (ap->ops->error_handler) { + /* EH might have kicked in while host_set lock is released */ + qc = ata_qc_from_tag(ap, qc->tag); + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ap->flags &= ~ATA_FLAG_NOINTR; + ata_irq_on(ap); + ata_qc_complete(qc); + } else + ata_port_freeze(ap); + } + } else { + /* old EH */ + ap->flags &= ~ATA_FLAG_NOINTR; + ata_irq_on(ap); + ata_qc_complete(qc); + } + spin_unlock_irqrestore(&ap->host_set->lock, flags); } -- cgit v0.10.2 From ad9e27624479bd167dd7eac0cea4bb3ad13bc926 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:12 +0900 Subject: [PATCH] libata-eh-fw: update ata_scsi_error() for new EH Update ata_scsi_error() for new EH. ata_scsi_error() is responsible for claiming timed out qcs and invoking ->error_handler in safe and synchronized manner. As the state of the controller is unknown if a qc has timed out, the port is frozen in such cases. Note that ata_scsi_timed_out() isn't used for new EH. This is because a timed out qc cannot be claimed by EH without freezing the port and freezing the port in ata_scsi_timed_out() results in unnecessary abortion of other active qcs. ata_scsi_timed_out() can be removed once all drivers are converted to new EH. While at it, add 'TODO: kill' comments to old EH functions. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index cb4e2b8..0803231 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -44,6 +44,8 @@ #include "libata.h" +static void __ata_port_freeze(struct ata_port *ap); + /** * ata_scsi_timed_out - SCSI layer time out callback * @cmd: timed out SCSI command @@ -55,6 +57,8 @@ * from finishing it by setting EH_SCHEDULED and return * EH_NOT_HANDLED. * + * TODO: kill this function once old EH is gone. + * * LOCKING: * Called from timer context * @@ -67,10 +71,16 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) struct ata_port *ap = ata_shost_to_port(host); unsigned long flags; struct ata_queued_cmd *qc; - enum scsi_eh_timer_return ret = EH_HANDLED; + enum scsi_eh_timer_return ret; DPRINTK("ENTER\n"); + if (ap->ops->error_handler) { + ret = EH_NOT_HANDLED; + goto out; + } + + ret = EH_HANDLED; spin_lock_irqsave(&ap->host_set->lock, flags); qc = ata_qc_from_tag(ap, ap->active_tag); if (qc) { @@ -81,6 +91,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) } spin_unlock_irqrestore(&ap->host_set->lock, flags); + out: DPRINTK("EXIT, ret=%d\n", ret); return ret; } @@ -100,21 +111,132 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); + spinlock_t *hs_lock = &ap->host_set->lock; + int i, repeat_cnt = ATA_EH_MAX_REPEAT; + unsigned long flags; DPRINTK("ENTER\n"); - /* synchronize with IRQ handler and port task */ - spin_unlock_wait(&ap->host_set->lock); + /* synchronize with port task */ ata_port_flush_task(ap); - WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + /* synchronize with host_set lock and sort out timeouts */ + + /* For new EH, all qcs are finished in one of three ways - + * normal completion, error completion, and SCSI timeout. + * Both cmpletions can race against SCSI timeout. When normal + * completion wins, the qc never reaches EH. When error + * completion wins, the qc has ATA_QCFLAG_FAILED set. + * + * When SCSI timeout wins, things are a bit more complex. + * Normal or error completion can occur after the timeout but + * before this point. In such cases, both types of + * completions are honored. A scmd is determined to have + * timed out iff its associated qc is active and not failed. + */ + if (ap->ops->error_handler) { + struct scsi_cmnd *scmd, *tmp; + int nr_timedout = 0; + + spin_lock_irqsave(hs_lock, flags); + + list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { + struct ata_queued_cmd *qc; + + for (i = 0; i < ATA_MAX_QUEUE; i++) { + qc = __ata_qc_from_tag(ap, i); + if (qc->flags & ATA_QCFLAG_ACTIVE && + qc->scsicmd == scmd) + break; + } + + if (i < ATA_MAX_QUEUE) { + /* the scmd has an associated qc */ + if (!(qc->flags & ATA_QCFLAG_FAILED)) { + /* which hasn't failed yet, timeout */ + qc->err_mask |= AC_ERR_TIMEOUT; + qc->flags |= ATA_QCFLAG_FAILED; + nr_timedout++; + } + } else { + /* Normal completion occurred after + * SCSI timeout but before this point. + * Successfully complete it. + */ + scmd->retries = scmd->allowed; + scsi_eh_finish_cmd(scmd, &ap->eh_done_q); + } + } + + /* If we have timed out qcs. They belong to EH from + * this point but the state of the controller is + * unknown. Freeze the port to make sure the IRQ + * handler doesn't diddle with those qcs. This must + * be done atomically w.r.t. setting QCFLAG_FAILED. + */ + if (nr_timedout) + __ata_port_freeze(ap); + + spin_unlock_irqrestore(hs_lock, flags); + } else + spin_unlock_wait(hs_lock); + + repeat: + /* invoke error handler */ + if (ap->ops->error_handler) { + /* clear EH pending */ + spin_lock_irqsave(hs_lock, flags); + ap->flags &= ~ATA_FLAG_EH_PENDING; + spin_unlock_irqrestore(hs_lock, flags); + + /* invoke EH */ + ap->ops->error_handler(ap); + + /* Exception might have happend after ->error_handler + * recovered the port but before this point. Repeat + * EH in such case. + */ + spin_lock_irqsave(hs_lock, flags); + + if (ap->flags & ATA_FLAG_EH_PENDING) { + if (--repeat_cnt) { + ata_port_printk(ap, KERN_INFO, + "EH pending after completion, " + "repeating EH (cnt=%d)\n", repeat_cnt); + spin_unlock_irqrestore(hs_lock, flags); + goto repeat; + } + ata_port_printk(ap, KERN_ERR, "EH pending after %d " + "tries, giving up\n", ATA_EH_MAX_REPEAT); + } - ap->ops->eng_timeout(ap); + /* Clear host_eh_scheduled while holding hs_lock such + * that if exception occurs after this point but + * before EH completion, SCSI midlayer will + * re-initiate EH. + */ + host->host_eh_scheduled = 0; + + spin_unlock_irqrestore(hs_lock, flags); + } else { + WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + ap->ops->eng_timeout(ap); + } + /* finish or retry handled scmd's and clean up */ WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q)); scsi_eh_flush_done_q(&ap->eh_done_q); + /* clean up */ + spin_lock_irqsave(hs_lock, flags); + + if (ap->flags & ATA_FLAG_RECOVERED) + ata_port_printk(ap, KERN_INFO, "EH complete\n"); + ap->flags &= ~ATA_FLAG_RECOVERED; + + spin_unlock_irqrestore(hs_lock, flags); + DPRINTK("EXIT\n"); } @@ -133,6 +255,8 @@ void ata_scsi_error(struct Scsi_Host *host) * an interrupt was not delivered to the driver, even though the * transaction completed successfully. * + * TODO: kill this function once old EH is gone. + * * LOCKING: * Inherited from SCSI layer (none, can sleep) */ @@ -198,6 +322,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) * an interrupt was not delivered to the driver, even though the * transaction completed successfully. * + * TODO: kill this function once old EH is gone. + * * LOCKING: * Inherited from SCSI layer (none, can sleep) */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 6758b4d..5ad5016 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -225,6 +225,9 @@ enum { ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + /* max repeat if error condition is still set after ->error_handler */ + ATA_EH_MAX_REPEAT = 5, + /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, }; -- cgit v0.10.2 From d95a717f579e81061830a308125c89f5858f740a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:14 +0900 Subject: [PATCH] libata-eh-fw: update ata_exec_internal() for new EH Update ata_exec_internal() such that it uses new EH framework. ->post_internal_cmd() is always invoked regardless of completion status. Also, when ata_exec_internal() detects a timeout condition and new EH is in place, it freezes the port as timeout for normal commands would do. Note that ata_port_flush_task() is called regardless of wait_for_completion status. This is necessary as exceptions unrelated to the qc can abort the qc, in which case PIO task could still be running after the wait for completion returns. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 35ae5b4..4def48e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -984,6 +984,7 @@ unsigned ata_exec_internal(struct ata_device *dev, DECLARE_COMPLETION(wait); unsigned long flags; unsigned int err_mask; + int rc; spin_lock_irqsave(&ap->host_set->lock, flags); @@ -1036,20 +1037,25 @@ unsigned ata_exec_internal(struct ata_device *dev, spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (!wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL)) { - ata_port_flush_task(ap); + rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL); + + ata_port_flush_task(ap); + if (!rc) { spin_lock_irqsave(&ap->host_set->lock, flags); /* We're racing with irq here. If we lose, the * following test prevents us from completing the qc - * again. If completion irq occurs after here but - * before the caller cleans up, it will result in a - * spurious interrupt. We can live with that. + * twice. If we win, the port is frozen and will be + * cleaned up by ->post_internal_cmd(). */ if (qc->flags & ATA_QCFLAG_ACTIVE) { - qc->err_mask = AC_ERR_TIMEOUT; - ata_qc_complete(qc); + qc->err_mask |= AC_ERR_TIMEOUT; + + if (ap->ops->error_handler) + ata_port_freeze(ap); + else + ata_qc_complete(qc); ata_dev_printk(dev, KERN_WARNING, "qc timeout (cmd 0x%x)\n", command); @@ -1058,6 +1064,16 @@ unsigned ata_exec_internal(struct ata_device *dev, spin_unlock_irqrestore(&ap->host_set->lock, flags); } + /* do post_internal_cmd */ + if (ap->ops->post_internal_cmd) + ap->ops->post_internal_cmd(qc); + + if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) { + ata_dev_printk(dev, KERN_WARNING, "zero err_mask for failed " + "internal command, assuming AC_ERR_OTHER\n"); + qc->err_mask |= AC_ERR_OTHER; + } + /* finish up */ spin_lock_irqsave(&ap->host_set->lock, flags); -- cgit v0.10.2 From 246619da308c6910a3ae30e7e5fbf46139619efe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:16 +0900 Subject: [PATCH] libata-eh-fw: update SCSI command completion path for new EH SCSI command completion path used to do some part of EH including printing messages and obtaining sense data. With new EH, all these are responsibilities of the EH, update SCSI command completion path to reflect this. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index fd7064b..e61cc357 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -415,6 +415,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) * @sk: the sense key we'll fill out * @asc: the additional sense code we'll fill out * @ascq: the additional sense code qualifier we'll fill out + * @verbose: be verbose * * Converts an ATA error into a SCSI error. Fill out pointers to * SK, ASC, and ASCQ bytes for later use in fixed or descriptor @@ -424,7 +425,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) * spin_lock_irqsave(host_set lock) */ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, - u8 *ascq) + u8 *ascq, int verbose) { int i; @@ -489,8 +490,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, } } /* No immediate match */ - printk(KERN_WARNING "ata%u: no sense translation for " - "error 0x%02x\n", id, drv_err); + if (verbose) + printk(KERN_WARNING "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); } /* Fall back to interpreting status bits */ @@ -503,8 +505,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, } } /* No error? Undecoded? */ - printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", - id, drv_stat); + if (verbose) + printk(KERN_WARNING "ata%u: no sense translation for " + "status: 0x%02x\n", id, drv_stat); /* We need a sensible error return here, which is tricky, and one that won't cause people to do things like return a disk wrongly */ @@ -513,9 +516,10 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, *ascq = 0x00; translate_done: - printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " - "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, - *sk, *asc, *ascq); + if (verbose) + printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x " + "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", + id, drv_stat, drv_err, *sk, *asc, *ascq); return; } @@ -538,6 +542,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; unsigned char *desc = sb + 8; + int verbose = qc->ap->ops->error_handler == NULL; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); @@ -550,7 +555,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) if (qc->err_mask || tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->id, tf->command, tf->feature, - &sb[1], &sb[2], &sb[3]); + &sb[1], &sb[2], &sb[3], verbose); sb[1] &= 0x0f; } @@ -608,6 +613,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc) struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; + int verbose = qc->ap->ops->error_handler == NULL; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); @@ -620,7 +626,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc) if (qc->err_mask || tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->id, tf->command, tf->feature, - &sb[2], &sb[12], &sb[13]); + &sb[2], &sb[12], &sb[13], verbose); sb[2] &= 0x0f; } @@ -1212,7 +1218,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } } - if (need_sense) + if (need_sense && !qc->ap->ops->error_handler) ata_dump_status(qc->ap->id, &qc->result_tf); qc->scsidone(cmd); @@ -2060,6 +2066,26 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) VPRINTK("ENTER, err_mask 0x%X\n", err_mask); + /* handle completion from new EH */ + if (unlikely(qc->ap->ops->error_handler && + (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) { + + if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) { + /* FIXME: not quite right; we don't want the + * translation of taskfile registers into a + * sense descriptors, since that's only + * correct for ATA, not ATAPI + */ + ata_gen_ata_desc_sense(qc); + } + + qc->scsicmd->result = SAM_STAT_CHECK_CONDITION; + qc->scsidone(cmd); + ata_qc_free(qc); + return; + } + + /* successful completion or old EH failure path */ if (unlikely(err_mask & AC_ERR_DEV)) { cmd->result = SAM_STAT_CHECK_CONDITION; atapi_request_sense(qc); -- cgit v0.10.2 From 9be1e979f2e1e57a091a658fa88dac266f9fd6fe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:17 +0900 Subject: [PATCH] libata-eh: add ATA and libata flags for new EH Add ATA and libata flags to be used by new EH. Signed-off-by: Tejun Heo diff --git a/include/linux/ata.h b/include/linux/ata.h index 312a2c0..a7c41f3 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -97,6 +97,9 @@ enum { ATA_DRQ = (1 << 3), /* data request i/o */ ATA_ERR = (1 << 0), /* have an error */ ATA_SRST = (1 << 2), /* software reset */ + ATA_ICRC = (1 << 7), /* interface CRC error */ + ATA_UNC = (1 << 6), /* uncorrectable media error */ + ATA_IDNF = (1 << 4), /* ID not found */ ATA_ABORTED = (1 << 2), /* command aborted */ /* ATA command block registers */ @@ -192,6 +195,16 @@ enum { SCR_ACTIVE = 3, SCR_NOTIFICATION = 4, + /* SError bits */ + SERR_DATA_RECOVERED = (1 << 0), /* recovered data error */ + SERR_COMM_RECOVERED = (1 << 1), /* recovered comm failure */ + SERR_DATA = (1 << 8), /* unrecovered data error */ + SERR_PERSISTENT = (1 << 9), /* persistent data/comm error */ + SERR_PROTOCOL = (1 << 10), /* protocol violation */ + SERR_INTERNAL = (1 << 11), /* host internal error */ + SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */ + SERR_DEV_XCHG = (1 << 26), /* device exchanged */ + /* struct ata_taskfile flags */ ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */ ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 5ad5016..6fe5ed8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -155,6 +155,7 @@ enum { ATA_FLAG_EH_PENDING = (1 << 16), /* EH pending */ ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ + ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */ ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */ @@ -225,6 +226,13 @@ enum { ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + /* reset / recovery action types */ + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + /* max repeat if error condition is still set after ->error_handler */ ATA_EH_MAX_REPEAT = 5, -- cgit v0.10.2 From 0c247c559cd70f85ba9f0764ce13ae00e20fcad8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:19 +0900 Subject: [PATCH] libata-eh: implement dev->ering This patch implements ata_ering and uses it to define dev->ering. ata_ering is a ring buffer which records libata errors - whether a command was for normar IO request, err_mask and timestamp. Errors are recorded per-device in dev->ering. This will be used by EH to determine recovery actions. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 0803231..71ad18b 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -46,6 +46,51 @@ static void __ata_port_freeze(struct ata_port *ap); +static void ata_ering_record(struct ata_ering *ering, int is_io, + unsigned int err_mask) +{ + struct ata_ering_entry *ent; + + WARN_ON(!err_mask); + + ering->cursor++; + ering->cursor %= ATA_ERING_SIZE; + + ent = &ering->ring[ering->cursor]; + ent->is_io = is_io; + ent->err_mask = err_mask; + ent->timestamp = get_jiffies_64(); +} + +static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering) +{ + struct ata_ering_entry *ent = &ering->ring[ering->cursor]; + if (!ent->err_mask) + return NULL; + return ent; +} + +static int ata_ering_map(struct ata_ering *ering, + int (*map_fn)(struct ata_ering_entry *, void *), + void *arg) +{ + int idx, rc = 0; + struct ata_ering_entry *ent; + + idx = ering->cursor; + do { + ent = &ering->ring[idx]; + if (!ent->err_mask) + break; + rc = map_fn(ent, arg); + if (rc) + break; + idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE; + } while (idx != ering->cursor); + + return rc; +} + /** * ata_scsi_timed_out - SCSI layer time out callback * @cmd: timed out SCSI command diff --git a/include/linux/libata.h b/include/linux/libata.h index 6fe5ed8..f5cea13 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -226,6 +226,9 @@ enum { ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + /* ering size */ + ATA_ERING_SIZE = 32, + /* reset / recovery action types */ ATA_EH_REVALIDATE = (1 << 0), ATA_EH_SOFTRESET = (1 << 1), @@ -375,6 +378,17 @@ struct ata_host_stats { unsigned long rw_reqbuf; }; +struct ata_ering_entry { + int is_io; + unsigned int err_mask; + u64 timestamp; +}; + +struct ata_ering { + int cursor; + struct ata_ering_entry ring[ATA_ERING_SIZE]; +}; + struct ata_device { struct ata_port *ap; u64 n_sectors; /* size of device, if ATA */ @@ -401,6 +415,9 @@ struct ata_device { u16 cylinders; /* Number of cylinders */ u16 heads; /* Number of heads */ u16 sectors; /* Number of sectors per track */ + + /* error history */ + struct ata_ering ering; }; struct ata_port { -- cgit v0.10.2 From f3e81b19aac23c0e8c55d5961324ef7de44c23bb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:21 +0900 Subject: [PATCH] libata-eh: implement ata_eh_info and ata_eh_context struct ata_eh_info serves as the communication channel between execution path and EH. Execution path describes detected error condition in ap->eh_info and EH recovers the port using it. To avoid missing error conditions detected during EH, EH makes its own copy of eh_info and clears it on entry allowing error info to accumulate during EH. Most EH states including EH's copy of eh_info are stored in ap->eh_context (struct ata_eh_context) which is owned by EH and thus doesn't require any synchronization to access and alter. This standardized context makes it easy to integrate various parts of EH and extend EH to handle multiple links (for PM). Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 71ad18b..1968f2d 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -229,9 +229,15 @@ void ata_scsi_error(struct Scsi_Host *host) repeat: /* invoke error handler */ if (ap->ops->error_handler) { - /* clear EH pending */ + /* fetch & clear EH info */ spin_lock_irqsave(hs_lock, flags); + + memset(&ap->eh_context, 0, sizeof(ap->eh_context)); + ap->eh_context.i = ap->eh_info; + memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + ap->flags &= ~ATA_FLAG_EH_PENDING; + spin_unlock_irqrestore(hs_lock, flags); /* invoke EH */ @@ -255,6 +261,9 @@ void ata_scsi_error(struct Scsi_Host *host) "tries, giving up\n", ATA_EH_MAX_REPEAT); } + /* this run is complete, make sure EH info is clear */ + memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + /* Clear host_eh_scheduled while holding hs_lock such * that if exception occurs after this point but * before EH completion, SCSI midlayer will diff --git a/include/linux/libata.h b/include/linux/libata.h index f5cea13..298f991 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -229,6 +229,9 @@ enum { /* ering size */ ATA_ERING_SIZE = 32, + /* desc_len for ata_eh_info and context */ + ATA_EH_DESC_LEN = 80, + /* reset / recovery action types */ ATA_EH_REVALIDATE = (1 << 0), ATA_EH_SOFTRESET = (1 << 1), @@ -236,6 +239,9 @@ enum { ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + /* ata_eh_info->flags */ + ATA_EHI_DID_RESET = (1 << 0), /* already reset this port */ + /* max repeat if error condition is still set after ->error_handler */ ATA_EH_MAX_REPEAT = 5, @@ -420,6 +426,21 @@ struct ata_device { struct ata_ering ering; }; +struct ata_eh_info { + struct ata_device *dev; /* offending device */ + u32 serror; /* SError from LLDD */ + unsigned int err_mask; /* port-wide err_mask */ + unsigned int action; /* ATA_EH_* action mask */ + unsigned int flags; /* ATA_EHI_* flags */ + char desc[ATA_EH_DESC_LEN]; + int desc_len; +}; + +struct ata_eh_context { + struct ata_eh_info i; + int tries[ATA_MAX_DEVICES]; +}; + struct ata_port { struct Scsi_Host *host; /* our co-allocated scsi host */ const struct ata_port_operations *ops; @@ -444,6 +465,11 @@ struct ata_port { unsigned int cbl; /* cable type; ATA_CBL_xxx */ unsigned int sata_spd_limit; /* SATA PHY speed limit */ + /* record runtime error info, protected by host_set lock */ + struct ata_eh_info eh_info; + /* EH context owned by EH */ + struct ata_eh_context eh_context; + struct ata_device device[ATA_MAX_DEVICES]; struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; @@ -711,6 +737,20 @@ extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args) /* + * ata_eh_info helpers + */ +#define ata_ehi_push_desc(ehi, fmt, args...) do { \ + (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \ + ATA_EH_DESC_LEN - (ehi)->desc_len, \ + fmt , ##args); \ +} while (0) + +#define ata_ehi_clear_desc(ehi) do { \ + (ehi)->desc[0] = '\0'; \ + (ehi)->desc_len = 0; \ +} while (0) + +/* * qc helpers */ static inline int -- cgit v0.10.2 From 022bdb075b9e1f224088a0b268de56268d7bc5b6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:22 +0900 Subject: [PATCH] libata-eh: implement new EH Implement new EH. The exported interface is ata_do_eh() which is to be called from ->error_handler and performs the following steps to recover the failed port. ata_eh_autopsy() : analyze SError/TF, determine the cause of failure and required recovery actions and record it in ap->eh_context ata_eh_report() : report the failure to user ata_eh_recover() : perform recovery actions described in ap->eh_context ata_eh_finish() : finish failed qcs LLDDs can customize error handling by modifying eh_context before calling ata_do_eh() or, if necessary, doing so inbetween each major steps by calling each step explicitly. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 4def48e..ddc4709 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5440,3 +5440,4 @@ EXPORT_SYMBOL_GPL(ata_eh_freeze_port); EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); +EXPORT_SYMBOL_GPL(ata_do_eh); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1968f2d..cd133f8 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -626,3 +626,778 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) scmd->retries--; __ata_eh_qc_complete(qc); } + +/** + * ata_eh_about_to_do - about to perform eh_action + * @ap: target ATA port + * @action: action about to be performed + * + * Called just before performing EH actions to clear related bits + * in @ap->eh_info such that eh actions are not unnecessarily + * repeated. + * + * LOCKING: + * None. + */ +static void ata_eh_about_to_do(struct ata_port *ap, unsigned int action) +{ + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->eh_info.action &= ~action; + ap->flags |= ATA_FLAG_RECOVERED; + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +/** + * ata_err_string - convert err_mask to descriptive string + * @err_mask: error mask to convert to string + * + * Convert @err_mask to descriptive string. Errors are + * prioritized according to severity and only the most severe + * error is reported. + * + * LOCKING: + * None. + * + * RETURNS: + * Descriptive string for @err_mask + */ +static const char * ata_err_string(unsigned int err_mask) +{ + if (err_mask & AC_ERR_HOST_BUS) + return "host bus error"; + if (err_mask & AC_ERR_ATA_BUS) + return "ATA bus error"; + if (err_mask & AC_ERR_TIMEOUT) + return "timeout"; + if (err_mask & AC_ERR_HSM) + return "HSM violation"; + if (err_mask & AC_ERR_SYSTEM) + return "internal error"; + if (err_mask & AC_ERR_MEDIA) + return "media error"; + if (err_mask & AC_ERR_INVALID) + return "invalid argument"; + if (err_mask & AC_ERR_DEV) + return "device error"; + return "unknown error"; +} + +/** + * 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) + * + * Perform ATAPI REQUEST_SENSE after the device reported CHECK + * SENSE. This function is EH helper. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, AC_ERR_* mask on failure + */ +static unsigned int atapi_eh_request_sense(struct ata_device *dev, + unsigned char *sense_buf) +{ + struct ata_port *ap = dev->ap; + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + DPRINTK("ATAPI request sense\n"); + + ata_tf_init(dev, &tf); + + /* FIXME: is this needed? */ + memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); + + /* XXX: why tf_read here? */ + ap->ops->tf_read(ap, &tf); + + /* fill these in, for the case where they are -not- overwritten */ + sense_buf[0] = 0x70; + sense_buf[2] = tf.feature >> 4; + + memset(cdb, 0, ATAPI_CDB_LEN); + cdb[0] = REQUEST_SENSE; + cdb[4] = SCSI_SENSE_BUFFERSIZE; + + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.command = ATA_CMD_PACKET; + + /* is it pointless to prefer PIO for "safety reasons"? */ + if (ap->flags & ATA_FLAG_PIO_DMA) { + tf.protocol = ATA_PROT_ATAPI_DMA; + tf.feature |= ATAPI_PKT_DMA; + } else { + tf.protocol = ATA_PROT_ATAPI; + tf.lbam = (8 * 1024) & 0xff; + tf.lbah = (8 * 1024) >> 8; + } + + return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, + sense_buf, SCSI_SENSE_BUFFERSIZE); +} + +/** + * ata_eh_analyze_serror - analyze SError for a failed port + * @ap: ATA port to analyze SError for + * + * Analyze SError if available and further determine cause of + * failure. + * + * LOCKING: + * None. + */ +static void ata_eh_analyze_serror(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + u32 serror = ehc->i.serror; + unsigned int err_mask = 0, action = 0; + + if (serror & SERR_PERSISTENT) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_HARDRESET; + } + if (serror & + (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_SOFTRESET; + } + if (serror & SERR_PROTOCOL) { + err_mask |= AC_ERR_HSM; + action |= ATA_EH_SOFTRESET; + } + if (serror & SERR_INTERNAL) { + err_mask |= AC_ERR_SYSTEM; + action |= ATA_EH_SOFTRESET; + } + if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_HARDRESET; + } + + ehc->i.err_mask |= err_mask; + ehc->i.action |= action; +} + +/** + * ata_eh_analyze_tf - analyze taskfile of a failed qc + * @qc: qc to analyze + * @tf: Taskfile registers to analyze + * + * Analyze taskfile of @qc and further determine cause of + * failure. This function also requests ATAPI sense data if + * avaliable. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * Determined recovery action + */ +static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, + const struct ata_taskfile *tf) +{ + unsigned int tmp, action = 0; + u8 stat = tf->command, err = tf->feature; + + if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) { + qc->err_mask |= AC_ERR_HSM; + return ATA_EH_SOFTRESET; + } + + if (!(qc->err_mask & AC_ERR_DEV)) + return 0; + + switch (qc->dev->class) { + case ATA_DEV_ATA: + if (err & ATA_ICRC) + qc->err_mask |= AC_ERR_ATA_BUS; + if (err & ATA_UNC) + qc->err_mask |= AC_ERR_MEDIA; + if (err & ATA_IDNF) + qc->err_mask |= AC_ERR_INVALID; + break; + + case ATA_DEV_ATAPI: + tmp = atapi_eh_request_sense(qc->dev, + qc->scsicmd->sense_buffer); + if (!tmp) { + /* ATA_QCFLAG_SENSE_VALID is used to tell + * atapi_qc_complete() that sense data is + * already valid. + * + * TODO: interpret sense data and set + * appropriate err_mask. + */ + qc->flags |= ATA_QCFLAG_SENSE_VALID; + } else + qc->err_mask |= tmp; + } + + if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) + action |= ATA_EH_SOFTRESET; + + return action; +} + +static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent) +{ + if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT)) + return 1; + + if (ent->is_io) { + if (ent->err_mask & AC_ERR_HSM) + return 1; + if ((ent->err_mask & + (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) + return 2; + } + + return 0; +} + +struct speed_down_needed_arg { + u64 since; + int nr_errors[3]; +}; + +static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg) +{ + struct speed_down_needed_arg *arg = void_arg; + + if (ent->timestamp < arg->since) + return -1; + + arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++; + return 0; +} + +/** + * ata_eh_speed_down_needed - Determine wheter speed down is necessary + * @dev: Device of interest + * + * This function examines error ring of @dev and determines + * whether speed down is necessary. Speed down is necessary if + * there have been more than 3 of Cat-1 errors or 10 of Cat-2 + * errors during last 15 minutes. + * + * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM + * violation for known supported commands. + * + * Cat-2 errors are unclassified DEV error for known supported + * command. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * 1 if speed down is necessary, 0 otherwise + */ +static int ata_eh_speed_down_needed(struct ata_device *dev) +{ + const u64 interval = 15LLU * 60 * HZ; + static const int err_limits[3] = { -1, 3, 10 }; + struct speed_down_needed_arg arg; + struct ata_ering_entry *ent; + int err_cat; + u64 j64; + + ent = ata_ering_top(&dev->ering); + if (!ent) + return 0; + + err_cat = ata_eh_categorize_ering_entry(ent); + if (err_cat == 0) + return 0; + + memset(&arg, 0, sizeof(arg)); + + j64 = get_jiffies_64(); + if (j64 >= interval) + arg.since = j64 - interval; + else + arg.since = 0; + + ata_ering_map(&dev->ering, speed_down_needed_cb, &arg); + + return arg.nr_errors[err_cat] > err_limits[err_cat]; +} + +/** + * ata_eh_speed_down - record error and speed down if necessary + * @dev: Failed device + * @is_io: Did the device fail during normal IO? + * @err_mask: err_mask of the error + * + * Record error and examine error history to determine whether + * adjusting transmission speed is necessary. It also sets + * transmission limits appropriately if such adjustment is + * necessary. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise + */ +static int ata_eh_speed_down(struct ata_device *dev, int is_io, + unsigned int err_mask) +{ + if (!err_mask) + return 0; + + /* record error and determine whether speed down is necessary */ + ata_ering_record(&dev->ering, is_io, err_mask); + + if (!ata_eh_speed_down_needed(dev)) + return 0; + + /* speed down SATA link speed if possible */ + if (sata_down_spd_limit(dev->ap) == 0) + return ATA_EH_HARDRESET; + + /* lower transfer mode */ + if (ata_down_xfermask_limit(dev, 0) == 0) + return ATA_EH_SOFTRESET; + + ata_dev_printk(dev, KERN_ERR, + "speed down requested but no transfer mode left\n"); + return 0; +} + +/** + * ata_eh_autopsy - analyze error and determine recovery action + * @ap: ATA port to perform autopsy on + * + * Analyze why @ap failed and determine which recovery action is + * needed. This function also sets more detailed AC_ERR_* values + * and fills sense data for ATAPI CHECK SENSE. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_autopsy(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned int action = ehc->i.action; + struct ata_device *failed_dev = NULL; + unsigned int all_err_mask = 0; + int tag, is_io = 0; + u32 serror; + int rc; + + DPRINTK("ENTER\n"); + + /* obtain and analyze SError */ + rc = sata_scr_read(ap, SCR_ERROR, &serror); + if (rc == 0) { + ehc->i.serror |= serror; + ata_eh_analyze_serror(ap); + } else if (rc != -EOPNOTSUPP) + action |= ATA_EH_HARDRESET; + + /* any real error trumps AC_ERR_OTHER */ + if (ehc->i.err_mask & ~AC_ERR_OTHER) + ehc->i.err_mask &= ~AC_ERR_OTHER; + + all_err_mask |= ehc->i.err_mask; + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + + /* inherit upper level err_mask */ + qc->err_mask |= ehc->i.err_mask; + + if (qc->err_mask & AC_ERR_TIMEOUT) + action |= ATA_EH_SOFTRESET; + + /* analyze TF */ + action |= ata_eh_analyze_tf(qc, &qc->result_tf); + + /* DEV errors are probably spurious in case of ATA_BUS error */ + if (qc->err_mask & AC_ERR_ATA_BUS) + qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA | + AC_ERR_INVALID); + + /* any real error trumps unknown error */ + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + + /* SENSE_VALID trumps dev/unknown error and revalidation */ + if (qc->flags & ATA_QCFLAG_SENSE_VALID) { + qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); + action &= ~ATA_EH_REVALIDATE; + } + + /* accumulate error info */ + failed_dev = qc->dev; + all_err_mask |= qc->err_mask; + if (qc->flags & ATA_QCFLAG_IO) + is_io = 1; + } + + /* speed down iff command was in progress */ + if (failed_dev) + action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); + + if (all_err_mask) + action |= ATA_EH_REVALIDATE; + + ehc->i.dev = failed_dev; + ehc->i.action = action; + + DPRINTK("EXIT\n"); +} + +/** + * ata_eh_report - report error handling to user + * @ap: ATA port EH is going on + * + * Report EH to user. + * + * LOCKING: + * None. + */ +static void ata_eh_report(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + const char *frozen, *desc; + int tag, nr_failed = 0; + + desc = NULL; + if (ehc->i.desc[0] != '\0') + desc = ehc->i.desc; + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask) + continue; + + nr_failed++; + } + + if (!nr_failed && !ehc->i.err_mask) + return; + + frozen = ""; + if (ap->flags & ATA_FLAG_FROZEN) + 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); + 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); + if (desc) + ata_port_printk(ap, KERN_ERR, "(%s)\n", desc); + } + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) + continue; + + ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x " + "Emask 0x%x stat 0x%x err 0x%x (%s)\n", + qc->tag, qc->tf.command, qc->err_mask, + qc->result_tf.command, qc->result_tf.feature, + ata_err_string(qc->err_mask)); + } +} + +static int ata_eh_reset(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned int classes[ATA_MAX_DEVICES]; + int tries = ATA_EH_RESET_TRIES; + ata_reset_fn_t reset; + int rc; + + if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && + !(ehc->i.action & ATA_EH_HARDRESET)))) + reset = softreset; + else + reset = hardreset; + + retry: + ata_port_printk(ap, KERN_INFO, "%s resetting port\n", + reset == softreset ? "soft" : "hard"); + + /* reset */ + ata_eh_about_to_do(ap, ATA_EH_RESET_MASK); + ehc->i.flags |= ATA_EHI_DID_RESET; + + rc = ata_do_reset(ap, reset, classes); + + if (rc && --tries) { + ata_port_printk(ap, KERN_WARNING, + "%sreset failed, retrying in 5 secs\n", + reset == softreset ? "soft" : "hard"); + ssleep(5); + + if (reset == hardreset) + sata_down_spd_limit(ap); + if (hardreset) + reset = hardreset; + goto retry; + } + + if (rc == 0) { + if (postreset) + postreset(ap, classes); + + /* reset successful, schedule revalidation */ + ehc->i.dev = NULL; + ehc->i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action |= ATA_EH_REVALIDATE; + } + + return rc; +} + +static int ata_eh_revalidate(struct ata_port *ap, + struct ata_device **r_failed_dev) +{ + struct ata_eh_context *ehc = &ap->eh_context; + struct ata_device *dev; + int i, rc = 0; + + DPRINTK("ENTER\n"); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) && + (!ehc->i.dev || ehc->i.dev == dev)) { + if (ata_port_offline(ap)) { + rc = -EIO; + break; + } + + ata_eh_about_to_do(ap, ATA_EH_REVALIDATE); + rc = ata_dev_revalidate(dev, + ehc->i.flags & ATA_EHI_DID_RESET); + if (rc) + break; + + ehc->i.action &= ~ATA_EH_REVALIDATE; + } + } + + if (rc) + *r_failed_dev = dev; + + DPRINTK("EXIT\n"); + return rc; +} + +static int ata_port_nr_enabled(struct ata_port *ap) +{ + int i, cnt = 0; + + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ata_dev_enabled(&ap->device[i])) + cnt++; + return cnt; +} + +/** + * ata_eh_recover - recover host port after error + * @ap: host port to recover + * @softreset: softreset method (can be NULL) + * @hardreset: hardreset method (can be NULL) + * @postreset: postreset method (can be NULL) + * + * This is the alpha and omega, eum and yang, heart and soul of + * libata exception handling. On entry, actions required to + * recover each devices are recorded in eh_context. This + * function executes all the operations with appropriate retrials + * and fallbacks to resurrect failed devices. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset) +{ + struct ata_eh_context *ehc = &ap->eh_context; + struct ata_device *dev; + int down_xfermask, i, rc; + + DPRINTK("ENTER\n"); + + /* prep for recovery */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + } + + retry: + down_xfermask = 0; + rc = 0; + + /* skip EH if possible. */ + if (!ata_port_nr_enabled(ap) && !(ap->flags & ATA_FLAG_FROZEN)) + ehc->i.action = 0; + + /* reset */ + if (ehc->i.action & ATA_EH_RESET_MASK) { + ata_eh_freeze_port(ap); + + rc = ata_eh_reset(ap, softreset, hardreset, postreset); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "reset failed, giving up\n"); + goto out; + } + + ata_eh_thaw_port(ap); + } + + /* revalidate existing devices */ + rc = ata_eh_revalidate(ap, &dev); + if (rc) + goto dev_fail; + + /* configure transfer mode if the port has been reset */ + if (ehc->i.flags & ATA_EHI_DID_RESET) { + rc = ata_set_mode(ap, &dev); + if (rc) { + down_xfermask = 1; + goto dev_fail; + } + } + + goto out; + + dev_fail: + switch (rc) { + case -ENODEV: + case -EINVAL: + ehc->tries[dev->devno] = 0; + break; + case -EIO: + sata_down_spd_limit(ap); + default: + ehc->tries[dev->devno]--; + if (down_xfermask && + ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1)) + ehc->tries[dev->devno] = 0; + } + + /* disable device if it has used up all its chances */ + if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) + ata_dev_disable(dev); + + /* soft didn't work? be haaaaard */ + if (ehc->i.flags & ATA_EHI_DID_RESET) + ehc->i.action |= ATA_EH_HARDRESET; + else + ehc->i.action |= ATA_EH_SOFTRESET; + + if (ata_port_nr_enabled(ap)) { + ata_port_printk(ap, KERN_WARNING, "failed to recover some " + "devices, retrying in 5 secs\n"); + ssleep(5); + } else { + /* no device left, repeat fast */ + msleep(500); + } + + goto retry; + + out: + if (rc) { + for (i = 0; i < ATA_MAX_DEVICES; i++) + ata_dev_disable(&ap->device[i]); + } + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * ata_eh_finish - finish up EH + * @ap: host port to finish EH for + * + * Recovery is complete. Clean up EH states and retry or finish + * failed qcs. + * + * LOCKING: + * None. + */ +static void ata_eh_finish(struct ata_port *ap) +{ + int tag; + + /* retry or finish qcs */ + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + + if (qc->err_mask) { + /* FIXME: Once EH migration is complete, + * generate sense data in this function, + * considering both err_mask and tf. + */ + if (qc->err_mask & AC_ERR_INVALID) + ata_eh_qc_complete(qc); + else + ata_eh_qc_retry(qc); + } else { + if (qc->flags & ATA_QCFLAG_SENSE_VALID) { + ata_eh_qc_complete(qc); + } else { + /* feed zero TF to sense generation */ + memset(&qc->result_tf, 0, sizeof(qc->result_tf)); + ata_eh_qc_retry(qc); + } + } + } +} + +/** + * ata_do_eh - do standard error handling + * @ap: host port to handle error for + * @softreset: softreset method (can be NULL) + * @hardreset: hardreset method (can be NULL) + * @postreset: postreset method (can be NULL) + * + * Perform standard error handling sequence. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + ata_eh_autopsy(ap); + ata_eh_report(ap); + ata_eh_recover(ap, softreset, hardreset, postreset); + ata_eh_finish(ap); +} diff --git a/include/linux/libata.h b/include/linux/libata.h index 298f991..9fe4607 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -247,6 +247,8 @@ enum { /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, + ATA_EH_RESET_TRIES = 3, + ATA_EH_DEV_TRIES = 3, }; enum hsm_task_states { @@ -727,6 +729,9 @@ extern void ata_eh_thaw_port(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); +extern void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); + /* * printk helpers */ -- cgit v0.10.2 From 6d97dbd72da31a0e334f251fa9df4be9fab6fde2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:24 +0900 Subject: [PATCH] libata-eh: implement BMDMA EH Implement stock BMDMA error handling methods. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 835dff0..49eff18 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -652,6 +652,150 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) ata_altstatus(ap); /* dummy read */ } +/** + * ata_bmdma_freeze - Freeze BMDMA controller port + * @ap: port to freeze + * + * Freeze BMDMA controller port. + * + * LOCKING: + * Inherited from caller. + */ +void ata_bmdma_freeze(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); +} + +/** + * ata_bmdma_thaw - Thaw BMDMA controller port + * @ap: port to thaw + * + * Thaw BMDMA controller port. + * + * LOCKING: + * Inherited from caller. + */ +void ata_bmdma_thaw(struct ata_port *ap) +{ + /* clear & re-enable interrupts */ + ata_chk_status(ap); + ap->ops->irq_clear(ap); + if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ + ata_irq_on(ap); +} + +/** + * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller + * @ap: port to handle error for + * @softreset: softreset method (can be NULL) + * @hardreset: hardreset method (can be NULL) + * @postreset: postreset method (can be NULL) + * + * Handle error for ATA BMDMA controller. It can handle both + * PATA and SATA controllers. Many controllers should be able to + * use this EH as-is or with some added handling before and + * after. + * + * This function is intended to be used for constructing + * ->error_handler callback by low level drivers. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_host_set *host_set = ap->host_set; + struct ata_eh_context *ehc = &ap->eh_context; + struct ata_queued_cmd *qc; + unsigned long flags; + int thaw = 0; + + qc = __ata_qc_from_tag(ap, ap->active_tag); + if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) + qc = NULL; + + /* reset PIO HSM and stop DMA engine */ + spin_lock_irqsave(&host_set->lock, flags); + + ap->flags &= ~ATA_FLAG_NOINTR; + ap->hsm_task_state = HSM_ST_IDLE; + + if (qc && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { + u8 host_stat; + + host_stat = ata_bmdma_status(ap); + + ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); + + /* BMDMA controllers indicate host bus error by + * setting DMA_ERR bit and timing out. As it wasn't + * really a timeout event, adjust error mask and + * cancel frozen state. + */ + if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) { + qc->err_mask = AC_ERR_HOST_BUS; + thaw = 1; + } + + ap->ops->bmdma_stop(qc); + } + + ata_altstatus(ap); + ata_chk_status(ap); + ap->ops->irq_clear(ap); + + spin_unlock_irqrestore(&host_set->lock, flags); + + if (thaw) + ata_eh_thaw_port(ap); + + /* PIO and DMA engines have been stopped, perform recovery */ + ata_do_eh(ap, softreset, hardreset, postreset); +} + +/** + * ata_bmdma_error_handler - Stock error handler for BMDMA controller + * @ap: port to handle error for + * + * Stock error handler for BMDMA controller. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_bmdma_error_handler(struct ata_port *ap) +{ + ata_reset_fn_t hardreset; + + hardreset = NULL; + if (sata_scr_valid(ap)) + hardreset = sata_std_hardreset; + + ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset); +} + +/** + * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for + * BMDMA controller + * @qc: internal command to clean up + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) +{ + ata_bmdma_stop(qc); +} + #ifdef CONFIG_PCI static struct ata_probe_ent * ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ddc4709..2969599 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5377,6 +5377,11 @@ EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); +EXPORT_SYMBOL_GPL(ata_bmdma_freeze); +EXPORT_SYMBOL_GPL(ata_bmdma_thaw); +EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh); +EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); +EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_phy_reset); diff --git a/include/linux/libata.h b/include/linux/libata.h index 9fe4607..6ccacbf 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -661,6 +661,14 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); +extern void ata_bmdma_freeze(struct ata_port *ap); +extern void ata_bmdma_thaw(struct ata_port *ap); +extern void ata_bmdma_drive_eh(struct ata_port *ap, + ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset); +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 void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -- cgit v0.10.2 From 3f037db0ba043022e43e8e7266e698d4af264851 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:25 +0900 Subject: [PATCH] ata_piix: convert to new EH ata_piix can use stock BMDMA EH routines. Convert to new EH. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index af1d46e..e3184a7 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -243,7 +243,10 @@ static const struct ata_port_operations piix_pata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .eng_timeout = ata_eng_timeout, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -271,7 +274,10 @@ static const struct ata_port_operations piix_sata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .eng_timeout = ata_eng_timeout, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, -- cgit v0.10.2 From f6aae27ed002ba9c0a98aff811dbde32ce749d28 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:27 +0900 Subject: [PATCH] sata_sil: convert to new EH Convert sata_sil to new EH. As these controllers have hardware interrupt mask and are known to have screaming interrupts issues, use hardware IRQ masking for freezing. sil_freeze() masks interrupts for the port and sil_thaw() unmasks them. As ports are automatically frozen before probing reset, there is no need to initialize interrupt masks sil_init_onde(). Remove related code. Other than freezing, sata_sil uses stock BMDMA EH routines. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index bfcece1..aa63044 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -96,6 +96,8 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void sil_post_set_mode (struct ata_port *ap); +static void sil_freeze(struct ata_port *ap); +static void sil_thaw(struct ata_port *ap); static const struct pci_device_id sil_pci_tbl[] = { @@ -174,7 +176,10 @@ static const struct ata_port_operations sil_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .eng_timeout = ata_eng_timeout, + .freeze = sil_freeze, + .thaw = sil_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .scr_read = sil_scr_read, @@ -314,6 +319,33 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) writel(val, mmio); } +static void sil_freeze(struct ata_port *ap) +{ + void __iomem *mmio_base = ap->host_set->mmio_base; + u32 tmp; + + /* plug IRQ */ + tmp = readl(mmio_base + SIL_SYSCFG); + tmp |= SIL_MASK_IDE0_INT << ap->port_no; + writel(tmp, mmio_base + SIL_SYSCFG); + readl(mmio_base + SIL_SYSCFG); /* flush */ +} + +static void sil_thaw(struct ata_port *ap) +{ + void __iomem *mmio_base = ap->host_set->mmio_base; + u32 tmp; + + /* clear IRQ */ + ata_chk_status(ap); + ata_bmdma_irq_clear(ap); + + /* turn on IRQ */ + tmp = readl(mmio_base + SIL_SYSCFG); + tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no); + writel(tmp, mmio_base + SIL_SYSCFG); +} + /** * sil_dev_config - Apply device/host-specific errata fixups * @ap: Port containing device to be examined @@ -384,7 +416,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; unsigned int i; int pci_dev_busy = 0; - u32 tmp, irq_mask; + u32 tmp; u8 cls; if (!printed_version++) @@ -474,24 +506,11 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } if (ent->driver_data == sil_3114) { - irq_mask = SIL_MASK_4PORT; - /* flip the magic "make 4 ports work" bit */ tmp = readl(mmio_base + sil_port[2].bmdma); if ((tmp & SIL_INTR_STEERING) == 0) writel(tmp | SIL_INTR_STEERING, mmio_base + sil_port[2].bmdma); - - } else { - irq_mask = SIL_MASK_2PORT; - } - - /* make sure IDE0/1/2/3 interrupts are not masked */ - tmp = readl(mmio_base + SIL_SYSCFG); - if (tmp & irq_mask) { - tmp &= ~irq_mask; - writel(tmp, mmio_base + SIL_SYSCFG); - readl(mmio_base + SIL_SYSCFG); /* flush */ } /* mask all SATA phy-related interrupts */ -- cgit v0.10.2 From 78cd52d02fa0735949a9fa30a6b79bf02c94c250 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:29 +0900 Subject: [PATCH] ahci: convert to new EH Convert AHCI to new EH. Unfortunately, ICH7 AHCI reacts badly if IRQ mask is diddled during operation. So, freezing is implemented by unconditionally clearing interrupt conditions while frozen. * Interrupts are categorized according to required action. e.g. Connection status or unknown FIS error requires freezing the port while TF or HBUS_DATA don't. * Only CONNECT (reflects SErr.X) interrupt is taken into account not PHYRDY (SErr.N), as CONNECT is better cue for starting EH. * AHCI may be invoked without any active command. e.g. CONNECT irq occuring while no qc in progress still triggers EH and will reset the port and revalidate attached device. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index a4fb8d0..d6894bd 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -71,6 +71,7 @@ enum { AHCI_CMD_CLR_BUSY = (1 << 10), RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ + RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, board_ahci_vt8251 = 1, @@ -128,15 +129,16 @@ enum { PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ - PORT_IRQ_FATAL = PORT_IRQ_TF_ERR | - PORT_IRQ_HBUS_ERR | - PORT_IRQ_HBUS_DATA_ERR | - PORT_IRQ_IF_ERR, - DEF_PORT_IRQ = PORT_IRQ_FATAL | PORT_IRQ_PHYRDY | - PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE | - PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS | - PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS | - PORT_IRQ_D2H_REG_FIS, + PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | + PORT_IRQ_IF_ERR | + PORT_IRQ_CONNECT | + PORT_IRQ_UNK_FIS, + PORT_IRQ_ERROR = PORT_IRQ_FREEZE | + PORT_IRQ_TF_ERR | + PORT_IRQ_HBUS_DATA_ERR, + DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | + PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | + PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, /* PORT_CMD bits */ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ @@ -197,13 +199,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes); static void ahci_irq_clear(struct ata_port *ap); -static void ahci_eng_timeout(struct ata_port *ap); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); -static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); +static void ahci_freeze(struct ata_port *ap); +static void ahci_thaw(struct ata_port *ap); +static void ahci_error_handler(struct ata_port *ap); +static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static void ahci_remove_one (struct pci_dev *pdev); static struct scsi_host_template ahci_sht = { @@ -237,14 +241,18 @@ static const struct ata_port_operations ahci_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, - .eng_timeout = ahci_eng_timeout, - .irq_handler = ahci_interrupt, .irq_clear = ahci_irq_clear, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, + .freeze = ahci_freeze, + .thaw = ahci_thaw, + + .error_handler = ahci_error_handler, + .post_internal_cmd = ahci_post_internal_cmd, + .port_start = ahci_port_start, .port_stop = ahci_port_stop, }; @@ -789,108 +797,97 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) ahci_fill_cmd_slot(pp, opts); } -static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) +static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { - void __iomem *mmio = ap->host_set->mmio_base; - void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - u32 tmp; + struct ahci_port_priv *pp = ap->private_data; + struct ata_eh_info *ehi = &ap->eh_info; + unsigned int err_mask = 0, action = 0; + struct ata_queued_cmd *qc; + u32 serror; - if ((ap->device[0].class != ATA_DEV_ATAPI) || - ((irq_stat & PORT_IRQ_TF_ERR) == 0)) - ata_port_printk(ap, KERN_WARNING, "port reset, " - "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", - irq_stat, - readl(mmio + HOST_IRQ_STAT), - readl(port_mmio + PORT_IRQ_STAT), - readl(port_mmio + PORT_CMD), - readl(port_mmio + PORT_TFDATA), - readl(port_mmio + PORT_SCR_STAT), - readl(port_mmio + PORT_SCR_ERR)); - - /* stop DMA */ - ahci_stop_engine(ap); + ata_ehi_clear_desc(ehi); - /* clear SATA phy error, if any */ - tmp = readl(port_mmio + PORT_SCR_ERR); - writel(tmp, port_mmio + PORT_SCR_ERR); + /* AHCI needs SError cleared; otherwise, it might lock up */ + serror = ahci_scr_read(ap, SCR_ERROR); + ahci_scr_write(ap, SCR_ERROR, serror); - /* if DRQ/BSY is set, device needs to be reset. - * if so, issue COMRESET - */ - tmp = readl(port_mmio + PORT_TFDATA); - if (tmp & (ATA_BUSY | ATA_DRQ)) { - writel(0x301, port_mmio + PORT_SCR_CTL); - readl(port_mmio + PORT_SCR_CTL); /* flush */ - udelay(10); - writel(0x300, port_mmio + PORT_SCR_CTL); - readl(port_mmio + PORT_SCR_CTL); /* flush */ + /* analyze @irq_stat */ + ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + + if (irq_stat & PORT_IRQ_TF_ERR) + err_mask |= AC_ERR_DEV; + + if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { + err_mask |= AC_ERR_HOST_BUS; + action |= ATA_EH_SOFTRESET; } - /* re-start DMA */ - ahci_start_engine(ap); -} + if (irq_stat & PORT_IRQ_IF_ERR) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(ehi, ", interface fatal error"); + } -static void ahci_eng_timeout(struct ata_port *ap) -{ - struct ata_host_set *host_set = ap->host_set; - void __iomem *mmio = host_set->mmio_base; - void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - struct ata_queued_cmd *qc; - unsigned long flags; + if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? + "connection status changed" : "PHY RDY changed"); + } + + if (irq_stat & PORT_IRQ_UNK_FIS) { + u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); - ata_port_printk(ap, KERN_WARNING, "handling error/timeout\n"); + err_mask |= AC_ERR_HSM; + action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", + unk[0], unk[1], unk[2], unk[3]); + } - spin_lock_irqsave(&host_set->lock, flags); + /* okay, let's hand over to EH */ + ehi->serror |= serror; + ehi->action |= action; - ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT)); qc = ata_qc_from_tag(ap, ap->active_tag); - qc->err_mask |= AC_ERR_TIMEOUT; - - spin_unlock_irqrestore(&host_set->lock, flags); + if (qc) + qc->err_mask |= err_mask; + else + ehi->err_mask |= err_mask; - ata_eh_qc_complete(qc); + if (irq_stat & PORT_IRQ_FREEZE) + ata_port_freeze(ap); + else + ata_port_abort(ap); } -static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) +static void ahci_host_intr(struct ata_port *ap) { void __iomem *mmio = ap->host_set->mmio_base; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - u32 status, serr, ci; - - serr = readl(port_mmio + PORT_SCR_ERR); - writel(serr, port_mmio + PORT_SCR_ERR); + struct ata_queued_cmd *qc; + u32 status, ci; 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) { - WARN_ON(qc->err_mask); - ata_qc_complete(qc); - qc = NULL; - } + if (unlikely(status & PORT_IRQ_ERROR)) { + ahci_error_intr(ap, status); + return; } - if (status & PORT_IRQ_FATAL) { - unsigned int err_mask; - if (status & PORT_IRQ_TF_ERR) - err_mask = AC_ERR_DEV; - else if (status & PORT_IRQ_IF_ERR) - err_mask = AC_ERR_ATA_BUS; - else - err_mask = AC_ERR_HOST_BUS; - - /* command processing has stopped due to error; restart */ - ahci_restart_port(ap, status); - - if (qc) { - qc->err_mask |= err_mask; + 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; } } - return 1; + /* spurious interrupt */ + if (ata_ratelimit()) + ata_port_printk(ap, KERN_INFO, "spurious interrupt " + "(irq_stat 0x%x active_tag %d)\n", + status, ap->active_tag); } static void ahci_irq_clear(struct ata_port *ap) @@ -927,14 +924,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * ap = host_set->ports[i]; if (ap) { - struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); - if (!ahci_host_intr(ap, qc)) - if (ata_ratelimit()) - dev_printk(KERN_WARNING, host_set->dev, - "unhandled interrupt on port %u\n", - i); - + ahci_host_intr(ap); VPRINTK("port %u\n", i); } else { VPRINTK("port %u (no irq)\n", i); @@ -951,7 +941,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * handled = 1; } - spin_unlock(&host_set->lock); + spin_unlock(&host_set->lock); VPRINTK("EXIT\n"); @@ -969,6 +959,56 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) return 0; } +static void ahci_freeze(struct ata_port *ap) +{ + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + + /* turn IRQ off */ + writel(0, port_mmio + PORT_IRQ_MASK); +} + +static void ahci_thaw(struct ata_port *ap) +{ + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + u32 tmp; + + /* clear IRQ */ + tmp = readl(port_mmio + PORT_IRQ_STAT); + writel(tmp, port_mmio + PORT_IRQ_STAT); + writel(1 << ap->id, mmio + HOST_IRQ_STAT); + + /* turn IRQ back on */ + writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); +} + +static void ahci_error_handler(struct ata_port *ap) +{ + if (!(ap->flags & ATA_FLAG_FROZEN)) { + /* restart engine */ + ahci_stop_engine(ap); + ahci_start_engine(ap); + } + + /* perform recovery */ + ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset); +} + +static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (qc->flags & ATA_QCFLAG_FAILED) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask) { + /* make DMA engine forget about the failed command */ + ahci_stop_engine(ap); + ahci_start_engine(ap); + } +} + static void ahci_setup_port(struct ata_ioports *port, unsigned long base, unsigned int port_idx) { @@ -1113,9 +1153,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) writel(tmp, port_mmio + PORT_IRQ_STAT); writel(1 << i, mmio + HOST_IRQ_STAT); - - /* set irq mask (enables interrupts) */ - writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); } tmp = readl(mmio + HOST_CTL); -- cgit v0.10.2 From 2a3917a8bb40a2cb75b458da9c356e8557e8fbed Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:30 +0900 Subject: [PATCH] ahci: add PIOS interim interrupt handling During multiblock PIO, multiple PIOS interrupts are generated before qc compltion. Current code prints unnecessary message for such cases. This is exposed when new EH slows down attached device into PIO mode. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index d6894bd..35487e3 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -883,7 +883,18 @@ static void ahci_host_intr(struct ata_port *ap) } } - /* spurious interrupt */ + /* hmmm... a spurious interupt */ + + /* ignore interim PIO setup fis interrupts */ + if (ata_tag_valid(ap->active_tag)) { + struct ata_queued_cmd *qc = + ata_qc_from_tag(ap, ap->active_tag); + + if (qc && qc->tf.protocol == ATA_PROT_PIO && + (status & PORT_IRQ_PIOS_FIS)) + return; + } + if (ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(irq_stat 0x%x active_tag %d)\n", -- cgit v0.10.2 From 88ce7550c38f46c8697f53727a571bf838bee398 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:32 +0900 Subject: [PATCH] sata_sil24: convert to new EH Convert sata_sil24 to new EH. * When port is frozen, IRQ for the port is masked. * sil24_softreset() doesn't need to mangle with IRQ mask anymore. libata ensures that the port is frozen during reset. * Only turn on interrupts which are handled by interrupt handler and EH. As we don't handle SDB notify yet, turn it off. DEV_XCHG and UNK_FIS are handled by EH and thus turned on. * sil24_softreset() usually fails to recover the port after DEV_XCHG. ATA_PORT_HARDRESET is used as recovery action for DEV_XCHG. * sil24 may be invoked without any active command. e.g. DEV_XCHG irq occuring while no qc in progress still triggers EH and will reset the port and revalidate attached device. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index ff96724..6e7728c 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -156,6 +156,9 @@ enum { PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ + DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | + PORT_IRQ_DEV_XCHG | PORT_IRQ_UNK_FIS, + /* bits[27:16] are unmasked (raw) */ PORT_IRQ_RAW_SHIFT = 16, PORT_IRQ_MASKED_MASK = 0x7ff, @@ -242,6 +245,58 @@ union sil24_cmd_block { struct sil24_atapi_block atapi; }; +static struct sil24_cerr_info { + unsigned int err_mask, action; + const char *desc; +} sil24_cerr_db[] = { + [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE, + "device error" }, + [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE, + "device error via D2H FIS" }, + [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE, + "device error via SDB FIS" }, + [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET, + "error in data FIS" }, + [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET, + "failed to transmit command FIS" }, + [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + "protocol mismatch" }, + [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + "data directon mismatch" }, + [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + "ran out of SGEs while writing" }, + [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + "ran out of SGEs while reading" }, + [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + "invalid data directon for ATAPI CDB" }, + [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET, + "SGT no on qword boundary" }, + [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI target abort while fetching SGT" }, + [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI master abort while fetching SGT" }, + [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI parity error while fetching SGT" }, + [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET, + "PRB not on qword boundary" }, + [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI target abort while fetching PRB" }, + [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI master abort while fetching PRB" }, + [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI parity error while fetching PRB" }, + [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "undefined error while transferring data" }, + [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI target abort while transferring data" }, + [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI master abort while transferring data" }, + [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, + "PCI parity error while transferring data" }, + [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET, + "FIS received while sending service FIS" }, +}; + /* * ap->private_data * @@ -269,8 +324,11 @@ static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); -static void sil24_eng_timeout(struct ata_port *ap); static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void sil24_freeze(struct ata_port *ap); +static void sil24_thaw(struct ata_port *ap); +static void sil24_error_handler(struct ata_port *ap); +static void sil24_post_internal_cmd(struct ata_queued_cmd *qc); static int sil24_port_start(struct ata_port *ap); static void sil24_port_stop(struct ata_port *ap); static void sil24_host_stop(struct ata_host_set *host_set); @@ -325,14 +383,17 @@ static const struct ata_port_operations sil24_ops = { .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, - .eng_timeout = sil24_eng_timeout, - .irq_handler = sil24_interrupt, .irq_clear = sil24_irq_clear, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, + .freeze = sil24_freeze, + .thaw = sil24_thaw, + .error_handler = sil24_error_handler, + .post_internal_cmd = sil24_post_internal_cmd, + .port_start = sil24_port_start, .port_stop = sil24_port_stop, .host_stop = sil24_host_stop, @@ -459,7 +520,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) struct sil24_port_priv *pp = ap->private_data; struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; dma_addr_t paddr = pp->cmd_block_dma; - u32 mask, irq_enable, irq_stat; + u32 mask, irq_stat; const char *reason; DPRINTK("ENTER\n"); @@ -470,10 +531,6 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) goto out; } - /* temporarily turn off IRQs during SRST */ - irq_enable = readl(port + PORT_IRQ_ENABLE_SET); - writel(irq_enable, port + PORT_IRQ_ENABLE_CLR); - /* put the port into known state */ if (sil24_init_port(ap)) { reason ="port not ready"; @@ -494,9 +551,6 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */ irq_stat >>= PORT_IRQ_RAW_SHIFT; - /* restore IRQs */ - writel(irq_enable, port + PORT_IRQ_ENABLE_SET); - if (!(irq_stat & PORT_IRQ_COMPLETE)) { if (irq_stat & PORT_IRQ_ERROR) reason = "SRST command error"; @@ -655,158 +709,134 @@ static void sil24_irq_clear(struct ata_port *ap) /* unused */ } -static int __sil24_restart_controller(void __iomem *port) +static void sil24_freeze(struct ata_port *ap) { - u32 tmp; - int cnt; - - writel(PORT_CS_INIT, port + PORT_CTRL_STAT); - - /* Max ~10ms */ - for (cnt = 0; cnt < 10000; cnt++) { - tmp = readl(port + PORT_CTRL_STAT); - if (tmp & PORT_CS_RDY) - return 0; - udelay(1); - } - - return -1; -} + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; -static void sil24_restart_controller(struct ata_port *ap) -{ - if (__sil24_restart_controller((void __iomem *)ap->ioaddr.cmd_addr)) - printk(KERN_ERR DRV_NAME - " ata%u: failed to restart controller\n", ap->id); + /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear + * PORT_IRQ_ENABLE instead. + */ + writel(0xffff, port + PORT_IRQ_ENABLE_CLR); } -static int __sil24_reset_controller(void __iomem *port) +static void sil24_thaw(struct ata_port *ap) { - int cnt; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; u32 tmp; - /* Reset controller state. Is this correct? */ - writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); - readl(port + PORT_CTRL_STAT); /* sync */ - - /* Max ~100ms */ - for (cnt = 0; cnt < 1000; cnt++) { - udelay(100); - tmp = readl(port + PORT_CTRL_STAT); - if (!(tmp & PORT_CS_DEV_RST)) - break; - } - - if (tmp & PORT_CS_DEV_RST) - return -1; - - if (tmp & PORT_CS_RDY) - return 0; - - return __sil24_restart_controller(port); -} - -static void sil24_reset_controller(struct ata_port *ap) -{ - printk(KERN_NOTICE DRV_NAME - " ata%u: resetting controller...\n", ap->id); - if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr)) - printk(KERN_ERR DRV_NAME - " ata%u: failed to reset controller\n", ap->id); -} - -static void sil24_eng_timeout(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - - qc = ata_qc_from_tag(ap, ap->active_tag); - - ata_port_printk(ap, KERN_ERR, "command timeout\n"); - qc->err_mask |= AC_ERR_TIMEOUT; - ata_eh_qc_complete(qc); + /* clear IRQ */ + tmp = readl(port + PORT_IRQ_STAT); + writel(tmp, port + PORT_IRQ_STAT); - sil24_reset_controller(ap); + /* turn IRQ back on */ + writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET); } -static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) +static void sil24_error_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 irq_stat, cmd_err, sstatus, serror; - unsigned int err_mask; + struct ata_eh_info *ehi = &ap->eh_info; + int freeze = 0; + u32 irq_stat; + /* on error, we need to clear IRQ explicitly */ irq_stat = readl(port + PORT_IRQ_STAT); - writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */ + writel(irq_stat, port + PORT_IRQ_STAT); - if (!(irq_stat & PORT_IRQ_ERROR)) { - /* ignore non-completion, non-error irqs for now */ - printk(KERN_WARNING DRV_NAME - "ata%u: non-error exception irq (irq_stat %x)\n", - ap->id, irq_stat); - return; - } + /* first, analyze and record host port events */ + ata_ehi_clear_desc(ehi); - cmd_err = readl(port + PORT_CMD_ERR); - sstatus = readl(port + PORT_SSTATUS); - serror = readl(port + PORT_SERROR); - if (serror) - writel(serror, port + PORT_SERROR); + ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); - /* - * Don't log ATAPI device errors. They're supposed to happen - * and any serious errors will be logged using sense data by - * the SCSI layer. - */ - if (ap->device[0].class != ATA_DEV_ATAPI || cmd_err > PORT_CERR_SDB) - printk("ata%u: error interrupt on port%d\n" - " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", - ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); - - if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) { - /* - * Device is reporting error, tf registers are valid. + if (irq_stat & PORT_IRQ_DEV_XCHG) { + ehi->err_mask |= AC_ERR_ATA_BUS; + /* sil24 doesn't recover very well from phy + * disconnection with a softreset. Force hardreset. */ - sil24_update_tf(ap); - err_mask = ac_err_mask(pp->tf.command); - sil24_restart_controller(ap); - } else { - /* - * Other errors. libata currently doesn't have any - * mechanism to report these errors. Just turn on - * ATA_ERR. - */ - err_mask = AC_ERR_OTHER; - sil24_reset_controller(ap); + ehi->action |= ATA_EH_HARDRESET; + ata_ehi_push_desc(ehi, ", device_exchanged"); + freeze = 1; } - if (qc) { - qc->err_mask |= err_mask; - ata_qc_complete(qc); + if (irq_stat & PORT_IRQ_UNK_FIS) { + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(ehi , ", unknown FIS"); + freeze = 1; + } + + /* deal with command error */ + if (irq_stat & PORT_IRQ_ERROR) { + struct sil24_cerr_info *ci = NULL; + unsigned int err_mask = 0, action = 0; + struct ata_queued_cmd *qc; + u32 cerr; + + /* analyze CMD_ERR */ + cerr = readl(port + PORT_CMD_ERR); + if (cerr < ARRAY_SIZE(sil24_cerr_db)) + ci = &sil24_cerr_db[cerr]; + + if (ci && ci->desc) { + err_mask |= ci->err_mask; + action |= ci->action; + ata_ehi_push_desc(ehi, ", %s", ci->desc); + } else { + err_mask |= AC_ERR_OTHER; + action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(ehi, ", unknown command error %d", + cerr); + } + + /* 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 + ehi->err_mask |= err_mask; + + ehi->action |= action; } + + /* freeze or abort */ + if (freeze) + ata_port_freeze(ap); + else + ata_port_abort(ap); } static inline void sil24_host_intr(struct ata_port *ap) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + struct ata_queued_cmd *qc; u32 slot_stat; slot_stat = readl(port + PORT_SLOT_STAT); - if (!(slot_stat & HOST_SSTAT_ATTN)) { - struct sil24_port_priv *pp = ap->private_data; - if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) - writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); + if (unlikely(slot_stat & HOST_SSTAT_ATTN)) { + sil24_error_intr(ap); + return; + } + + if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) + writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); - if (qc) { - if (qc->flags & ATA_QCFLAG_RESULT_TF) - sil24_update_tf(ap); - qc->err_mask |= ac_err_mask(pp->tf.command); - ata_qc_complete(qc); - } - } else - sil24_error_intr(ap, slot_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); + 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); } static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) @@ -846,6 +876,31 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs * return IRQ_RETVAL(handled); } +static void sil24_error_handler(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + + if (sil24_init_port(ap)) { + ata_eh_freeze_port(ap); + ehc->i.action |= ATA_EH_HARDRESET; + } + + /* perform recovery */ + ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset); +} + +static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (qc->flags & ATA_QCFLAG_FAILED) + qc->err_mask |= AC_ERR_OTHER; + + /* make DMA engine forget about the failed command */ + if (qc->err_mask) + sil24_init_port(ap); +} + static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev) { const size_t cb_size = sizeof(*pp->cmd_block); @@ -1058,15 +1113,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Always use 64bit activation */ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - /* Configure interrupts */ - writel(0xffff, port + PORT_IRQ_ENABLE_CLR); - writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | - PORT_IRQ_SDB_NOTIFY, port + PORT_IRQ_ENABLE_SET); - - /* Clear interrupts */ - writel(0x0fff0fff, port + PORT_IRQ_STAT); - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - /* Clear port multiplier enable and resume bits */ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); } -- cgit v0.10.2 From c17ea20d9a689d7335e97e09354865cdd9f873e1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:59:29 +0900 Subject: [PATCH] libata: fix irq-pio merge * kill ata_poll_qc_complete() and implement/use ata_hsm_qc_complete() which completes qcs in new EH compliant manner from HSM * don't print error message from ata_hsm_move(). it's responsibility of EH. * kill ATA_FLAG_NOINTR usage in bmdma EH Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 49eff18..6d30d2c 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -726,7 +726,6 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, /* reset PIO HSM and stop DMA engine */ spin_lock_irqsave(&host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; ap->hsm_task_state = HSM_ST_IDLE; if (qc && (qc->tf.protocol == ATA_PROT_DMA || diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c859b96..487b8f2 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3462,40 +3462,6 @@ skip_map: } /** - * ata_poll_qc_complete - turn irq back on and finish qc - * @qc: Command to complete - * @err_mask: ATA status register content - * - * LOCKING: - * None. (grabs host lock) - */ -void ata_poll_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned long flags; - - spin_lock_irqsave(&ap->host_set->lock, flags); - - if (ap->ops->error_handler) { - /* EH might have kicked in while host_set lock is released */ - qc = ata_qc_from_tag(ap, qc->tag); - if (qc) { - if (!(qc->err_mask & AC_ERR_HSM)) { - ata_irq_on(ap); - ata_qc_complete(qc); - } else - ata_port_freeze(ap); - } - } else { - /* old EH */ - ata_irq_on(ap); - ata_qc_complete(qc); - } - - spin_unlock_irqrestore(&ap->host_set->lock, flags); -} - -/** * swap_buf_le16 - swap halves of 16-bit words in place * @buf: Buffer to swap * @buf_words: Number of 16-bit words in buffer. @@ -3918,6 +3884,56 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q } /** + * ata_hsm_qc_complete - finish a qc running on standard HSM + * @qc: Command to complete + * @in_wq: 1 if called from workqueue, 0 otherwise + * + * Finish @qc which is running on standard HSM. + * + * LOCKING: + * If @in_wq is zero, spin_lock_irqsave(host_set lock). + * Otherwise, none on entry and grabs host lock. + */ +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + unsigned long flags; + + if (ap->ops->error_handler) { + if (in_wq) { + spin_lock_irqsave(&ap->host_set->lock, flags); + + /* EH might have kicked in while host_set lock + * is released. + */ + qc = ata_qc_from_tag(ap, qc->tag); + if (qc) { + if (likely(!(qc->err_mask & AC_ERR_HSM))) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else + ata_port_freeze(ap); + } + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else { + if (likely(!(qc->err_mask & AC_ERR_HSM))) + ata_qc_complete(qc); + else + ata_port_freeze(ap); + } + } else { + if (in_wq) { + spin_lock_irqsave(&ap->host_set->lock, flags); + ata_irq_on(ap); + ata_qc_complete(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else + ata_qc_complete(qc); + } +} + +/** * ata_hsm_move - move the HSM to the next state. * @ap: the target ata_port * @qc: qc on going @@ -4108,19 +4124,12 @@ fsm_start: ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - if (in_wq) - ata_poll_qc_complete(qc); - else - ata_qc_complete(qc); + ata_hsm_qc_complete(qc, in_wq); poll_next = 0; break; case HSM_ST_ERR: - if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_ERR "ata%u: dev %u command error, drv_stat 0x%x\n", - ap->id, qc->dev->devno, status); - /* make sure qc->err_mask is available to * know what's wrong and recover */ @@ -4129,10 +4138,7 @@ fsm_start: ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - if (in_wq) - ata_poll_qc_complete(qc); - else - ata_qc_complete(qc); + ata_hsm_qc_complete(qc, in_wq); poll_next = 0; break; -- cgit v0.10.2 From 88e490340ea4c3a2ebc0187a4339912e2fc1a081 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:38 +0900 Subject: [PATCH] libata-ncq: add NCQ related ATA/libata constants and macros Add NCQ related ATA/libata constants and macros. Signed-off-by: Tejun Heo 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 db17723..7c9e280 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 */ @@ -150,6 +151,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 */ -- cgit v0.10.2 From 2115ea94a2d11fbd228b049e667ec2d3e91ca371 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:39 +0900 Subject: [PATCH] libata-ncq: pass ata_scsi_translate() return value to SCSI midlayer ata_scsi_translate() will need to return SCSI_ML_QUEUE_DEVICE_BUSY to achieve exlusion between NCQ and non-NCQ commands or among non-NCQ commands. Pass its return value upward to SCSI midlayer. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index e61cc357..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 ata_queued_cmd *qc) * * 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 ata_device *dev, struct scsi_cmnd *cmd, 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(struct ata_port *ap, #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(struct scsi_cmnd *cmd, * 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 *cmd, void (*done)(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 *cmd, void (*done)(struct scsi_cmnd *)) spin_unlock(&ap->host_set->lock); spin_lock(shost->host_lock); - return 0; + return rc; } /** -- cgit v0.10.2 From 6cec4a3943bdfe46e2952bc246f17670f747be8d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:41 +0900 Subject: [PATCH] libata-ncq: rename ap->qactive to ap->qc_allocated Rename ap->qactive to ap->qc_allocated. This is to accomodate addition of ap->qc_active, mask of active qcs. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 487b8f2..f840180 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1006,7 +1006,7 @@ unsigned ata_exec_internal(struct ata_device *dev, 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); @@ -4207,7 +4207,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) /* 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; } @@ -4264,7 +4264,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) 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 7c9e280..b3a4f8b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -474,7 +474,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; -- cgit v0.10.2 From dedaf2b0365ccec50714fbde0b3215e7e94fa47c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:43 +0900 Subject: [PATCH] libata-ncq: implement ap->qc_active, ap->sactive and complete helper 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. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f840180..eea1fe9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -981,6 +981,7 @@ unsigned ata_exec_internal(struct ata_device *dev, 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_device *dev, 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_device *dev, 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 @@ -4270,6 +4277,8 @@ void ata_qc_free(struct ata_queued_cmd *qc) 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)); @@ -4277,13 +4286,17 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) 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); @@ -4349,6 +4362,55 @@ void ata_qc_complete(struct ata_queued_cmd *qc) } } +/** + * 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; @@ -4388,8 +4450,22 @@ void ata_qc_issue(struct ata_queued_cmd *qc) { 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 b3a4f8b..dd0db2d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -475,7 +475,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; @@ -668,6 +671,8 @@ extern void ata_bmdma_drive_eh(struct ata_port *ap, 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, -- cgit v0.10.2 From 3dc1d88193b9c65b01b64fb2dc730e486306649f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:45 +0900 Subject: [PATCH] libata-ncq: implement NCQ command translation and exclusion 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. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index eea1fe9..14ffb52 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4416,6 +4416,7 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc) 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(struct ata_queued_cmd *qc, const u8 *scsicm */ 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_queued_cmd *qc) } /** + * 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_device *dev, struct scsi_cmnd *cmd, { 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; } /** -- cgit v0.10.2 From e8ee84518c159a663c07bf691ace187527380f61 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:46 +0900 Subject: [PATCH] libata-ncq: update EH to handle NCQ 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. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index e401f35..7244caf 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -685,6 +685,98 @@ static const char * ata_err_string(unsigned int err_mask) } /** + * 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) @@ -783,6 +875,66 @@ static void ata_eh_analyze_serror(struct ata_port *ap) } /** + * 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 @@ -999,6 +1151,9 @@ static void ata_eh_autopsy(struct ata_port *ap) } 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; @@ -1093,17 +1248,17 @@ static void ata_eh_report(struct ata_port *ap) 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); } -- cgit v0.10.2 From a6e6ce8e8dc907a2cf2b994b0ea4099423f046bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:48 +0900 Subject: [PATCH] libata-ncq: implement NCQ device configuration 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. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 14ffb52..9051b68 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1251,6 +1251,28 @@ static inline u8 ata_dev_knobble(struct ata_device *dev) 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_device *dev, int print_info) 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_device *dev, int print_info) 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(sata_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 #include #include +#include #include #include #include @@ -684,6 +685,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev, 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_device *sdev) } /** + * 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 dd0db2d..fcdd798 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, @@ -679,6 +679,8 @@ extern int ata_std_bios_param(struct scsi_device *sdev, 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); /* -- cgit v0.10.2 From dd410ff12925fc49df3174b18e43598b2b2b621f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:50 +0900 Subject: [PATCH] ahci: clean up AHCI constants in preparation for NCQ * Rename CMD_TBL_HDR to CMD_TBL_HDR_SZ as it's size not offset. * Define MAX_CMDS and CMD_SZ and use them in calculation of other constants. * Define CMD_TBL_AR_SZ as product of CMD_TBL_SZ and MAX_CMDS, and use it when calculating PRIV_DMA_SZ. * CMD_SLOT_SZ is also dependent on MAX_CMDS but hasn't been changed because I didn't want to change the value used by the original code (32 commands). Later NCQ change will bump MAX_CMDS to 32 anyway and the hard coded 32 can be changed to MAX_CMDS then. * Reorder HOST_CAP_* flags. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 35487e3..b25373f 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 */ @@ -398,7 +401,7 @@ static int ahci_port_start(struct ata_port *ap) 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; -- cgit v0.10.2 From 979db803b8fd120d4ed5216520e9d1815e18bc38 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:52 +0900 Subject: [PATCH] ahci: add HOST_CAP_NCQ constant Add HOST_CAP_NCQ. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index b25373f..740e7d8 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 */ -- cgit v0.10.2 From a9764c2bb5b6d3c9df91f2977a2a640f55de0dc2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:53 +0900 Subject: [PATCH] ahci: kill pp->cmd_tbl_sg With NCQ, there are multiple sg tables, so pp->cmd_tbl_sg doesn't cut it. Directly calculate sg table address from pp->cmd_tbl. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 740e7d8..9f974db 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; }; @@ -402,8 +401,6 @@ static int ahci_port_start(struct ata_port *ap) 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) @@ -749,7 +746,7 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc) /* * 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); -- cgit v0.10.2 From 12fad3f965830d71f6454f02b2af002a64cec4d3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:55 +0900 Subject: [PATCH] ahci: implement NCQ suppport Implement NCQ support. Original implementation is from Jens Axboe. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 9f974db..45fd71d 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, @@ -218,7 +218,8 @@ static struct scsi_host_template ahci_sht = { .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, @@ -533,12 +534,17 @@ static unsigned int ahci_dev_classify(struct ata_port *ap) 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) @@ -610,7 +616,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) 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); @@ -629,7 +636,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) 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); @@ -734,9 +741,8 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 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; @@ -746,7 +752,7 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc) /* * 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); @@ -767,6 +773,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) 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; @@ -775,16 +782,17 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) * 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. @@ -795,7 +803,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) 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) @@ -865,8 +873,9 @@ static void ahci_host_intr(struct ata_port *ap) { void __iomem *mmio = ap->host_set->mmio_base; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - struct ata_queued_cmd *qc; - u32 status, ci; + struct ata_eh_info *ehi = &ap->eh_info; + u32 status, qc_active; + int rc; status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); @@ -876,16 +885,27 @@ static void ahci_host_intr(struct ata_port *ap) 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 = @@ -898,8 +918,8 @@ static void ahci_host_intr(struct ata_port *ap) 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) @@ -907,7 +927,7 @@ static void ahci_irq_clear(struct ata_port *ap) /* 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; @@ -965,7 +985,9 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 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; @@ -1262,6 +1284,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) VPRINTK("ENTER\n"); + WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); + if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -1329,6 +1353,9 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 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 */ -- cgit v0.10.2 From aee10a03eb3e240bfd1a6f91e06ce82df47c5c58 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:56 +0900 Subject: [PATCH] sata_sil24: implement NCQ support Implement NCQ support. Sil24 has 31 command slots and all of them are used for NCQ command queueing. libata guarantees that no other command is in progress when it issues an internal command, so always use tag 0 for internal commands. Signed-off-by: Tejun Heo diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 6e7728c..4c76f05 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_sht = { .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_info[] = { }, }; +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_queued_cmd *qc) { 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_queued_cmd *qc) 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_port *ap) /* 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_port *ap) 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(struct ata_port *ap) 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(struct ata_queued_cmd *qc) 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_port *ap) 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; -- cgit v0.10.2