summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-12-05 10:43:07 +0300
committerJeff Garzik <jeff@garzik.org>2008-01-23 13:24:14 +0300
commit55dba3120fbcbea6800f9a18503d25f73212a347 (patch)
tree1b23e606aad8bc58dbe68ca905c0658625fb176e
parentceb0c642624f634c5b4f46b0e22df19be87a2e53 (diff)
downloadlinux-55dba3120fbcbea6800f9a18503d25f73212a347.tar.xz
libata: update ->data_xfer hook for ATAPI
Depending on how many bytes are transferred as a unit, PIO data transfer may consume more bytes than requested. Knowing how much data is consumed is necessary to determine how much is left for draining. This patch update ->data_xfer such that it returns the number of consumed bytes. While at it, it also makes the following changes. * s/adev/dev/ * use READ/WRITE constants for rw indication * misc clean ups Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/libata-core.c46
-rw-r--r--drivers/ata/pata_bf54x.c28
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c26
-rw-r--r--drivers/ata/pata_legacy.c36
-rw-r--r--drivers/ata/pata_qdi.c30
-rw-r--r--drivers/ata/pata_scc.c30
-rw-r--r--drivers/ata/pata_winbond.c28
-rw-r--r--include/linux/libata.h11
8 files changed, 133 insertions, 102 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 2c9745a74d50..39cedd949ed4 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4994,7 +4994,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
/**
* ata_data_xfer - Transfer data by PIO
- * @adev: device to target
+ * @dev: device to target
* @buf: data buffer
* @buflen: buffer length
* @write_data: read/write
@@ -5003,37 +5003,44 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
*
* LOCKING:
* Inherited from caller.
+ *
+ * RETURNS:
+ * Bytes consumed.
*/
-void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
- struct ata_port *ap = adev->link->ap;
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
- if (write_data)
- iowrite16_rep(ap->ioaddr.data_addr, buf, words);
+ if (rw == READ)
+ ioread16_rep(data_addr, buf, words);
else
- ioread16_rep(ap->ioaddr.data_addr, buf, words);
+ iowrite16_rep(data_addr, buf, words);
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
- } else {
- align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr));
+ if (rw == READ) {
+ align_buf[0] = cpu_to_le16(ioread16(data_addr));
memcpy(trailing_buf, align_buf, 1);
+ } else {
+ memcpy(align_buf, trailing_buf, 1);
+ iowrite16(le16_to_cpu(align_buf[0]), data_addr);
}
+ words++;
}
+
+ return words << 1;
}
/**
* ata_data_xfer_noirq - Transfer data by PIO
- * @adev: device to target
+ * @dev: device to target
* @buf: data buffer
* @buflen: buffer length
* @write_data: read/write
@@ -5043,14 +5050,21 @@ void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
*
* LOCKING:
* Inherited from caller.
+ *
+ * RETURNS:
+ * Bytes consumed.
*/
-void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
unsigned long flags;
+ unsigned int consumed;
+
local_irq_save(flags);
- ata_data_xfer(adev, buf, buflen, write_data);
+ consumed = ata_data_xfer(dev, buf, buflen, rw);
local_irq_restore(flags);
+
+ return consumed;
}
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 7842cc487359..41cd921082ba 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1167,34 +1167,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
* Note: Original code is ata_data_xfer().
*/
-static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
- struct ata_port *ap = adev->link->ap;
- unsigned int words = buflen >> 1;
- unsigned short *buf16 = (u16 *) buf;
+ struct ata_port *ap = dev->link->ap;
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int words = buflen >> 1;
+ unsigned short *buf16 = (u16 *)buf;
/* Transfer multiple of 2 bytes */
- if (write_data) {
- write_atapi_data(base, words, buf16);
- } else {
+ if (rw == READ)
read_atapi_data(base, words, buf16);
- }
+ else
+ write_atapi_data(base, words, buf16);
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
unsigned short align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- write_atapi_data(base, 1, align_buf);
- } else {
+ if (rw == READ) {
read_atapi_data(base, 1, align_buf);
memcpy(trailing_buf, align_buf, 1);
+ } else {
+ memcpy(align_buf, trailing_buf, 1);
+ write_atapi_data(base, 1, align_buf);
}
+ words++;
}
+
+ return words << 1;
}
/**
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 120b5bfa7ce6..030878fedeb5 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
return 0;
}
-static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
+ unsigned char *buf, unsigned int buflen, int rw)
{
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
- struct ata_port *ap = adev->link->ap;
+ struct ata_port *ap = dev->link->ap;
void __iomem *mmio = ap->ioaddr.data_addr;
struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
@@ -59,30 +59,32 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
udelay(100);
/* Transfer multiple of 2 bytes */
- if (write_data) {
- for (i = 0; i < words; i++)
- writew(buf16[i], mmio);
- } else {
+ if (rw == READ)
for (i = 0; i < words; i++)
buf16[i] = readw(mmio);
- }
+ else
+ for (i = 0; i < words; i++)
+ writew(buf16[i], mmio);
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- writew(align_buf[0], mmio);
- } else {
+ if (rw == READ) {
align_buf[0] = readw(mmio);
memcpy(trailing_buf, align_buf, 1);
+ } else {
+ memcpy(align_buf, trailing_buf, 1);
+ writew(align_buf[0], mmio);
}
+ words++;
}
udelay(100);
*data->cs0_cfg |= 0x01;
+
+ return words << 1;
}
static struct scsi_host_template ixp4xx_sht = {
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 17159b5e1e43..dae85aa12e32 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -249,13 +249,14 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
-static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
+ unsigned char *buf, unsigned int buflen, int rw)
{
- struct ata_port *ap = adev->link->ap;
- int slop = buflen & 3;
- unsigned long flags;
-
if (ata_id_has_dword_io(adev->id)) {
+ struct ata_port *ap = dev->link->ap;
+ int slop = buflen & 3;
+ unsigned long flags;
+
local_irq_save(flags);
/* Perform the 32bit I/O synchronization sequence */
@@ -264,26 +265,27 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
ioread8(ap->ioaddr.nsect_addr);
/* Now the data */
-
- if (write_data)
- iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
- else
+ if (rw == READ)
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
- __le32 pad = 0;
- if (write_data) {
- memcpy(&pad, buf + buflen - slop, slop);
- iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
- } else {
+ u32 pad;
+ if (rw == READ) {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop);
+ } else {
+ memcpy(&pad, buf + buflen - slop, slop);
+ iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
}
+ buflen += 4 - slop;
}
local_irq_restore(flags);
- }
- else
- ata_data_xfer_noirq(adev, buf, buflen, write_data);
+ } else
+ buflen = ata_data_xfer_noirq(dev, buf, buflen, rw);
+
+ return buflen;
}
static struct ata_port_operations pdc20230_port_ops = {
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index a4c0e502cb42..9f308ed76cc8 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -124,29 +124,33 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
-static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
- struct ata_port *ap = adev->link->ap;
- int slop = buflen & 3;
+ if (ata_id_has_dword_io(dev->id)) {
+ struct ata_port *ap = dev->link->ap;
+ int slop = buflen & 3;
- if (ata_id_has_dword_io(adev->id)) {
- if (write_data)
- iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
- else
+ if (rw == READ)
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
- __le32 pad = 0;
- if (write_data) {
- memcpy(&pad, buf + buflen - slop, slop);
- iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
- } else {
+ u32 pad;
+ if (rw == READ) {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop);
+ } else {
+ memcpy(&pad, buf + buflen - slop, slop);
+ iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
}
+ buflen += 4 - slop;
}
} else
- ata_data_xfer(adev, buf, buflen, write_data);
+ buflen = ata_data_xfer(dev, buf, buflen, rw);
+
+ return buflen;
}
static struct scsi_host_template qdi_sht = {
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index ea2ef9fc15be..55055b27524c 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -768,45 +768,47 @@ static u8 scc_bmdma_status (struct ata_port *ap)
/**
* scc_data_xfer - Transfer data by PIO
- * @adev: device for this I/O
+ * @dev: device for this I/O
* @buf: data buffer
* @buflen: buffer length
- * @write_data: read/write
+ * @rw: read/write
*
* Note: Original code is ata_data_xfer().
*/
-static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
- struct ata_port *ap = adev->link->ap;
+ struct ata_port *ap = dev->link->ap;
unsigned int words = buflen >> 1;
unsigned int i;
u16 *buf16 = (u16 *) buf;
void __iomem *mmio = ap->ioaddr.data_addr;
/* Transfer multiple of 2 bytes */
- if (write_data) {
- for (i = 0; i < words; i++)
- out_be32(mmio, cpu_to_le16(buf16[i]));
- } else {
+ if (rw == READ)
for (i = 0; i < words; i++)
buf16[i] = le16_to_cpu(in_be32(mmio));
- }
+ else
+ for (i = 0; i < words; i++)
+ out_be32(mmio, cpu_to_le16(buf16[i]));
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- out_be32(mmio, cpu_to_le16(align_buf[0]));
- } else {
+ if (rw == READ) {
align_buf[0] = le16_to_cpu(in_be32(mmio));
memcpy(trailing_buf, align_buf, 1);
+ } else {
+ memcpy(align_buf, trailing_buf, 1);
+ out_be32(mmio, cpu_to_le16(align_buf[0]));
}
+ words++;
}
+
+ return words << 1;
}
/**
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 7116a9e7a8b2..7312e9182d69 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -92,29 +92,33 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
-static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static void winbond_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
- struct ata_port *ap = adev->link->ap;
+ struct ata_port *ap = dev->link->ap;
int slop = buflen & 3;
- if (ata_id_has_dword_io(adev->id)) {
- if (write_data)
- iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
- else
+ if (ata_id_has_dword_io(dev->id)) {
+ if (rw == READ)
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
- __le32 pad = 0;
- if (write_data) {
- memcpy(&pad, buf + buflen - slop, slop);
- iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
- } else {
+ u32 pad;
+ if (rw == READ) {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop);
+ } else {
+ memcpy(&pad, buf + buflen - slop, slop);
+ iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
}
+ buflen += 4 - slop;
}
} else
- ata_data_xfer(adev, buf, buflen, write_data);
+ buflen = ata_data_xfer(dev, buf, buflen, rw);
+
+ return buflen;
}
static struct scsi_host_template winbond_sht = {
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 03afcd63202d..7fa96cb4f6db 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -701,7 +701,8 @@ struct ata_port_operations {
void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (struct ata_queued_cmd *qc);
- void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+ unsigned int (*data_xfer) (struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw);
int (*qc_defer) (struct ata_queued_cmd *qc);
void (*qc_prep) (struct ata_queued_cmd *qc);
@@ -881,10 +882,10 @@ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
extern int ata_port_start(struct ata_port *ap);
extern int ata_sff_port_start(struct ata_port *ap);
extern irqreturn_t ata_interrupt(int irq, void *dev_instance);
-extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data);
-extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data);
+extern unsigned int ata_data_xfer(struct ata_device *dev,
+ unsigned char *buf, unsigned int buflen, int rw);
+extern unsigned int ata_data_xfer_noirq(struct ata_device *dev,
+ unsigned char *buf, unsigned int buflen, int rw);
extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc);
extern void ata_qc_prep(struct ata_queued_cmd *qc);