[PATCH] libata handle the case when device returns/needs extra data
authorAlbert Lee <albertcc@tw.ibm.com>
Fri, 12 Aug 2005 06:17:50 +0000 (14:17 +0800)
committerJeff Garzik <jgarzik@pobox.com>
Fri, 12 Aug 2005 06:44:20 +0000 (02:44 -0400)
PATCH 2/2:  handle the case when device returns/needs extra data

Description:
   Sometimes the device returns/needs extra data than expected.

Changes:
   Modify __atapi_pio_bytes() to handle the case where device returns/needs extra data.
     - for read case, discard trailing data from the device
     - for write case, padding zero data to the device

Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
drivers/scsi/libata-core.c

index 8f6e536d89241a8e7558d32a586d77d8242adbab..9add4c521b6bc5a868cd3937fcd5625ae8b8ca86 100644 (file)
@@ -2697,10 +2697,33 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
        unsigned char *buf;
        unsigned int offset, count;
 
        unsigned char *buf;
        unsigned int offset, count;
 
-       if (qc->curbytes == qc->nbytes - bytes)
+       if (qc->curbytes + bytes >= qc->nbytes)
                ap->pio_task_state = PIO_ST_LAST;
 
 next_sg:
                ap->pio_task_state = PIO_ST_LAST;
 
 next_sg:
+       if (unlikely(qc->cursg >= qc->n_elem)) {
+               /* 
+                * The end of qc->sg is reached and the device expects
+                * more data to transfer. In order not to overrun qc->sg
+                * and fulfill length specified in the byte count register,
+                *    - for read case, discard trailing data from the device
+                *    - for write case, padding zero data to the device
+                */
+               u16 pad_buf[1] = { 0 };
+               unsigned int words = bytes >> 1;
+               unsigned int i;
+
+               if (words) /* warning if bytes > 1 */
+                       printk(KERN_WARNING "ata%u: %u bytes trailing data\n", 
+                              ap->id, bytes);
+
+               for (i = 0; i < words; i++)
+                       ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write);
+
+               ap->pio_task_state = PIO_ST_LAST;
+               return;
+       }
+
        sg = &qc->sg[qc->cursg];
 
        page = sg->page;
        sg = &qc->sg[qc->cursg];
 
        page = sg->page;
@@ -2734,9 +2757,8 @@ next_sg:
 
        kunmap(page);
 
 
        kunmap(page);
 
-       if (bytes) {
+       if (bytes)
                goto next_sg;
                goto next_sg;
-       }
 }
 
 /**
 }
 
 /**