diff options
author | Albert Lee <albertcc@tw.ibm.com> | 2005-08-12 02:17:50 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-12 02:44:20 -0400 |
commit | 563a6e1fb0af58433beec1ab418e1fafbd100b56 (patch) | |
tree | dcf2145bbf63751722f694044fe547a7dab27d1f /drivers/scsi | |
parent | 6ae4cfb5711b6f2878c9e384617971d98c34a7f5 (diff) |
[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) | |||
2697 | unsigned char *buf; | 2697 | unsigned char *buf; |
2698 | unsigned int offset, count; | 2698 | unsigned int offset, count; |
2699 | 2699 | ||
2700 | if (qc->curbytes == qc->nbytes - bytes) | 2700 | if (qc->curbytes + bytes >= qc->nbytes) |
2701 | ap->pio_task_state = PIO_ST_LAST; | 2701 | ap->pio_task_state = PIO_ST_LAST; |
2702 | 2702 | ||
2703 | next_sg: | 2703 | next_sg: |
2704 | if (unlikely(qc->cursg >= qc->n_elem)) { | ||
2705 | /* | ||
2706 | * The end of qc->sg is reached and the device expects | ||
2707 | * more data to transfer. In order not to overrun qc->sg | ||
2708 | * and fulfill length specified in the byte count register, | ||
2709 | * - for read case, discard trailing data from the device | ||
2710 | * - for write case, padding zero data to the device | ||
2711 | */ | ||
2712 | u16 pad_buf[1] = { 0 }; | ||
2713 | unsigned int words = bytes >> 1; | ||
2714 | unsigned int i; | ||
2715 | |||
2716 | if (words) /* warning if bytes > 1 */ | ||
2717 | printk(KERN_WARNING "ata%u: %u bytes trailing data\n", | ||
2718 | ap->id, bytes); | ||
2719 | |||
2720 | for (i = 0; i < words; i++) | ||
2721 | ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); | ||
2722 | |||
2723 | ap->pio_task_state = PIO_ST_LAST; | ||
2724 | return; | ||
2725 | } | ||
2726 | |||
2704 | sg = &qc->sg[qc->cursg]; | 2727 | sg = &qc->sg[qc->cursg]; |
2705 | 2728 | ||
2706 | page = sg->page; | 2729 | page = sg->page; |
@@ -2734,9 +2757,8 @@ next_sg: | |||
2734 | 2757 | ||
2735 | kunmap(page); | 2758 | kunmap(page); |
2736 | 2759 | ||
2737 | if (bytes) { | 2760 | if (bytes) |
2738 | goto next_sg; | 2761 | goto next_sg; |
2739 | } | ||
2740 | } | 2762 | } |
2741 | 2763 | ||
2742 | /** | 2764 | /** |