diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2007-07-06 19:13:52 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-07-09 12:17:35 -0400 |
commit | d26fc9551a15fdad0d5de8376a78816b8af44f00 (patch) | |
tree | 5c829c1baf499ad1f31ed4b8b41e766b290a6306 /drivers/ata/libata-core.c | |
parent | c1e6f28cc5de37dcd113b9668a185c0b9334ba8a (diff) |
libata: Support chips with 64K PRD quirk
Add ata_dumb_qc_prep and supporting logic so that a driver can just
specify it needs to be helped in this area. 64K entries are split
as with drivers/ide.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 74c4cd9ad82..5b25311ba88 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -4103,6 +4103,68 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) | |||
4103 | } | 4103 | } |
4104 | 4104 | ||
4105 | /** | 4105 | /** |
4106 | * ata_fill_sg_dumb - Fill PCI IDE PRD table | ||
4107 | * @qc: Metadata associated with taskfile to be transferred | ||
4108 | * | ||
4109 | * Fill PCI IDE PRD (scatter-gather) table with segments | ||
4110 | * associated with the current disk command. Perform the fill | ||
4111 | * so that we avoid writing any length 64K records for | ||
4112 | * controllers that don't follow the spec. | ||
4113 | * | ||
4114 | * LOCKING: | ||
4115 | * spin_lock_irqsave(host lock) | ||
4116 | * | ||
4117 | */ | ||
4118 | static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) | ||
4119 | { | ||
4120 | struct ata_port *ap = qc->ap; | ||
4121 | struct scatterlist *sg; | ||
4122 | unsigned int idx; | ||
4123 | |||
4124 | WARN_ON(qc->__sg == NULL); | ||
4125 | WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); | ||
4126 | |||
4127 | idx = 0; | ||
4128 | ata_for_each_sg(sg, qc) { | ||
4129 | u32 addr, offset; | ||
4130 | u32 sg_len, len, blen; | ||
4131 | |||
4132 | /* determine if physical DMA addr spans 64K boundary. | ||
4133 | * Note h/w doesn't support 64-bit, so we unconditionally | ||
4134 | * truncate dma_addr_t to u32. | ||
4135 | */ | ||
4136 | addr = (u32) sg_dma_address(sg); | ||
4137 | sg_len = sg_dma_len(sg); | ||
4138 | |||
4139 | while (sg_len) { | ||
4140 | offset = addr & 0xffff; | ||
4141 | len = sg_len; | ||
4142 | if ((offset + sg_len) > 0x10000) | ||
4143 | len = 0x10000 - offset; | ||
4144 | |||
4145 | blen = len & 0xffff; | ||
4146 | ap->prd[idx].addr = cpu_to_le32(addr); | ||
4147 | if (blen == 0) { | ||
4148 | /* Some PATA chipsets like the CS5530 can't | ||
4149 | cope with 0x0000 meaning 64K as the spec says */ | ||
4150 | ap->prd[idx].flags_len = cpu_to_le32(0x8000); | ||
4151 | blen = 0x8000; | ||
4152 | ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000); | ||
4153 | } | ||
4154 | ap->prd[idx].flags_len = cpu_to_le32(blen); | ||
4155 | VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); | ||
4156 | |||
4157 | idx++; | ||
4158 | sg_len -= len; | ||
4159 | addr += len; | ||
4160 | } | ||
4161 | } | ||
4162 | |||
4163 | if (idx) | ||
4164 | ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); | ||
4165 | } | ||
4166 | |||
4167 | /** | ||
4106 | * ata_check_atapi_dma - Check whether ATAPI DMA can be supported | 4168 | * ata_check_atapi_dma - Check whether ATAPI DMA can be supported |
4107 | * @qc: Metadata associated with taskfile to check | 4169 | * @qc: Metadata associated with taskfile to check |
4108 | * | 4170 | * |
@@ -4149,6 +4211,23 @@ void ata_qc_prep(struct ata_queued_cmd *qc) | |||
4149 | ata_fill_sg(qc); | 4211 | ata_fill_sg(qc); |
4150 | } | 4212 | } |
4151 | 4213 | ||
4214 | /** | ||
4215 | * ata_dumb_qc_prep - Prepare taskfile for submission | ||
4216 | * @qc: Metadata associated with taskfile to be prepared | ||
4217 | * | ||
4218 | * Prepare ATA taskfile for submission. | ||
4219 | * | ||
4220 | * LOCKING: | ||
4221 | * spin_lock_irqsave(host lock) | ||
4222 | */ | ||
4223 | void ata_dumb_qc_prep(struct ata_queued_cmd *qc) | ||
4224 | { | ||
4225 | if (!(qc->flags & ATA_QCFLAG_DMAMAP)) | ||
4226 | return; | ||
4227 | |||
4228 | ata_fill_sg_dumb(qc); | ||
4229 | } | ||
4230 | |||
4152 | void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } | 4231 | void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } |
4153 | 4232 | ||
4154 | /** | 4233 | /** |
@@ -6821,6 +6900,7 @@ EXPORT_SYMBOL_GPL(ata_do_set_mode); | |||
6821 | EXPORT_SYMBOL_GPL(ata_data_xfer); | 6900 | EXPORT_SYMBOL_GPL(ata_data_xfer); |
6822 | EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); | 6901 | EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); |
6823 | EXPORT_SYMBOL_GPL(ata_qc_prep); | 6902 | EXPORT_SYMBOL_GPL(ata_qc_prep); |
6903 | EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); | ||
6824 | EXPORT_SYMBOL_GPL(ata_noop_qc_prep); | 6904 | EXPORT_SYMBOL_GPL(ata_noop_qc_prep); |
6825 | EXPORT_SYMBOL_GPL(ata_bmdma_setup); | 6905 | EXPORT_SYMBOL_GPL(ata_bmdma_setup); |
6826 | EXPORT_SYMBOL_GPL(ata_bmdma_start); | 6906 | EXPORT_SYMBOL_GPL(ata_bmdma_start); |