[PATCH] libata: err_mask misc fix
[safe/jmp/linux-2.6] / drivers / scsi / libata-core.c
index bb604df..e4c4007 100644 (file)
@@ -605,7 +605,7 @@ void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
        tf->command = ata_rw_cmds[index + lba48 + write];
 }
 
-static const char * xfer_mode_str[] = {
+static const char * const xfer_mode_str[] = {
        "UDMA/16",
        "UDMA/25",
        "UDMA/33",
@@ -1046,6 +1046,30 @@ static unsigned int ata_pio_modes(const struct ata_device *adev)
        return modes;
 }
 
+static int ata_qc_wait_err(struct ata_queued_cmd *qc,
+                          struct completion *wait)
+{
+       int rc = 0;
+
+       if (wait_for_completion_timeout(wait, 30 * HZ) < 1) {
+               /* timeout handling */
+               qc->err_mask |= ac_err_mask(ata_chk_status(qc->ap));
+
+               if (!qc->err_mask) {
+                       printk(KERN_WARNING "ata%u: slow completion (cmd %x)\n",
+                              qc->ap->id, qc->tf.command);
+               } else {
+                       printk(KERN_WARNING "ata%u: qc timeout (cmd %x)\n",
+                              qc->ap->id, qc->tf.command);
+                       rc = -EIO;
+               }
+
+               ata_qc_complete(qc);
+       }
+
+       return rc;
+}
+
 /**
  *     ata_dev_identify - obtain IDENTIFY x DEVICE page
  *     @ap: port on which device we wish to probe resides
@@ -1125,7 +1149,7 @@ retry:
        if (rc)
                goto err_out;
        else
-               wait_for_completion(&wait);
+               ata_qc_wait_err(qc, &wait);
 
        spin_lock_irqsave(&ap->host_set->lock, flags);
        ap->ops->tf_read(ap, &qc->tf);
@@ -1151,6 +1175,7 @@ retry:
                                qc->cursg_ofs = 0;
                                qc->cursect = 0;
                                qc->nsect = 1;
+                               qc->err_mask = 0;
                                goto retry;
                        }
                }
@@ -1420,11 +1445,23 @@ void __sata_phy_reset(struct ata_port *ap)
        } while (time_before(jiffies, timeout));
 
        /* TODO: phy layer with polling, timeouts, etc. */
-       if (sata_dev_present(ap))
+       sstatus = scr_read(ap, SCR_STATUS);
+       if (sata_dev_present(ap)) {
+               const char *speed;
+               u32 tmp;
+
+               tmp = (sstatus >> 4) & 0xf;
+               if (tmp & (1 << 0))
+                       speed = "1.5";
+               else if (tmp & (1 << 1))
+                       speed = "3.0";
+               else
+                       speed = "<unknown>";
+               printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
+                      ap->id, speed, sstatus);
                ata_port_probe(ap);
-       else {
-               sstatus = scr_read(ap, SCR_STATUS);
-               printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n",
+       } else {
+               printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
                       ap->id, sstatus);
                ata_port_disable(ap);
        }
@@ -2047,7 +2084,7 @@ static void ata_pr_blacklisted(const struct ata_port *ap,
                ap->id, dev->devno);
 }
 
-static const char * ata_dma_blacklist [] = {
+static const char * const ata_dma_blacklist [] = {
        "WDC AC11000H",
        "WDC AC22100H",
        "WDC AC32500H",
@@ -2269,7 +2306,7 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
        if (rc)
                ata_port_disable(ap);
        else
-               wait_for_completion(&wait);
+               ata_qc_wait_err(qc, &wait);
 
        DPRINTK("EXIT\n");
 }
@@ -2317,7 +2354,7 @@ static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev)
        if (rc)
                goto err_out;
 
-       wait_for_completion(&wait);
+       ata_qc_wait_err(qc, &wait);
 
        swap_buf_le16(dev->id, ATA_ID_WORDS);
 
@@ -2373,7 +2410,7 @@ static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
        if (rc)
                ata_port_disable(ap);
        else
-               wait_for_completion(&wait);
+               ata_qc_wait_err(qc, &wait);
 
        DPRINTK("EXIT\n");
 }
@@ -2741,7 +2778,7 @@ skip_map:
  *     None.  (grabs host lock)
  */
 
-void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
+void ata_poll_qc_complete(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        unsigned long flags;
@@ -2749,7 +2786,7 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
        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);
 }
 
@@ -2766,10 +2803,14 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
 
 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);
+       assert(qc != NULL);
+
        switch (ap->hsm_task_state) {
        case HSM_ST:
        case HSM_ST_POLL:
@@ -2789,6 +2830,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
        status = ata_chk_status(ap);
        if (status & ATA_BUSY) {
                if (time_after(jiffies, ap->pio_task_timeout)) {
+                       qc->err_mask |= AC_ERR_ATA_BUS;
                        ap->hsm_task_state = HSM_ST_TMOUT;
                        return 0;
                }
@@ -2823,29 +2865,31 @@ static int ata_pio_complete (struct ata_port *ap)
         * msecs, then chk-status again.  If still busy, fall back to
         * HSM_ST_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;
                }
        }
 
+       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;
        }
 
-       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 */
 
@@ -3153,6 +3197,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
 err_out:
        printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
              ap->id, dev->devno);
+       qc->err_mask |= AC_ERR_ATA_BUS;
        ap->hsm_task_state = HSM_ST_ERR;
 }
 
@@ -3191,8 +3236,16 @@ static void ata_pio_block(struct ata_port *ap)
        qc = ata_qc_from_tag(ap, ap->active_tag);
        assert(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)) {
-               /* no more data to transfer or unsupported ATAPI command */
+               /* DRQ=0 means no more data to transfer */
                if ((status & ATA_DRQ) == 0) {
                        ap->hsm_task_state = HSM_ST_LAST;
                        return;
@@ -3202,6 +3255,7 @@ static void ata_pio_block(struct ata_port *ap)
        } else {
                /* handle BSY=0, DRQ=0 as error */
                if ((status & ATA_DRQ) == 0) {
+                       qc->err_mask |= AC_ERR_ATA_BUS;
                        ap->hsm_task_state = HSM_ST_ERR;
                        return;
                }
@@ -3219,9 +3273,14 @@ static void ata_pio_error(struct ata_port *ap)
        qc = ata_qc_from_tag(ap, ap->active_tag);
        assert(qc != NULL);
 
+       /* 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;
 
-       ata_poll_qc_complete(qc, AC_ERR_ATA_BUS);
+       ata_poll_qc_complete(qc);
 }
 
 static void ata_pio_task(void *_data)
@@ -3323,7 +3382,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
                       ap->id, qc->tf.command, drv_stat, host_stat);
 
                /* 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;
        }
 
@@ -3422,7 +3482,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
        return qc;
 }
 
-int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask)
+int ata_qc_complete_noop(struct ata_queued_cmd *qc)
 {
        return 0;
 }
@@ -3481,7 +3541,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
  *     spin_lock_irqsave(host_set lock)
  */
 
-void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
+void ata_qc_complete(struct ata_queued_cmd *qc)
 {
        int rc;
 
@@ -3498,7 +3558,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
        qc->flags &= ~ATA_QCFLAG_ACTIVE;
 
        /* call completion callback */
-       rc = qc->complete_fn(qc, err_mask);
+       rc = qc->complete_fn(qc);
 
        /* if callback indicates not to complete command (non-zero),
         * return immediately
@@ -3936,7 +3996,8 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
                ap->ops->irq_clear(ap);
 
                /* complete taskfile transaction */
-               ata_qc_complete(qc, ac_err_mask(status));
+               qc->err_mask |= ac_err_mask(status);
+               ata_qc_complete(qc);
                break;
 
        default:
@@ -4030,13 +4091,17 @@ 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))
-               goto err_out_status;
+       if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
+               qc->err_mask |= AC_ERR_ATA_BUS;
+               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) {
+               qc->err_mask |= AC_ERR_ATA_BUS;
                goto err_out;
+       }
 
        /* send SCSI cdb */
        DPRINTK("send cdb\n");
@@ -4068,10 +4133,8 @@ static void atapi_packet_task(void *_data)
 
        return;
 
-err_out_status:
-       status = ata_chk_status(ap);
 err_out:
-       ata_poll_qc_complete(qc, __ac_err_mask(status));
+       ata_poll_qc_complete(qc);
 }