From 92d3ab27e8fd23d1a9dc3b69d17b2afb83e5c6f5 Mon Sep 17 00:00:00 2001
From: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date: Mon, 28 Apr 2008 23:44:36 +0200
Subject: [PATCH] falconide/q40ide: add ->atapi_*put_bytes and ->ata_*put_data
 methods (take 2)

* Add ->atapi_{in,out}put_bytes and ->ata_{in,out}put_data methods to
  falconide and q40ide host drivers (->ata_* methods are implemented on
  top of ->atapi_* methods so they also do byte-swapping now).

* Cleanup atapi_{in,out}put_bytes().

v2:
* Add 'struct request *rq' argument to ->ata_{in,out}put_data methods
  and don't byte-swap disk fs requests (we shouldn't un-swap fs requests
  because fs itself is stored byte-swapped on the disk) - this is how
  things were done before the patch (ideally device mapper should be
  used instead but it would break existing setups and would have some
  performance impact).

Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Michael Schmitz <schmitz@debian.org>
Cc: Roman Zippel <zippel@linux-m68k.org>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Richard Zidlicky <rz@linux-m68k.org>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
---
 drivers/ide/cris/ide-cris.c    | 14 +++++++------
 drivers/ide/ide-io.c           |  2 +-
 drivers/ide/ide-iops.c         | 26 +++++++-----------------
 drivers/ide/ide-probe.c        |  2 +-
 drivers/ide/ide-taskfile.c     | 16 ++++++++-------
 drivers/ide/legacy/falconide.c | 36 ++++++++++++++++++++++++++++++++++
 drivers/ide/legacy/q40ide.c    | 34 ++++++++++++++++++++++++++++++++
 include/linux/ide.h            |  4 ++--
 8 files changed, 98 insertions(+), 36 deletions(-)

diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 9df26855bc0..aa263df7656 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -673,8 +673,10 @@ cris_ide_inb(unsigned long reg)
 	return (unsigned char)cris_ide_inw(reg);
 }
 
-static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
-static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
+static void cris_ide_input_data(ide_drive_t *, struct request *,
+				void *, unsigned int);
+static void cris_ide_output_data(ide_drive_t *, struct request *,
+				 void *, unsigned int);
 static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
 
@@ -900,8 +902,8 @@ cris_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun
 /*
  * This is used for most PIO data transfers *from* the IDE interface
  */
-static void
-cris_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+static void cris_ide_input_data(ide_drive_t *drive, struct request *rq,
+				void *buffer, unsigned int wcount)
 {
 	cris_atapi_input_bytes(drive, buffer, wcount << 2);
 }
@@ -909,8 +911,8 @@ cris_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 /*
  * This is used for most PIO data transfers *to* the IDE interface
  */
-static void
-cris_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+static void cris_ide_output_data(ide_drive_t *drive, struct request *,
+				 void *buffer, unsigned int wcount)
 {
 	cris_atapi_output_bytes(drive, buffer, wcount << 2);
 }
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 3a2d8930d17..60078cf307f 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -422,7 +422,7 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
 		u32 wcount = (i > 16) ? 16 : i;
 
 		i -= wcount;
-		HWIF(drive)->ata_input_data(drive, buffer, wcount);
+		drive->hwif->ata_input_data(drive, NULL, buffer, wcount);
 	}
 }
 
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 5425d3038ec..7ec7fa2aef9 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -192,7 +192,8 @@ static void ata_vlb_sync(ide_drive_t *drive, unsigned long port)
 /*
  * This is used for most PIO data transfers *from* the IDE interface
  */
-static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
+static void ata_input_data(ide_drive_t *drive, struct request *rq,
+			   void *buffer, u32 wcount)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	struct ide_io_ports *io_ports = &hwif->io_ports;
@@ -215,7 +216,8 @@ static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
 /*
  * This is used for most PIO data transfers *to* the IDE interface
  */
-static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
+static void ata_output_data(ide_drive_t *drive, struct request *rq,
+			    void *buffer, u32 wcount)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	struct ide_io_ports *io_ports = &hwif->io_ports;
@@ -248,14 +250,7 @@ static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount)
 	ide_hwif_t *hwif = HWIF(drive);
 
 	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(hwif->io_ports.data_addr, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI || CONFIG_Q40 */
-	hwif->ata_input_data(drive, buffer, bytecount / 4);
+	hwif->ata_input_data(drive, NULL, buffer, bytecount / 4);
 	if ((bytecount & 0x03) >= 2)
 		hwif->INSW(hwif->io_ports.data_addr,
 			   (u8 *)buffer + (bytecount & ~0x03), 1);
@@ -266,14 +261,7 @@ static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount)
 	ide_hwif_t *hwif = HWIF(drive);
 
 	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(hwif->io_ports.data_addr, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI || CONFIG_Q40 */
-	hwif->ata_output_data(drive, buffer, bytecount / 4);
+	hwif->ata_output_data(drive, NULL, buffer, bytecount / 4);
 	if ((bytecount & 0x03) >= 2)
 		hwif->OUTSW(hwif->io_ports.data_addr,
 			    (u8 *)buffer + (bytecount & ~0x03), 1);
@@ -668,7 +656,7 @@ int ide_driveid_update(ide_drive_t *drive)
 		local_irq_restore(flags);
 		return 0;
 	}
-	hwif->ata_input_data(drive, id, SECTOR_WORDS);
+	hwif->ata_input_data(drive, NULL, id, SECTOR_WORDS);
 	(void)ide_read_status(drive);	/* clear drive IRQ */
 	local_irq_enable();
 	local_irq_restore(flags);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 862f02603f9..e06a6460521 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -124,7 +124,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
 
 	id = drive->id;
 	/* read 512 bytes of id info */
-	hwif->ata_input_data(drive, id, SECTOR_WORDS);
+	hwif->ata_input_data(drive, NULL, id, SECTOR_WORDS);
 
 	drive->id_read = 1;
 	local_irq_enable();
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 9f9ad9fb6b8..7f6bfd31441 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -283,7 +283,8 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
 	return stat;
 }
 
-static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
+static void ide_pio_sector(ide_drive_t *drive, struct request *rq,
+			   unsigned int write)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	struct scatterlist *sg = hwif->sg_table;
@@ -323,9 +324,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
 
 	/* do the actual data transfer */
 	if (write)
-		hwif->ata_output_data(drive, buf, SECTOR_WORDS);
+		hwif->ata_output_data(drive, rq, buf, SECTOR_WORDS);
 	else
-		hwif->ata_input_data(drive, buf, SECTOR_WORDS);
+		hwif->ata_input_data(drive, rq, buf, SECTOR_WORDS);
 
 	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 #ifdef CONFIG_HIGHMEM
@@ -333,13 +334,14 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
 #endif
 }
 
-static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
+static void ide_pio_multi(ide_drive_t *drive, struct request *rq,
+			  unsigned int write)
 {
 	unsigned int nsect;
 
 	nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
 	while (nsect--)
-		ide_pio_sector(drive, write);
+		ide_pio_sector(drive, rq, write);
 }
 
 static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
@@ -362,10 +364,10 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 	switch (drive->hwif->data_phase) {
 	case TASKFILE_MULTI_IN:
 	case TASKFILE_MULTI_OUT:
-		ide_pio_multi(drive, write);
+		ide_pio_multi(drive, rq, write);
 		break;
 	default:
-		ide_pio_sector(drive, write);
+		ide_pio_sector(drive, rq, write);
 		break;
 	}
 
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 56cdaa0eeea..32c044b17d4 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -44,6 +44,36 @@
 int falconide_intr_lock;
 EXPORT_SYMBOL(falconide_intr_lock);
 
+static void falconide_atapi_input_bytes(ide_drive_t *drive, void *buf,
+					unsigned int len)
+{
+	insw_swapw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void falconide_atapi_output_bytes(ide_drive_t *drive, void *buf,
+					 unsigned int len)
+{
+	outsw_swapw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void falconide_ata_input_data(ide_drive_t *drive, struct request *rq,
+				     void *buf, unsigned int wcount)
+{
+	if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+		return insw(drive->hwif->io_ports.data_addr, buf, wcount * 2);
+
+	falconide_atapi_input_bytes(drive, buf, wcount * 4);
+}
+
+static void falconide_ata_output_data(ide_drive_t *drive, struct request *rq,
+				      void *buf, unsigned int wcount)
+{
+	if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+		return outsw(drive->hwif->io_ports.data_addr, buf, wcount * 2);
+
+	falconide_atapi_output_bytes(drive, buf, wcount * 4);
+}
+
 static void __init falconide_setup_ports(hw_regs_t *hw)
 {
 	int i;
@@ -90,6 +120,12 @@ static int __init falconide_init(void)
 		ide_init_port_data(hwif, index);
 		ide_init_port_hw(hwif, &hw);
 
+		/* Atari has a byte-swapped IDE interface */
+		hwif->atapi_input_bytes  = falconide_atapi_input_bytes;
+		hwif->atapi_output_bytes = falconide_atapi_output_bytes;
+		hwif->ata_input_data	 = falconide_ata_input_data;
+		hwif->ata_output_data	 = falconide_ata_output_data;
+
 		ide_get_lock(NULL, NULL);
 		ide_device_add(idx, NULL);
 		ide_release_lock();
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index f9210458aea..deae3d2ca65 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -72,7 +72,35 @@ static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
 	hw->ack_intr = ack_intr;
 }
 
+static void q40ide_atapi_input_bytes(ide_drive_t *drive, void *buf,
+				     unsigned int len)
+{
+	insw_swapw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
 
+static void q40ide_atapi_output_bytes(ide_drive_t *drive, void *buf,
+				      unsigned int len)
+{
+	outsw_swapw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void q40ide_ata_input_data(ide_drive_t *drive, struct request *rq,
+				  void *buf, unsigned int wcount)
+{
+	if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+		return insw(drive->hwif->io_ports.data_addr, buf, wcount * 2);
+
+	q40ide_atapi_input_bytes(drive, buf, wcount * 4);
+}
+
+static void q40ide_ata_output_data(ide_drive_t *drive, struct request *rq,
+				   void *buf, unsigned int wcount)
+{
+	if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+		return outsw(drive->hwif->io_ports.data_addr, buf, wcount * 2);
+
+	q40ide_atapi_output_bytes(drive, buf, wcount * 4);
+}
 
 /* 
  * the static array is needed to have the name reported in /proc/ioports,
@@ -123,6 +151,12 @@ static int __init q40ide_init(void)
 		ide_init_port_data(hwif, hwif->index);
 		ide_init_port_hw(hwif, &hw);
 
+		/* Q40 has a byte-swapped IDE interface */
+		hwif->atapi_input_bytes  = q40ide_atapi_input_bytes;
+		hwif->atapi_output_bytes = q40ide_atapi_output_bytes;
+		hwif->ata_input_data	 = q40ide_ata_input_data;
+		hwif->ata_output_data	 = q40ide_ata_output_data;
+
 		idx[i] = hwif->index;
 	}
     }
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 32fd77bb443..0cbc46bf08a 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -467,8 +467,8 @@ typedef struct hwif_s {
 	const struct ide_port_ops	*port_ops;
 	const struct ide_dma_ops	*dma_ops;
 
-	void (*ata_input_data)(ide_drive_t *, void *, u32);
-	void (*ata_output_data)(ide_drive_t *, void *, u32);
+	void (*ata_input_data)(ide_drive_t *, struct request *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, struct request *, void *, u32);
 
 	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
 	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
-- 
2.41.3