From: Jeff Garzik Date: Wed, 24 May 2006 05:49:12 +0000 (-0400) Subject: Merge branch 'upstream-fixes' into upstream X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=c81e29b4aca2b2503238276219d97faaac994b4f;p=linux-beck.git Merge branch 'upstream-fixes' into upstream Conflicts: drivers/scsi/libata-core.c --- c81e29b4aca2b2503238276219d97faaac994b4f diff --cc drivers/scsi/libata-core.c index bf00d2b2e404,fa476e7e0a48..e891b83be10f --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@@ -3690,68 -3444,14 +3690,68 @@@ static void ata_pio_sector(struct ata_q qc->cursg++; qc->cursg_ofs = 0; } +} - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); +/** + * 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 ++ * 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; + + WARN_ON(qc->dev->multi_count == 0); + + 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 + * + * When device has indicated its readiness to accept + * a CDB, this function is called. Send the CDB. + * + * LOCKING: + * caller. + */ - /* do the actual data transfer */ - do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); +static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + /* send SCSI cdb */ + DPRINTK("send cdb\n"); + WARN_ON(qc->dev->cdb_len < 12); - kunmap(page); + ata_data_xfer(ap, qc->cdb, qc->dev->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; + } } /** @@@ -3899,80 -3583,127 +3899,82 @@@ err_out } /** - * ata_pio_block - start PIO on a block + * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue. * @ap: the target ata_port + * @qc: qc on going * - * LOCKING: - * None. (executing in kernel thread context) + * RETURNS: + * 1 if ok in workqueue, 0 otherwise. */ -static void ata_pio_block(struct ata_port *ap) +static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) { - 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; - } - } + if (qc->tf.flags & ATA_TFLAG_POLLING) + return 1; - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); + if (ap->hsm_task_state == HSM_ST_FIRST) { + if (qc->tf.protocol == ATA_PROT_PIO && + (qc->tf.flags & ATA_TFLAG_WRITE)) + return 1; - /* check error */ - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - ap->hsm_task_state = HSM_ST_ERR; - return; + if (is_atapi_taskfile(&qc->tf) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; } - /* 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_sector(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); + return 0; } -static void ata_pio_task(void *_data) +/** + * 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 = _data; - unsigned long timeout; - int qc_completed; - -fsm_start: - timeout = 0; - qc_completed = 0; - - switch (ap->hsm_task_state) { - case HSM_ST_IDLE: - return; - - case HSM_ST: - ata_pio_block(ap); - break; + struct ata_port *ap = qc->ap; + unsigned long flags; - case HSM_ST_LAST: - qc_completed = ata_pio_complete(ap); - break; + if (ap->ops->error_handler) { + if (in_wq) { + spin_lock_irqsave(&ap->host_set->lock, flags); - case HSM_ST_POLL: - case HSM_ST_LAST_POLL: - timeout = ata_pio_poll(ap); - break; + /* 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); + } - case HSM_ST_TMOUT: - case HSM_ST_ERR: - ata_pio_error(ap); - return; + 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); } + - if (timeout) - ata_port_queue_task(ap, ata_pio_task, ap, timeout); - else if (!qc_completed) - goto fsm_start; ++ ata_altstatus(ap); /* flush */ } /**