--- drivers/scsi/Kconfig | 11 +- drivers/scsi/Makefile | 1 drivers/scsi/libata-core.c | 4 drivers/scsi/pata_ixp4xx.c | 242 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 3 deletions(-) --- linux-ixp4xx.orig/drivers/scsi/Kconfig 2006-02-24 18:13:55.000000000 +0100 +++ linux-ixp4xx/drivers/scsi/Kconfig 2006-02-24 18:50:19.000000000 +0100 @@ -903,11 +903,20 @@ config SCSI_PATA_WINBOND tristate "Winbond SL82C105 PATA support" depends on SCSI_SATA && PCI help - This option enables support for SL82C105 PATA devices found in the + This option enables support for SL82C105 PATAll devices found in the Netwinder and some other systems If unsure, say N. +config SCSI_PATA_IXP4XX + tristate "IXP4XX Compact FLash support" + depends on SCSI_SATA && PCI + help + This option enables support for a Compact Flash connected on + the ixp4xx expansion bus. + + If unsure, say N. + config SCSI_BUSLOGIC tristate "BusLogic SCSI support" --- linux-ixp4xx.orig/drivers/scsi/Makefile 2006-02-24 18:13:55.000000000 +0100 +++ linux-ixp4xx/drivers/scsi/Makefile 2006-02-24 18:16:46.000000000 +0100 @@ -174,6 +174,7 @@ obj-$(CONFIG_SCSI_PATA_VIA) += libata.o obj-$(CONFIG_SCSI_PATA_WINBOND) += libata.o pata_sl82c105.o obj-$(CONFIG_SCSI_ATA_GENERIC) += libata.o ata_generic.o obj-$(CONFIG_SCSI_PATA_LEGACY) += libata.o pata_legacy.o +obj-$(CONFIG_SCSI_PATA_IXP4XX) += libata.o pata_ixp4xx.o obj-$(CONFIG_ARM) += arm/ --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/scsi/pata_ixp4xx.c 2006-02-24 18:43:02.000000000 +0100 @@ -0,0 +1,242 @@ +/* + * pata-ixp4xx.c - Legacy port PATA/SATA controller driver. + * Copyright (c) 2006 Tower Technologies + * + * An ATA driver to handle a Compact Flash connected + * to the ixp4xx expansion bus. + */ + +#include +#include +#include +#include + +#define DRV_NAME "ixp4xx" +#define DRV_VERSION "0.0.2" + +/* XXX remove when converting to platform driver */ +#define IXP4XX_IDE_BASE IXP4XX_EXP_BUS_BASE(1) +#define IXP4XX_IDE_IRQ IRQ_IXP4XX_GPIO12 +#define IXP4XX_IDE_CONTROL 0x1e +#define IXP4XX_IDE_INT 12 +#define IXP4XX_IDE_CS1_BITS 0xbfff0043 +#define IXP4XX_IDE_PIO_MASK 0x1f + +#ifdef __ARMEB__ +#define ixp4xx_writew(data,addr) writew(data,addr) +#define ixp4xx_readw(addr) readw(addr) +#else +#define ixp4xx_writew(data,addr) writew(le16_to_cpu(data),addr) +#define ixp4xx_readw(addr) cpu_to_le16(readw(addr)) +#endif + +static struct ata_host_set *ixp4xx_host; + +static unsigned int ixp4xx_mode_filter(const struct ata_port *ap, + struct ata_device *adev, unsigned int mask, int shift) +{ + if (shift != ATA_SHIFT_PIO) + return 0; + return mask; +} + +static void ixp4xx_set_mode(struct ata_port *ap) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->pio_mode = XFER_PIO_0; + dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + } + } +} + +static void ixp4xx_phy_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + ata_port_probe(ap); + ata_bus_reset(ap); +} + +void ixp4xx_mmio_data_xfer(struct ata_port *ap, struct ata_device *adev, + unsigned char *buf, unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + + /* set the expansion bus in 16bit mode and restore + * 8 bit mode after the transaction. + */ + *IXP4XX_EXP_CS1 &= ~(0x00000001); + + /* Transfer multiple of 2 bytes */ + if (write_data) { + for (i = 0; i < words; i++) + writew(buf16[i], mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = readw(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(le16_to_cpu(align_buf[0]), mmio); + } else { + align_buf[0] = cpu_to_le16(readw(mmio)); + memcpy(trailing_buf, align_buf, 1); + } + } + + *IXP4XX_EXP_CS1 |= 0x00000001; +} + +void ixp4xx_host_stop(struct ata_host_set *host_set) +{ + ata_host_stop(host_set); + release_region(IXP4XX_IDE_BASE, 0x1000); +} + +static struct scsi_host_template ixp4xx_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +// .ordered_flush = 1, +}; + +static struct ata_port_operations ixp4xx_port_ops = { + .set_mode = ixp4xx_set_mode, + .mode_filter = ixp4xx_mode_filter, + + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, + .data_xfer = ixp4xx_mmio_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ixp4xx_host_stop, + + .phy_reset = ixp4xx_phy_reset, +}; + +/* adjust the addresses to handle the address swizzling of the + * ixp4xx in little endian mode. + */ +#ifndef __ARMEB__ +void ixp4xx_fix_le_ports(struct ata_ioports *ioaddr) +{ + ioaddr->data_addr ^= 0x02; + ioaddr->cmd_addr ^= 0x03; + ioaddr->altstatus_addr ^= 0x03; + ioaddr->ctl_addr ^= 0x03; + ioaddr->error_addr ^= 0x03; + ioaddr->feature_addr ^= 0x03; + ioaddr->nsect_addr ^= 0x03; + ioaddr->lbal_addr ^= 0x03; + ioaddr->lbam_addr ^= 0x03; + ioaddr->lbah_addr ^= 0x03; + ioaddr->device_addr ^= 0x03; + ioaddr->status_addr ^= 0x03; + ioaddr->command_addr ^= 0x03; +} +#endif + +static __init int ixp4xx_init_one(unsigned long base, unsigned int irq) +{ + int ret; + struct ata_probe_ent ae; + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + + ae.mmio_base = ioremap(base, 0x1000); + if (ae.mmio_base == NULL) + return -ENOMEM; + + if (request_region(base, 0x1000, "pata_ixp4xx") == NULL) + return -EBUSY; + + ae.dev = NULL; + ae.port_ops = &ixp4xx_port_ops; + ae.sht = &ixp4xx_sht; + ae.n_ports = 1; + ae.pio_mask = IXP4XX_IDE_PIO_MASK; + ae.irq = irq; + ae.irq_flags = 0; + ae.host_flags = ATA_FLAG_IRQ_MASK | ATA_FLAG_MMIO; + + ae.port[0].cmd_addr = (unsigned long) ae.mmio_base; + ae.port[0].altstatus_addr = (unsigned long) ae.mmio_base + IXP4XX_IDE_CONTROL; + ae.port[0].ctl_addr = (unsigned long) ae.mmio_base + IXP4XX_IDE_CONTROL; + ata_std_ports(&ae.port[0]); + +#ifndef __ARMEB__ + ixp4xx_fix_le_ports(&ae.port[0]); +#endif + ret = ata_device_add(&ae); + if (ret == 0) + return -ENODEV; + + ixp4xx_host = ae.host_set; + return 0; +} + +static __init int ixp4xx_init(void) +{ + gpio_line_config(IXP4XX_IDE_INT, IXP4XX_GPIO_IN | IXP4XX_GPIO_STYLE_ACTIVE_HIGH); + + *IXP4XX_EXP_CS1 |= IXP4XX_IDE_CS1_BITS; + + if (ixp4xx_init_one(IXP4XX_IDE_BASE, IXP4XX_IDE_INT) == 0) + return 0; + + return -ENODEV; +} + +static __exit void ixp4xx_exit(void) +{ + if (ixp4xx_host) + ata_host_set_remove(ixp4xx_host); +} + +MODULE_AUTHOR("Alessandro Zummo"); +MODULE_DESCRIPTION("low-level driver for ixp4xx CF/ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(ixp4xx_init); +module_exit(ixp4xx_exit); --- linux-ixp4xx.orig/drivers/scsi/libata-core.c 2006-02-24 18:13:55.000000000 +0100 +++ linux-ixp4xx/drivers/scsi/libata-core.c 2006-02-24 18:16:46.000000000 +0100 @@ -2513,8 +2513,8 @@ static void ata_dev_set_xfermode(struct tf.nsect = dev->xfer_mode; if (ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0)) { - printk(KERN_ERR "ata%u: failed to set xfermode, disabled\n", - ap->id); + printk(KERN_ERR "ata%u: failed to set xfermode (0x%02x), disabled\n", + ap->id, dev->xfer_mode); ata_port_disable(ap); }