Merge branch 'upstream'
authorJeff Garzik <jgarzik@pobox.com>
Tue, 6 Dec 2005 09:52:48 +0000 (04:52 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Tue, 6 Dec 2005 09:52:48 +0000 (04:52 -0500)
1  2 
drivers/scsi/libata-core.c
drivers/scsi/pdc_adma.c
drivers/scsi/sata_mv.c
drivers/scsi/sata_promise.c
drivers/scsi/sata_qstor.c
drivers/scsi/sata_sx4.c
include/linux/libata.h

@@@ -2793,8 -2784,9 +2794,8 @@@ void ata_poll_qc_complete(struct ata_qu
        unsigned long flags;
  
        spin_lock_irqsave(&ap->host_set->lock, flags);
 -      ap->flags &= ~ATA_FLAG_NOINTR;
        ata_irq_on(ap);
-       ata_qc_complete(qc, err_mask);
+       ata_qc_complete(qc);
        spin_unlock_irqrestore(&ap->host_set->lock, flags);
  }
  
@@@ -2867,31 -2863,33 +2873,33 @@@ static int ata_pio_complete (struct ata
         * 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)) {
+       drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
+       if (drv_stat & ATA_BUSY) {
                msleep(2);
-               drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
-               if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+               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 0;
 +                      return 1;
                }
        }
  
+       qc = ata_qc_from_tag(ap, ap->active_tag);
+       assert(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 0;
 +              return 1;
        }
  
-       qc = ata_qc_from_tag(ap, ap->active_tag);
-       assert(qc != NULL);
        ap->hsm_task_state = HSM_ST_IDLE;
  
-       ata_poll_qc_complete(qc, 0);
+       assert(qc->err_mask == 0);
+       ata_poll_qc_complete(qc);
  
        /* another command may start at this point */
  
@@@ -3539,10 -3381,9 +3562,11 @@@ static void ata_qc_timeout(struct ata_q
                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, ac_err_mask(drv_stat));
+               qc->err_mask |= ac_err_mask(drv_stat);
+               ata_qc_complete(qc);
                break;
        }
  
@@@ -4177,142 -3958,48 +4201,143 @@@ void ata_bmdma_stop(struct ata_queued_c
  inline unsigned int ata_host_intr (struct ata_port *ap,
                                   struct ata_queued_cmd *qc)
  {
 -      u8 status, host_stat;
 +      u8 status, host_stat = 0;
  
 -      switch (qc->tf.protocol) {
 +      VPRINTK("ata%u: protocol %d task_state %d\n",
 +              ap->id, qc->tf.protocol, ap->hsm_task_state);
  
 -      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);
 -
 -              /* 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_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 */
 +                      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, ac_err_mask(status));
+               qc->err_mask |= ac_err_mask(status);
+               ata_qc_complete(qc);
                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;
        }
@@@ -463,15 -463,13 +463,13 @@@ static inline unsigned int adma_intr_pk
                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))) {
-                       unsigned int err_mask = 0;
                        if ((status & (aPERR | aPSD | aUIRQ)))
-                               err_mask = AC_ERR_OTHER;
+                               qc->err_mask |= AC_ERR_OTHER;
                        else if (pp->pkt[0] != cDONE)
-                               err_mask = AC_ERR_OTHER;
+                               qc->err_mask |= AC_ERR_OTHER;
  
-                       ata_qc_complete(qc, err_mask);
+                       ata_qc_complete(qc);
                }
        }
        return handled;
@@@ -1242,8 -1242,10 +1242,10 @@@ static void mv_host_intr(struct ata_hos
                                VPRINTK("port %u IRQ found for qc, "
                                        "ata_status 0x%x\n", port,ata_status);
                                /* mark qc status appropriately */
-                               if (!(qc->tf.flags & ATA_TFLAG_POLLING))
 -                              if (!(qc->tf.ctl & ATA_NIEN)) {
++                              if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
+                                       qc->err_mask |= err_mask;
 -                                      ata_qc_complete(qc);
 +                                      ata_qc_complete(qc, err_mask);
+                               }
                        }
                }
        }
Simple merge
Simple merge
Simple merge
Simple merge