From cedc9a478d8c6265879dc3839ef3d4849a709184 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 07:13:30 -0400 Subject: libata: fix ATAPI DMA alignment issues ATAPI needs to be padded to next 4 byte boundary, if misaligned. Original work by me, many fixes from Tejun Heo. --- include/linux/libata.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'include/linux/libata.h') diff --git a/include/linux/libata.h b/include/linux/libata.h index ceee1fc42c60..3ab67622ef93 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -154,6 +154,10 @@ enum { ATA_SHIFT_UDMA = 0, ATA_SHIFT_MWDMA = 8, ATA_SHIFT_PIO = 11, + + /* size of buffer to pad xfers ending on unaligned boundaries */ + ATA_DMA_PAD_SZ = 4, + ATA_DMA_PAD_BUF_SZ = ATA_DMA_PAD_SZ * ATA_MAX_QUEUE, }; enum pio_task_states { @@ -237,9 +241,12 @@ struct ata_queued_cmd { unsigned long flags; /* ATA_QCFLAG_xxx */ unsigned int tag; unsigned int n_elem; + unsigned int orig_n_elem; int dma_dir; + unsigned int pad_len; + unsigned int nsect; unsigned int cursect; @@ -250,9 +257,11 @@ struct ata_queued_cmd { unsigned int cursg_ofs; struct scatterlist sgent; + struct scatterlist pad_sgent; void *buf_virt; - struct scatterlist *sg; + /* DO NOT iterate over __sg manually, use ata_for_each_sg() */ + struct scatterlist *__sg; ata_qc_cb_t complete_fn; @@ -295,6 +304,9 @@ struct ata_port { struct ata_prd *prd; /* our SG list */ dma_addr_t prd_dma; /* and its DMA mapping */ + void *pad; /* array of DMA pad buffers */ + dma_addr_t pad_dma; + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ u8 ctl; /* cache of ATA control register */ @@ -458,6 +470,19 @@ extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); #endif /* CONFIG_PCI */ +static inline struct scatterlist * +ata_qc_next_sg(struct scatterlist *sg, struct ata_queued_cmd *qc) +{ + if (sg == &qc->pad_sgent) + return NULL; + if (++sg - qc->__sg < qc->n_elem) + return sg; + return qc->pad_len ? &qc->pad_sgent : NULL; +} + +#define ata_for_each_sg(sg, qc) \ + for (sg = qc->__sg; sg; sg = ata_qc_next_sg(sg, qc)) + static inline unsigned int ata_tag_valid(unsigned int tag) { return (tag < ATA_MAX_QUEUE) ? 1 : 0; -- cgit v1.2.1 From 972c26bdd6b58e7534473c4f7928584578cf43f4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 18 Oct 2005 22:14:54 -0400 Subject: libata: add ata_sg_is_last() helper, use it in several drivers --- include/linux/libata.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include/linux/libata.h') diff --git a/include/linux/libata.h b/include/linux/libata.h index d3f58a796c3a..d3dfefefabec 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -480,6 +480,18 @@ extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); #endif /* CONFIG_PCI */ +static inline int +ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc) +{ + if (sg == &qc->pad_sgent) + return 1; + if (qc->pad_len) + return 0; + if (((sg - qc->__sg) + 1) == qc->n_elem) + return 1; + return 0; +} + static inline struct scatterlist * ata_qc_next_sg(struct scatterlist *sg, struct ata_queued_cmd *qc) { -- cgit v1.2.1 From 6037d6bbdff65eb5a84fe35e140f4da4f7cc103a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 4 Nov 2005 22:08:00 -0500 Subject: [libata] ATAPI pad allocation fixes/cleanup Use ata_pad_{alloc,free} in two drivers, to factor out common code. Add ata_pad_{alloc,free} to two other drivers, which needed the padding but had not been updated. --- include/linux/libata.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include/linux/libata.h') diff --git a/include/linux/libata.h b/include/linux/libata.h index 6225b78fa65b..dcd17e7458ab 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -777,4 +777,17 @@ static inline unsigned int __ac_err_mask(u8 status) return mask; } +static inline int ata_pad_alloc(struct ata_port *ap, struct device *dev) +{ + ap->pad_dma = 0; + ap->pad = dma_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ, + &ap->pad_dma, GFP_KERNEL); + return (ap->pad == NULL) ? -ENOMEM : 0; +} + +static inline void ata_pad_free(struct ata_port *ap, struct device *dev) +{ + dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); +} + #endif /* __LINUX_LIBATA_H__ */ -- cgit v1.2.1