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

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
Loading
Loading
Loading
Loading
+30 −16
Original line number Diff line number Diff line
@@ -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;
}


+15 −13
Original line number Diff line number Diff line
@@ -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;
	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;
	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;

	/* 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;
}

/**
+14 −12
Original line number Diff line number Diff line
@@ -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 = {
+19 −17
Original line number Diff line number Diff line
@@ -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;
	if (ata_id_has_dword_io(adev->id)) {
		struct ata_port *ap = dev->link->ap;
		int slop = buflen & 3;
		unsigned long flags;

	if (ata_id_has_dword_io(adev->id)) {
		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 = {
+17 −13
Original line number Diff line number Diff line
@@ -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;
	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 = {
Loading