diff options
author | Albert Lee | 2005-08-12 08:17:50 +0200 |
---|---|---|
committer | Jeff Garzik | 2005-08-12 08:44:20 +0200 |
commit | 563a6e1fb0af58433beec1ab418e1fafbd100b56 (patch) | |
tree | dcf2145bbf63751722f694044fe547a7dab27d1f /drivers/scsi | |
parent | [PATCH] libata ata_data_xfer() fix (diff) | |
download | kernel-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/scsi')
-rw-r--r-- | drivers/scsi/libata-core.c | 28 |
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; - } } /** |