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>
This commit is contained in:
parent
c1e6f28cc5
commit
d26fc9551a
@ -4102,6 +4102,68 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
|
|||||||
ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
|
ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_fill_sg_dumb - Fill PCI IDE PRD table
|
||||||
|
* @qc: Metadata associated with taskfile to be transferred
|
||||||
|
*
|
||||||
|
* Fill PCI IDE PRD (scatter-gather) table with segments
|
||||||
|
* associated with the current disk command. Perform the fill
|
||||||
|
* so that we avoid writing any length 64K records for
|
||||||
|
* controllers that don't follow the spec.
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* spin_lock_irqsave(host lock)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
|
||||||
|
{
|
||||||
|
struct ata_port *ap = qc->ap;
|
||||||
|
struct scatterlist *sg;
|
||||||
|
unsigned int idx;
|
||||||
|
|
||||||
|
WARN_ON(qc->__sg == NULL);
|
||||||
|
WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
ata_for_each_sg(sg, qc) {
|
||||||
|
u32 addr, offset;
|
||||||
|
u32 sg_len, len, blen;
|
||||||
|
|
||||||
|
/* determine if physical DMA addr spans 64K boundary.
|
||||||
|
* Note h/w doesn't support 64-bit, so we unconditionally
|
||||||
|
* truncate dma_addr_t to u32.
|
||||||
|
*/
|
||||||
|
addr = (u32) sg_dma_address(sg);
|
||||||
|
sg_len = sg_dma_len(sg);
|
||||||
|
|
||||||
|
while (sg_len) {
|
||||||
|
offset = addr & 0xffff;
|
||||||
|
len = sg_len;
|
||||||
|
if ((offset + sg_len) > 0x10000)
|
||||||
|
len = 0x10000 - offset;
|
||||||
|
|
||||||
|
blen = len & 0xffff;
|
||||||
|
ap->prd[idx].addr = cpu_to_le32(addr);
|
||||||
|
if (blen == 0) {
|
||||||
|
/* Some PATA chipsets like the CS5530 can't
|
||||||
|
cope with 0x0000 meaning 64K as the spec says */
|
||||||
|
ap->prd[idx].flags_len = cpu_to_le32(0x8000);
|
||||||
|
blen = 0x8000;
|
||||||
|
ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000);
|
||||||
|
}
|
||||||
|
ap->prd[idx].flags_len = cpu_to_le32(blen);
|
||||||
|
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
sg_len -= len;
|
||||||
|
addr += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx)
|
||||||
|
ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_check_atapi_dma - Check whether ATAPI DMA can be supported
|
* ata_check_atapi_dma - Check whether ATAPI DMA can be supported
|
||||||
* @qc: Metadata associated with taskfile to check
|
* @qc: Metadata associated with taskfile to check
|
||||||
@ -4149,6 +4211,23 @@ void ata_qc_prep(struct ata_queued_cmd *qc)
|
|||||||
ata_fill_sg(qc);
|
ata_fill_sg(qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_dumb_qc_prep - Prepare taskfile for submission
|
||||||
|
* @qc: Metadata associated with taskfile to be prepared
|
||||||
|
*
|
||||||
|
* Prepare ATA taskfile for submission.
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* spin_lock_irqsave(host lock)
|
||||||
|
*/
|
||||||
|
void ata_dumb_qc_prep(struct ata_queued_cmd *qc)
|
||||||
|
{
|
||||||
|
if (!(qc->flags & ATA_QCFLAG_DMAMAP))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ata_fill_sg_dumb(qc);
|
||||||
|
}
|
||||||
|
|
||||||
void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
|
void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -6821,6 +6900,7 @@ EXPORT_SYMBOL_GPL(ata_do_set_mode);
|
|||||||
EXPORT_SYMBOL_GPL(ata_data_xfer);
|
EXPORT_SYMBOL_GPL(ata_data_xfer);
|
||||||
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
|
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
|
||||||
EXPORT_SYMBOL_GPL(ata_qc_prep);
|
EXPORT_SYMBOL_GPL(ata_qc_prep);
|
||||||
|
EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
|
||||||
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
|
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
|
||||||
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
|
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
|
||||||
EXPORT_SYMBOL_GPL(ata_bmdma_start);
|
EXPORT_SYMBOL_GPL(ata_bmdma_start);
|
||||||
|
@ -2620,7 +2620,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
|
|||||||
ata_dev_printk(dev, KERN_WARNING,
|
ata_dev_printk(dev, KERN_WARNING,
|
||||||
"invalid multi_count %u ignored\n",
|
"invalid multi_count %u ignored\n",
|
||||||
multi_count);
|
multi_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* READ/WRITE LONG use a non-standard sect_size */
|
/* READ/WRITE LONG use a non-standard sect_size */
|
||||||
qc->sect_size = ATA_SECT_SIZE;
|
qc->sect_size = ATA_SECT_SIZE;
|
||||||
|
@ -146,7 +146,7 @@ static struct scsi_host_template cs5520_sht = {
|
|||||||
.queuecommand = ata_scsi_queuecmd,
|
.queuecommand = ata_scsi_queuecmd,
|
||||||
.can_queue = ATA_DEF_QUEUE,
|
.can_queue = ATA_DEF_QUEUE,
|
||||||
.this_id = ATA_SHT_THIS_ID,
|
.this_id = ATA_SHT_THIS_ID,
|
||||||
.sg_tablesize = LIBATA_MAX_PRD,
|
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
|
||||||
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
||||||
.emulated = ATA_SHT_EMULATED,
|
.emulated = ATA_SHT_EMULATED,
|
||||||
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
||||||
@ -178,7 +178,7 @@ static struct ata_port_operations cs5520_port_ops = {
|
|||||||
.bmdma_start = ata_bmdma_start,
|
.bmdma_start = ata_bmdma_start,
|
||||||
.bmdma_stop = ata_bmdma_stop,
|
.bmdma_stop = ata_bmdma_stop,
|
||||||
.bmdma_status = ata_bmdma_status,
|
.bmdma_status = ata_bmdma_status,
|
||||||
.qc_prep = ata_qc_prep,
|
.qc_prep = ata_dumb_qc_prep,
|
||||||
.qc_issue = ata_qc_issue_prot,
|
.qc_issue = ata_qc_issue_prot,
|
||||||
.data_xfer = ata_data_xfer,
|
.data_xfer = ata_data_xfer,
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ static struct scsi_host_template cs5530_sht = {
|
|||||||
.queuecommand = ata_scsi_queuecmd,
|
.queuecommand = ata_scsi_queuecmd,
|
||||||
.can_queue = ATA_DEF_QUEUE,
|
.can_queue = ATA_DEF_QUEUE,
|
||||||
.this_id = ATA_SHT_THIS_ID,
|
.this_id = ATA_SHT_THIS_ID,
|
||||||
.sg_tablesize = LIBATA_MAX_PRD,
|
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
|
||||||
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
||||||
.emulated = ATA_SHT_EMULATED,
|
.emulated = ATA_SHT_EMULATED,
|
||||||
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
||||||
@ -201,7 +201,7 @@ static struct ata_port_operations cs5530_port_ops = {
|
|||||||
.post_internal_cmd = ata_bmdma_post_internal_cmd,
|
.post_internal_cmd = ata_bmdma_post_internal_cmd,
|
||||||
.cable_detect = ata_cable_40wire,
|
.cable_detect = ata_cable_40wire,
|
||||||
|
|
||||||
.qc_prep = ata_qc_prep,
|
.qc_prep = ata_dumb_qc_prep,
|
||||||
.qc_issue = cs5530_qc_issue_prot,
|
.qc_issue = cs5530_qc_issue_prot,
|
||||||
|
|
||||||
.data_xfer = ata_data_xfer,
|
.data_xfer = ata_data_xfer,
|
||||||
|
@ -185,7 +185,7 @@ static struct scsi_host_template sc1200_sht = {
|
|||||||
.queuecommand = ata_scsi_queuecmd,
|
.queuecommand = ata_scsi_queuecmd,
|
||||||
.can_queue = ATA_DEF_QUEUE,
|
.can_queue = ATA_DEF_QUEUE,
|
||||||
.this_id = ATA_SHT_THIS_ID,
|
.this_id = ATA_SHT_THIS_ID,
|
||||||
.sg_tablesize = LIBATA_MAX_PRD,
|
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
|
||||||
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
||||||
.emulated = ATA_SHT_EMULATED,
|
.emulated = ATA_SHT_EMULATED,
|
||||||
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
||||||
@ -219,7 +219,7 @@ static struct ata_port_operations sc1200_port_ops = {
|
|||||||
.bmdma_stop = ata_bmdma_stop,
|
.bmdma_stop = ata_bmdma_stop,
|
||||||
.bmdma_status = ata_bmdma_status,
|
.bmdma_status = ata_bmdma_status,
|
||||||
|
|
||||||
.qc_prep = ata_qc_prep,
|
.qc_prep = ata_dumb_qc_prep,
|
||||||
.qc_issue = sc1200_qc_issue_prot,
|
.qc_issue = sc1200_qc_issue_prot,
|
||||||
|
|
||||||
.data_xfer = ata_data_xfer,
|
.data_xfer = ata_data_xfer,
|
||||||
|
@ -116,6 +116,7 @@ static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
|
|||||||
enum {
|
enum {
|
||||||
/* various global constants */
|
/* various global constants */
|
||||||
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
|
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
|
||||||
|
LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, /* Worst case */
|
||||||
ATA_MAX_PORTS = 8,
|
ATA_MAX_PORTS = 8,
|
||||||
ATA_DEF_QUEUE = 1,
|
ATA_DEF_QUEUE = 1,
|
||||||
/* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */
|
/* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */
|
||||||
@ -778,6 +779,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
|
|||||||
unsigned int buflen, int write_data);
|
unsigned int buflen, int write_data);
|
||||||
extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
|
extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
|
||||||
unsigned int buflen, int write_data);
|
unsigned int buflen, int write_data);
|
||||||
|
extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc);
|
||||||
extern void ata_qc_prep(struct ata_queued_cmd *qc);
|
extern void ata_qc_prep(struct ata_queued_cmd *qc);
|
||||||
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
|
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
|
||||||
extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
|
extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
|
||||||
|
Loading…
Reference in New Issue
Block a user