]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/scsi/libata-core.c
[PATCH] libata kernel-doc fixes
[linux-2.6.git] / drivers / scsi / libata-core.c
index 8be7dc0b47b849858c8d5b37872e7112fb8e3b31..f1942545a20d6cb3134e243c9a4df5856f44e0c3 100644 (file)
@@ -51,8 +51,8 @@
 #include <linux/jiffies.h>
 #include <linux/scatterlist.h>
 #include <scsi/scsi.h>
-#include "scsi.h"
 #include "scsi_priv.h"
+#include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 #include <asm/io.h>
@@ -294,28 +294,6 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
                ata_exec_command_pio(ap, tf);
 }
 
-/**
- *     ata_exec - issue ATA command to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Issues PIO/MMIO write to ATA command register, with proper
- *     synchronization with interrupt handler / other threads.
- *
- *     LOCKING:
- *     Obtains host_set lock.
- */
-
-static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       unsigned long flags;
-
-       DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-       spin_lock_irqsave(&ap->host_set->lock, flags);
-       ap->ops->exec_command(ap, tf);
-       spin_unlock_irqrestore(&ap->host_set->lock, flags);
-}
-
 /**
  *     ata_tf_to_host - issue ATA taskfile to host controller
  *     @ap: port to which command is being issued
@@ -326,30 +304,11 @@ static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf)
  *     other threads.
  *
  *     LOCKING:
- *     Obtains host_set lock.
- */
-
-static void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       ap->ops->tf_load(ap, tf);
-
-       ata_exec(ap, tf);
-}
-
-/**
- *     ata_tf_to_host_nolock - issue ATA taskfile to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Issues ATA taskfile register set to ATA host controller,
- *     with proper synchronization with interrupt handler and
- *     other threads.
- *
- *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  */
 
-void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf)
+static inline void ata_tf_to_host(struct ata_port *ap,
+                                 const struct ata_taskfile *tf)
 {
        ap->ops->tf_load(ap, tf);
        ap->ops->exec_command(ap, tf);
@@ -1912,12 +1871,14 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
  *
  *     LOCKING:
  *     PCI/etc. bus probe sem.
+ *     Obtains host_set lock.
  *
  */
 
 static unsigned int ata_bus_edd(struct ata_port *ap)
 {
        struct ata_taskfile tf;
+       unsigned long flags;
 
        /* set up execute-device-diag (bus reset) taskfile */
        /* also, take interrupts to a known state (disabled) */
@@ -1928,7 +1889,9 @@ static unsigned int ata_bus_edd(struct ata_port *ap)
        tf.protocol = ATA_PROT_NODATA;
 
        /* do bus reset */
+       spin_lock_irqsave(&ap->host_set->lock, flags);
        ata_tf_to_host(ap, &tf);
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
        /* spec says at least 2ms.  but who knows with those
         * crazy ATAPI devices...
@@ -2427,8 +2390,9 @@ static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
 static void ata_sg_clean(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       struct scatterlist *sg = qc->sg;
+       struct scatterlist *sg = qc->__sg;
        int dir = qc->dma_dir;
+       void *pad_buf = NULL;
 
        assert(qc->flags & ATA_QCFLAG_DMAMAP);
        assert(sg != NULL);
@@ -2438,14 +2402,35 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
 
        DPRINTK("unmapping %u sg elements\n", qc->n_elem);
 
-       if (qc->flags & ATA_QCFLAG_SG)
+       /* if we padded the buffer out to 32-bit bound, and data
+        * xfer direction is from-device, we must copy from the
+        * pad buffer back into the supplied buffer
+        */
+       if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
+               pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+
+       if (qc->flags & ATA_QCFLAG_SG) {
                dma_unmap_sg(ap->host_set->dev, sg, qc->n_elem, dir);
-       else
+               /* restore last sg */
+               sg[qc->orig_n_elem - 1].length += qc->pad_len;
+               if (pad_buf) {
+                       struct scatterlist *psg = &qc->pad_sgent;
+                       void *addr = kmap_atomic(psg->page, KM_IRQ0);
+                       memcpy(addr + psg->offset, pad_buf, qc->pad_len);
+                       kunmap_atomic(psg->page, KM_IRQ0);
+               }
+       } else {
                dma_unmap_single(ap->host_set->dev, sg_dma_address(&sg[0]),
                                 sg_dma_len(&sg[0]), dir);
+               /* restore sg */
+               sg->length += qc->pad_len;
+               if (pad_buf)
+                       memcpy(qc->buf_virt + sg->length - qc->pad_len,
+                              pad_buf, qc->pad_len);
+       }
 
        qc->flags &= ~ATA_QCFLAG_DMAMAP;
-       qc->sg = NULL;
+       qc->__sg = NULL;
 }
 
 /**
@@ -2461,15 +2446,15 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
  */
 static void ata_fill_sg(struct ata_queued_cmd *qc)
 {
-       struct scatterlist *sg = qc->sg;
        struct ata_port *ap = qc->ap;
-       unsigned int idx, nelem;
+       struct scatterlist *sg;
+       unsigned int idx;
 
-       assert(sg != NULL);
+       assert(qc->__sg != NULL);
        assert(qc->n_elem > 0);
 
        idx = 0;
-       for (nelem = qc->n_elem; nelem; nelem--,sg++) {
+       ata_for_each_sg(sg, qc) {
                u32 addr, offset;
                u32 sg_len, len;
 
@@ -2555,12 +2540,18 @@ void ata_qc_prep(struct ata_queued_cmd *qc)
 
 void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
 {
+       struct scatterlist *sg;
+
        qc->flags |= ATA_QCFLAG_SINGLE;
 
-       qc->sg = &qc->sgent;
+       memset(&qc->sgent, 0, sizeof(qc->sgent));
+       qc->__sg = &qc->sgent;
        qc->n_elem = 1;
+       qc->orig_n_elem = 1;
        qc->buf_virt = buf;
-       sg_init_one(qc->sg, buf, buflen);
+
+       sg = qc->__sg;
+       sg_init_one(sg, buf, buflen);
 }
 
 /**
@@ -2581,8 +2572,9 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
                 unsigned int n_elem)
 {
        qc->flags |= ATA_QCFLAG_SG;
-       qc->sg = sg;
+       qc->__sg = sg;
        qc->n_elem = n_elem;
+       qc->orig_n_elem = n_elem;
 }
 
 /**
@@ -2602,13 +2594,39 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        int dir = qc->dma_dir;
-       struct scatterlist *sg = qc->sg;
+       struct scatterlist *sg = qc->__sg;
        dma_addr_t dma_address;
 
+       /* we must lengthen transfers to end on a 32-bit boundary */
+       qc->pad_len = sg->length & 3;
+       if (qc->pad_len) {
+               void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+               struct scatterlist *psg = &qc->pad_sgent;
+
+               assert(qc->dev->class == ATA_DEV_ATAPI);
+
+               memset(pad_buf, 0, ATA_DMA_PAD_SZ);
+
+               if (qc->tf.flags & ATA_TFLAG_WRITE)
+                       memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
+                              qc->pad_len);
+
+               sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
+               sg_dma_len(psg) = ATA_DMA_PAD_SZ;
+               /* trim sg */
+               sg->length -= qc->pad_len;
+
+               DPRINTK("padding done, sg->length=%u pad_len=%u\n",
+                       sg->length, qc->pad_len);
+       }
+
        dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt,
                                     sg->length, dir);
-       if (dma_mapping_error(dma_address))
+       if (dma_mapping_error(dma_address)) {
+               /* restore sg */
+               sg->length += qc->pad_len;
                return -1;
+       }
 
        sg_dma_address(sg) = dma_address;
        sg_dma_len(sg) = sg->length;
@@ -2636,16 +2654,54 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
 static int ata_sg_setup(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       struct scatterlist *sg = qc->sg;
+       struct scatterlist *sg = qc->__sg;
+       struct scatterlist *lsg = &sg[qc->n_elem - 1];
        int n_elem, dir;
 
        VPRINTK("ENTER, ata%u\n", ap->id);
        assert(qc->flags & ATA_QCFLAG_SG);
 
+       /* we must lengthen transfers to end on a 32-bit boundary */
+       qc->pad_len = lsg->length & 3;
+       if (qc->pad_len) {
+               void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+               struct scatterlist *psg = &qc->pad_sgent;
+               unsigned int offset;
+
+               assert(qc->dev->class == ATA_DEV_ATAPI);
+
+               memset(pad_buf, 0, ATA_DMA_PAD_SZ);
+
+               /*
+                * psg->page/offset are used to copy to-be-written
+                * data in this function or read data in ata_sg_clean.
+                */
+               offset = lsg->offset + lsg->length - qc->pad_len;
+               psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
+               psg->offset = offset_in_page(offset);
+
+               if (qc->tf.flags & ATA_TFLAG_WRITE) {
+                       void *addr = kmap_atomic(psg->page, KM_IRQ0);
+                       memcpy(pad_buf, addr + psg->offset, qc->pad_len);
+                       kunmap_atomic(psg->page, KM_IRQ0);
+               }
+
+               sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
+               sg_dma_len(psg) = ATA_DMA_PAD_SZ;
+               /* trim last sg */
+               lsg->length -= qc->pad_len;
+
+               DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
+                       qc->n_elem - 1, lsg->length, qc->pad_len);
+       }
+
        dir = qc->dma_dir;
        n_elem = dma_map_sg(ap->host_set->dev, sg, qc->n_elem, dir);
-       if (n_elem < 1)
+       if (n_elem < 1) {
+               /* restore last sg */
+               lsg->length += qc->pad_len;
                return -1;
+       }
 
        DPRINTK("%d sg elements mapped\n", n_elem);
 
@@ -2657,7 +2713,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
 /**
  *     ata_poll_qc_complete - turn irq back on and finish qc
  *     @qc: Command to complete
- *     @drv_stat: ATA status register content
+ *     @err_mask: ATA status register content
  *
  *     LOCKING:
  *     None.  (grabs host lock)
@@ -2917,7 +2973,7 @@ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
 static void ata_pio_sector(struct ata_queued_cmd *qc)
 {
        int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
-       struct scatterlist *sg = qc->sg;
+       struct scatterlist *sg = qc->__sg;
        struct ata_port *ap = qc->ap;
        struct page *page;
        unsigned int offset;
@@ -2967,7 +3023,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
 static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
 {
        int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
-       struct scatterlist *sg = qc->sg;
+       struct scatterlist *sg = qc->__sg;
        struct ata_port *ap = qc->ap;
        struct page *page;
        unsigned char *buf;
@@ -3000,7 +3056,7 @@ next_sg:
                return;
        }
 
-       sg = &qc->sg[qc->cursg];
+       sg = &qc->__sg[qc->cursg];
 
        page = sg->page;
        offset = sg->offset + qc->cursg_ofs;
@@ -3357,7 +3413,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
 
        qc = ata_qc_new(ap);
        if (qc) {
-               qc->sg = NULL;
+               qc->__sg = NULL;
                qc->flags = 0;
                qc->scsicmd = NULL;
                qc->ap = ap;
@@ -3422,7 +3478,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
 /**
  *     ata_qc_complete - Complete an active ATA command
  *     @qc: Command to complete
- *     @drv_stat: ATA Status register contents
+ *     @err_mask: ATA Status register contents
  *
  *     Indicate to the mid and upper layers that an ATA
  *     command has completed, with either an ok or not-ok status.
@@ -3555,7 +3611,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 
        switch (qc->tf.protocol) {
        case ATA_PROT_NODATA:
-               ata_tf_to_host_nolock(ap, &qc->tf);
+               ata_tf_to_host(ap, &qc->tf);
                break;
 
        case ATA_PROT_DMA:
@@ -3566,20 +3622,20 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 
        case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
                ata_qc_set_polling(qc);
-               ata_tf_to_host_nolock(ap, &qc->tf);
+               ata_tf_to_host(ap, &qc->tf);
                ap->hsm_task_state = HSM_ST;
                queue_work(ata_wq, &ap->pio_task);
                break;
 
        case ATA_PROT_ATAPI:
                ata_qc_set_polling(qc);
-               ata_tf_to_host_nolock(ap, &qc->tf);
+               ata_tf_to_host(ap, &qc->tf);
                queue_work(ata_wq, &ap->packet_task);
                break;
 
        case ATA_PROT_ATAPI_NODATA:
                ap->flags |= ATA_FLAG_NOINTR;
-               ata_tf_to_host_nolock(ap, &qc->tf);
+               ata_tf_to_host(ap, &qc->tf);
                queue_work(ata_wq, &ap->packet_task);
                break;
 
@@ -4041,11 +4097,18 @@ err_out:
 int ata_port_start (struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
+       int rc;
 
        ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
        if (!ap->prd)
                return -ENOMEM;
 
+       rc = ata_pad_alloc(ap, dev);
+       if (rc) {
+               dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+               return rc;
+       }
+
        DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
 
        return 0;
@@ -4069,6 +4132,7 @@ void ata_port_stop (struct ata_port *ap)
        struct device *dev = ap->host_set->dev;
 
        dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+       ata_pad_free(ap, dev);
 }
 
 void ata_host_stop (struct ata_host_set *host_set)
@@ -4126,8 +4190,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
        host->unique_id = ata_unique_id++;
        host->max_cmd_len = 12;
 
-       scsi_assign_lock(host, &host_set->lock);
-
        ap->flags = ATA_FLAG_PORT_DISABLED;
        ap->id = host->unique_id;
        ap->host = host;