]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - include/linux/libata.h
Merge rsync://bughost.org/repos/ieee80211-delta/
[linux-2.6-omap-h63xx.git] / include / linux / libata.h
index 0ba3af7a1236f448ac886878398da323d559309b..dcd17e7458ab602684db8cc965006267969e028f 100644 (file)
@@ -155,6 +155,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,
        
        /* Masks for port functions */
        ATA_PORT_PRIMARY        = (1 << 0),
@@ -249,9 +253,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;
 
@@ -262,9 +269,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;
 
@@ -310,6 +319,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 */
@@ -512,6 +524,31 @@ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bit
 #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)
+{
+       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;
@@ -740,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__ */