Commit 55dba312 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

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: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent ceb0c642
...@@ -4994,7 +4994,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) ...@@ -4994,7 +4994,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
/** /**
* ata_data_xfer - Transfer data by PIO * ata_data_xfer - Transfer data by PIO
* @adev: device to target * @dev: device to target
* @buf: data buffer * @buf: data buffer
* @buflen: buffer length * @buflen: buffer length
* @write_data: read/write * @write_data: read/write
...@@ -5003,37 +5003,44 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) ...@@ -5003,37 +5003,44 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
* *
* LOCKING: * LOCKING:
* Inherited from caller. * Inherited from caller.
*
* RETURNS:
* Bytes consumed.
*/ */
void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf,
unsigned int buflen, int write_data) 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; unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */ /* Transfer multiple of 2 bytes */
if (write_data) if (rw == READ)
iowrite16_rep(ap->ioaddr.data_addr, buf, words); ioread16_rep(data_addr, buf, words);
else else
ioread16_rep(ap->ioaddr.data_addr, buf, words); iowrite16_rep(data_addr, buf, words);
/* Transfer trailing 1 byte, if any. */ /* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) { if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 }; u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1; unsigned char *trailing_buf = buf + buflen - 1;
if (write_data) { if (rw == READ) {
memcpy(align_buf, trailing_buf, 1); align_buf[0] = cpu_to_le16(ioread16(data_addr));
iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
} else {
align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr));
memcpy(trailing_buf, align_buf, 1); 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 * ata_data_xfer_noirq - Transfer data by PIO
* @adev: device to target * @dev: device to target
* @buf: data buffer * @buf: data buffer
* @buflen: buffer length * @buflen: buffer length
* @write_data: read/write * @write_data: read/write
...@@ -5043,14 +5050,21 @@ void ata_data_xfer(struct ata_device *adev, unsigned char *buf, ...@@ -5043,14 +5050,21 @@ void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
* *
* LOCKING: * LOCKING:
* Inherited from caller. * Inherited from caller.
*
* RETURNS:
* Bytes consumed.
*/ */
void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
unsigned int buflen, int write_data) unsigned int buflen, int rw)
{ {
unsigned long flags; unsigned long flags;
unsigned int consumed;
local_irq_save(flags); local_irq_save(flags);
ata_data_xfer(adev, buf, buflen, write_data); consumed = ata_data_xfer(dev, buf, buflen, rw);
local_irq_restore(flags); local_irq_restore(flags);
return consumed;
} }
......
...@@ -1167,34 +1167,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) ...@@ -1167,34 +1167,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
* Note: Original code is ata_data_xfer(). * Note: Original code is ata_data_xfer().
*/ */
static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf, static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
unsigned int buflen, int write_data) 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 short *buf16 = (u16 *) buf;
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
unsigned int words = buflen >> 1;
unsigned short *buf16 = (u16 *)buf;
/* Transfer multiple of 2 bytes */ /* Transfer multiple of 2 bytes */
if (write_data) { if (rw == READ)
write_atapi_data(base, words, buf16);
} else {
read_atapi_data(base, words, buf16); read_atapi_data(base, words, buf16);
} else
write_atapi_data(base, words, buf16);
/* Transfer trailing 1 byte, if any. */ /* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) { if (unlikely(buflen & 0x01)) {
unsigned short align_buf[1] = { 0 }; unsigned short align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1; unsigned char *trailing_buf = buf + buflen - 1;
if (write_data) { if (rw == READ) {
memcpy(align_buf, trailing_buf, 1);
write_atapi_data(base, 1, align_buf);
} else {
read_atapi_data(base, 1, align_buf); read_atapi_data(base, 1, align_buf);
memcpy(trailing_buf, align_buf, 1); memcpy(trailing_buf, align_buf, 1);
} else {
memcpy(align_buf, trailing_buf, 1);
write_atapi_data(base, 1, align_buf);
} }
words++;
} }
return words << 1;
} }
/** /**
......
...@@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) ...@@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
return 0; return 0;
} }
static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
unsigned int buflen, int write_data) unsigned char *buf, unsigned int buflen, int rw)
{ {
unsigned int i; unsigned int i;
unsigned int words = buflen >> 1; unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf; 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; void __iomem *mmio = ap->ioaddr.data_addr;
struct ixp4xx_pata_data *data = ap->host->dev->platform_data; 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, ...@@ -59,30 +59,32 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
udelay(100); udelay(100);
/* Transfer multiple of 2 bytes */ /* Transfer multiple of 2 bytes */
if (write_data) { if (rw == READ)
for (i = 0; i < words; i++)
writew(buf16[i], mmio);
} else {
for (i = 0; i < words; i++) for (i = 0; i < words; i++)
buf16[i] = readw(mmio); buf16[i] = readw(mmio);
} else
for (i = 0; i < words; i++)
writew(buf16[i], mmio);
/* Transfer trailing 1 byte, if any. */ /* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) { if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 }; u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1; unsigned char *trailing_buf = buf + buflen - 1;
if (write_data) { if (rw == READ) {
memcpy(align_buf, trailing_buf, 1);
writew(align_buf[0], mmio);
} else {
align_buf[0] = readw(mmio); align_buf[0] = readw(mmio);
memcpy(trailing_buf, align_buf, 1); memcpy(trailing_buf, align_buf, 1);
} else {
memcpy(align_buf, trailing_buf, 1);
writew(align_buf[0], mmio);
} }
words++;
} }
udelay(100); udelay(100);
*data->cs0_cfg |= 0x01; *data->cs0_cfg |= 0x01;
return words << 1;
} }
static struct scsi_host_template ixp4xx_sht = { static struct scsi_host_template ixp4xx_sht = {
......
...@@ -249,13 +249,14 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) ...@@ -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)) { 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); local_irq_save(flags);
/* Perform the 32bit I/O synchronization sequence */ /* 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 ...@@ -264,26 +265,27 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
ioread8(ap->ioaddr.nsect_addr); ioread8(ap->ioaddr.nsect_addr);
/* Now the data */ /* Now the data */
if (rw == READ)
if (write_data)
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) { if (unlikely(slop)) {
__le32 pad = 0; u32 pad;
if (write_data) { if (rw == READ) {
memcpy(&pad, buf + buflen - slop, slop);
iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
} else {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop); 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); local_irq_restore(flags);
} } else
else buflen = ata_data_xfer_noirq(dev, buf, buflen, rw);
ata_data_xfer_noirq(adev, buf, buflen, write_data);
return buflen;
} }
static struct ata_port_operations pdc20230_port_ops = { static struct ata_port_operations pdc20230_port_ops = {
......
...@@ -124,29 +124,33 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) ...@@ -124,29 +124,33 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(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; if (ata_id_has_dword_io(dev->id)) {
int slop = buflen & 3; struct ata_port *ap = dev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) { if (rw == READ)
if (write_data)
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) { if (unlikely(slop)) {
__le32 pad = 0; u32 pad;
if (write_data) { if (rw == READ) {
memcpy(&pad, buf + buflen - slop, slop);
iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
} else {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop); 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 } 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 = { static struct scsi_host_template qdi_sht = {
......
...@@ -768,45 +768,47 @@ static u8 scc_bmdma_status (struct ata_port *ap) ...@@ -768,45 +768,47 @@ static u8 scc_bmdma_status (struct ata_port *ap)
/** /**
* scc_data_xfer - Transfer data by PIO * scc_data_xfer - Transfer data by PIO
* @adev: device for this I/O * @dev: device for this I/O
* @buf: data buffer * @buf: data buffer
* @buflen: buffer length * @buflen: buffer length
* @write_data: read/write * @rw: read/write
* *
* Note: Original code is ata_data_xfer(). * Note: Original code is ata_data_xfer().
*/ */
static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
unsigned int buflen, int write_data) 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 words = buflen >> 1;
unsigned int i; unsigned int i;
u16 *buf16 = (u16 *) buf; u16 *buf16 = (u16 *) buf;
void __iomem *mmio = ap->ioaddr.data_addr; void __iomem *mmio = ap->ioaddr.data_addr;
/* Transfer multiple of 2 bytes */ /* Transfer multiple of 2 bytes */
if (write_data) { if (rw == READ)
for (i = 0; i < words; i++)
out_be32(mmio, cpu_to_le16(buf16[i]));
} else {
for (i = 0; i < words; i++) for (i = 0; i < words; i++)
buf16[i] = le16_to_cpu(in_be32(mmio)); 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. */ /* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) { if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 }; u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1; unsigned char *trailing_buf = buf + buflen - 1;
if (write_data) { if (rw == READ) {
memcpy(align_buf, trailing_buf, 1);
out_be32(mmio, cpu_to_le16(align_buf[0]));
} else {
align_buf[0] = le16_to_cpu(in_be32(mmio)); align_buf[0] = le16_to_cpu(in_be32(mmio));
memcpy(trailing_buf, align_buf, 1); 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;
} }
/** /**
......
...@@ -92,29 +92,33 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) ...@@ -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; int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) { if (ata_id_has_dword_io(dev->id)) {
if (write_data) if (rw == READ)
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) { if (unlikely(slop)) {
__le32 pad = 0; u32 pad;
if (write_data) { if (rw == READ) {
memcpy(&pad, buf + buflen - slop, slop);
iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
} else {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop); 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 } 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 = { static struct scsi_host_template winbond_sht = {
......
...@@ -701,7 +701,8 @@ struct ata_port_operations { ...@@ -701,7 +701,8 @@ struct ata_port_operations {
void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (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); int (*qc_defer) (struct ata_queued_cmd *qc);
void (*qc_prep) (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) ...@@ -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_port_start(struct ata_port *ap);
extern int ata_sff_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 irqreturn_t ata_interrupt(int irq, void *dev_instance);
extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf, extern unsigned int ata_data_xfer(struct ata_device *dev,
unsigned int buflen, int write_data); unsigned char *buf, unsigned int buflen, int rw);
extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, extern unsigned int ata_data_xfer_noirq(struct ata_device *dev,
unsigned int buflen, int write_data); unsigned char *buf, unsigned int buflen, int rw);
extern int ata_std_qc_defer(struct ata_queued_cmd *qc); 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_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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment