diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -71,6 +71,7 @@ static int fgb(u32 bitmap); static int ata_choose_xfer_mode(struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static void __ata_qc_complete(struct ata_queued_cmd *qc); static unsigned int ata_unique_id = 1; @@ -3037,32 +3038,11 @@ static void ata_qc_timeout(struct ata_qu { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; - struct ata_device *dev = qc->dev; u8 host_stat = 0, drv_stat; unsigned long flags; DPRINTK("ENTER\n"); - /* FIXME: doesn't this conflict with timeout handling? */ - if (qc->dev->class == ATA_DEV_ATAPI && qc->scsicmd) { - struct scsi_cmnd *cmd = qc->scsicmd; - - if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) { - - /* finish completing original command */ - spin_lock_irqsave(&host_set->lock, flags); - __ata_qc_complete(qc); - spin_unlock_irqrestore(&host_set->lock, flags); - - atapi_request_sense(ap, dev, cmd); - - cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); - scsi_finish_command(cmd); - - goto out; - } - } - spin_lock_irqsave(&host_set->lock, flags); /* hack alert! We cannot use the supplied completion @@ -3101,7 +3081,6 @@ static void ata_qc_timeout(struct ata_qu spin_unlock_irqrestore(&host_set->lock, flags); -out: DPRINTK("EXIT\n"); } @@ -3127,19 +3106,33 @@ out: void ata_eng_timeout(struct ata_port *ap) { struct ata_queued_cmd *qc; + struct ata_host_set *host_set = ap->host_set; + unsigned long flags; + int printed_message = 0; DPRINTK("ENTER\n"); + spin_lock_irqsave(&host_set->lock, flags); + while (ap->flags & ATA_FLAG_IN_EH) { + spin_unlock_irqrestore(&host_set->lock, flags); + + if (!printed_message++) + printk(KERN_INFO "ata%u: waiting in timeout handler for EH\n", + ap->id); + + msleep(250); + + spin_lock_irqsave(&host_set->lock, flags); + } + spin_unlock_irqrestore(&host_set->lock, flags); + qc = ata_qc_from_tag(ap, ap->active_tag); if (qc) ata_qc_timeout(qc); - else { + else printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); - goto out; - } -out: DPRINTK("EXIT\n"); } @@ -3207,7 +3200,7 @@ struct ata_queued_cmd *ata_qc_new_init(s return qc; } -int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) { return 0; } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1479,19 +1479,33 @@ void ata_scsi_badcmd(struct scsi_cmnd *c done(cmd); } -void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd) +static int atapi_qc_complete_sense(struct ata_queued_cmd *qc, u8 drv_stat) { - DECLARE_COMPLETION(wait); - struct ata_queued_cmd *qc; - unsigned long flags; + struct scsi_cmnd *cmd = qc->scsicmd; + int ok; + + ok = ata_ok(drv_stat); + if (ok) + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + else + ata_to_sense_error(qc, drv_stat); + + DPRINTK("ATAPI request sense completion (sense %sretrieved)\n", + ok ? "" : "not "); + + qc->ap->flags &= ~ATA_FLAG_IN_EH; + qc->scsidone(cmd); + return 0; +} + +static void atapi_request_sense(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scsi_cmnd *cmd = qc->scsicmd; int rc; DPRINTK("ATAPI request sense\n"); - qc = ata_qc_new_init(ap, dev); - BUG_ON(qc == NULL); - /* FIXME: is this needed? */ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); @@ -1510,44 +1524,39 @@ void atapi_request_sense(struct ata_port qc->tf.lbah = (8 * 1024) >> 8; qc->nbytes = SCSI_SENSE_BUFFERSIZE; - qc->waiting = &wait; - qc->complete_fn = ata_qc_complete_noop; + qc->complete_fn = atapi_qc_complete_sense; - spin_lock_irqsave(&ap->host_set->lock, flags); rc = ata_qc_issue(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (rc) + if (rc) { + /* FIXME: complete failing command with an error */ ata_port_disable(ap); - else - wait_for_completion(&wait); + } + + /* FIXME: add timer for timeout of this command */ + /* control flow continues in atapi_qc_complete_sense() */ DPRINTK("EXIT\n"); } static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { + struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat); + rmb(); + if (ap->host->eh_active) + return 1; + if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ))) ata_to_sense_error(qc, drv_stat); else if (unlikely(drv_stat & ATA_ERR)) { DPRINTK("request check condition\n"); - - /* FIXME: command completion with check condition - * but no sense causes the error handler to run, - * which then issues REQUEST SENSE, fills in the sense - * buffer, and completes the command (for the second - * time). We need to issue REQUEST SENSE some other - * way, to avoid completing the command twice. - */ - cmd->result = SAM_STAT_CHECK_CONDITION; - - qc->scsidone(cmd); - + ap->flags |= ATA_FLAG_IN_EH; + atapi_request_sense(qc); return 1; } @@ -1585,6 +1594,7 @@ static int atapi_qc_complete(struct ata_ qc->scsidone(cmd); return 0; } + /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -39,7 +39,6 @@ struct ata_scsi_args { /* libata-core.c */ extern int atapi_enabled; -extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); extern void ata_qc_free(struct ata_queued_cmd *qc); @@ -52,8 +51,6 @@ extern void swap_buf_le16(u16 *buf, unsi /* libata-scsi.c */ -extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd); extern void ata_scsi_scan_host(struct ata_port *ap); extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); diff --git a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -118,6 +118,7 @@ enum { 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_FLAG_IN_EH = (1 << 10), ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */