summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlbert Lee2005-08-12 08:17:50 +0200
committerJeff Garzik2005-08-12 08:44:20 +0200
commit563a6e1fb0af58433beec1ab418e1fafbd100b56 (patch)
treedcf2145bbf63751722f694044fe547a7dab27d1f /drivers
parent[PATCH] libata ata_data_xfer() fix (diff)
downloadkernel-qcow2-linux-563a6e1fb0af58433beec1ab418e1fafbd100b56.tar.gz
kernel-qcow2-linux-563a6e1fb0af58433beec1ab418e1fafbd100b56.tar.xz
kernel-qcow2-linux-563a6e1fb0af58433beec1ab418e1fafbd100b56.zip
[PATCH] libata handle the case when device returns/needs extra data
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/libata-core.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 8f6e536d8924..9add4c521b6b 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2697,10 +2697,33 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
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:
+ 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;
@@ -2734,9 +2757,8 @@ next_sg:
kunmap(page);
- if (bytes) {
+ if (bytes)
goto next_sg;
- }
}
/**