[PATCH] libata: Fix the HSM error_mask mapping (was: Re: libata-tj and SMART)
authorAlbert Lee <albertcc@tw.ibm.com>
Fri, 19 May 2006 03:43:04 +0000 (11:43 +0800)
committerJeff Garzik <jeff@garzik.org>
Sat, 20 May 2006 04:37:01 +0000 (00:37 -0400)
Fix the HSM error_mask mapping.

Changes:
- Better mapping in ac_err_mask()
- In HSM_ST_FIRST ans HSM_ST state, check ATA_ERR|ATA_DF and map it to AC_ERR_DEV instead of AC_ERR_HSM.
- In HSM_ST_FIRST and HSM_ST state, map DRQ=1 ERR=1 to AC_ERR_HSM.
- For PIO data in and DRQ=1 ERR=1, add check after the junk data block is read.

Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/scsi/libata-core.c
include/linux/libata.h

index 00881226f8dd789624a955c5c910f018f8ce8e6c..aa38ed3e59a8e55743780ff86324371236a76e26 100644 (file)
@@ -4009,9 +4009,15 @@ fsm_start:
                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 */
-                       qc->err_mask |= AC_ERR_HSM;
+               if (unlikely((status & ATA_DRQ) == 0)) {
+                       /* handle BSY=0, DRQ=0 as error */
+                       if (likely(status & (ATA_ERR | ATA_DF)))
+                               /* device stops HSM for abort/error */
+                               qc->err_mask |= AC_ERR_DEV;
+                       else
+                               /* HSM violation. Let EH handle this */
+                               qc->err_mask |= AC_ERR_HSM;
+
                        ap->hsm_task_state = HSM_ST_ERR;
                        goto fsm_start;
                }
@@ -4025,7 +4031,7 @@ fsm_start:
                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;
+                       qc->err_mask |= AC_ERR_HSM;
                        ap->hsm_task_state = HSM_ST_ERR;
                        goto fsm_start;
                }
@@ -4067,7 +4073,9 @@ fsm_start:
                if (qc->tf.protocol == ATA_PROT_ATAPI) {
                        /* ATAPI PIO protocol */
                        if ((status & ATA_DRQ) == 0) {
-                               /* no more data to transfer */
+                               /* No more data to transfer or device error.
+                                * Device error will be tagged in HSM_ST_LAST.
+                                */
                                ap->hsm_task_state = HSM_ST_LAST;
                                goto fsm_start;
                        }
@@ -4081,7 +4089,7 @@ fsm_start:
                        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;
+                               qc->err_mask |= AC_ERR_HSM;
                                ap->hsm_task_state = HSM_ST_ERR;
                                goto fsm_start;
                        }
@@ -4096,7 +4104,13 @@ fsm_start:
                        /* ATA PIO protocol */
                        if (unlikely((status & ATA_DRQ) == 0)) {
                                /* handle BSY=0, DRQ=0 as error */
-                               qc->err_mask |= AC_ERR_HSM;
+                               if (likely(status & (ATA_ERR | ATA_DF)))
+                                       /* device stops HSM for abort/error */
+                                       qc->err_mask |= AC_ERR_DEV;
+                               else
+                                       /* HSM violation. Let EH handle this */
+                                       qc->err_mask |= AC_ERR_HSM;
+
                                ap->hsm_task_state = HSM_ST_ERR;
                                goto fsm_start;
                        }
@@ -4121,6 +4135,9 @@ fsm_start:
                                        status = ata_wait_idle(ap);
                                }
 
+                               if (status & (ATA_BUSY | ATA_DRQ))
+                                       qc->err_mask |= AC_ERR_HSM;
+
                                /* ata_pio_sectors() might change the
                                 * state to HSM_ST_LAST. so, the state
                                 * is changed after ata_pio_sectors().
index 2803ab8e92438453b725fce570d8afb3808ab797..c51502c047a4c5b78a89240a7ea31a5e5eecc7b4 100644 (file)
@@ -1062,7 +1062,7 @@ static inline int ata_try_flush_cache(const struct ata_device *dev)
 
 static inline unsigned int ac_err_mask(u8 status)
 {
-       if (status & ATA_BUSY)
+       if (status & (ATA_BUSY | ATA_DRQ))
                return AC_ERR_HSM;
        if (status & (ATA_ERR | ATA_DF))
                return AC_ERR_DEV;