From 7e45b0e5f6f68d04311ba7813f5f5457c9119640 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 29 Sep 2006 18:30:05 +0100 Subject: [PATCH] libata: Winbond support Winbond 83759A support in non-multichip mode (afaik nobody ever used multichip mode anyway). The 83759 is not supported by this driver as it is already handled elsewhere and doens't use the same interfaces. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 7 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_winbond.c | 306 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 314 insertions(+) create mode 100644 drivers/ata/pata_winbond.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 03f6338acc8f..b38e2c325ea7 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -483,6 +483,13 @@ config PATA_WINBOND If unsure, say N. +config PATA_WINBOND_VLB + tristate "Winbond W83759A VLB PATA support (Experimental)" + depends on ISA && EXPERIMENTAL + help + Support for the Winbond W83759A controller on Vesa Local Bus + systems. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 72243a677f9b..ff6c6db22baf 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o obj-$(CONFIG_PATA_SIL680) += pata_sil680.o obj-$(CONFIG_PATA_VIA) += pata_via.o obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o +obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o # Should be last but one libata driver diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c new file mode 100644 index 000000000000..48941d0757e9 --- /dev/null +++ b/drivers/ata/pata_winbond.c @@ -0,0 +1,306 @@ +/* + * pata_winbond.c - Winbond VLB ATA controllers + * (C) 2006 Red Hat + * + * Support for the Winbond 83759A when operating in advanced mode. + * Multichip mode is not currently supported. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_winbond" +#define DRV_VERSION "0.0.1" + +#define NR_HOST 4 /* Two winbond controllers, two channels each */ + +struct winbond_data { + unsigned long config; + struct platform_device *platform_dev; +}; + +static struct ata_host *winbond_host[NR_HOST]; +static struct winbond_data winbond_data[NR_HOST]; +static int nr_winbond_host; + +#ifdef MODULE +static int probe_winbond = 1; +#else +static int probe_winbond; +#endif + +static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED; + +static void winbond_writecfg(unsigned long port, u8 reg, u8 val) +{ + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + outb(val, port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); +} + +static u8 winbond_readcfg(unsigned long port, u8 reg) +{ + u8 val; + + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + val = inb(port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); + + return val; +} + +static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing t; + struct winbond_data *winbond = ap->host->private_data; + int active, recovery; + u8 reg; + int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); + + reg = winbond_readcfg(winbond->config, 0x81); + + /* Get the timing data in cycles */ + if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ + ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); + else + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + active = (FIT(t.active, 3, 17) - 1) & 0x0F; + recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; + timing = (active << 4) | recovery; + winbond_writecfg(winbond->config, timing, reg); + + /* Load the setup timing */ + + reg = 0x35; + if (adev->class != ATA_DEV_ATA) + reg |= 0x08; /* FIFO off */ + if (!ata_pio_need_iordy(adev)) + reg |= 0x02; /* IORDY off */ + reg |= (FIT(t.setup, 0, 3) << 6); + winbond_writecfg(winbond->config, timing + 1, reg); +} + + +static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + int slop = buflen & 3; + + if (ata_id_has_dword_io(adev->id)) { + if (write_data) + outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + else + insl(ap->ioaddr.data_addr, buf, buflen >> 2); + + if (unlikely(slop)) { + u32 pad; + if (write_data) { + memcpy(&pad, buf + buflen - slop, slop); + outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + } else { + pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); + } + } + } else + ata_pio_data_xfer(adev, buf, buflen, write_data); +} + +static struct scsi_host_template winbond_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, +}; + +static struct ata_port_operations winbond_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = winbond_set_piomode, + + .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, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = winbond_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop +}; + +/** + * winbond_init_one - attach a winbond interface + * @type: Type to display + * @io: I/O port start + * @irq: interrupt line + * @fast: True if on a > 33Mhz VLB + * + * Register a VLB bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + */ + +static __init int winbond_init_one(unsigned long port) +{ + struct ata_probe_ent ae; + struct platform_device *pdev; + int ret; + u8 reg; + int i; + + reg = winbond_readcfg(port, 0x81); + reg |= 0x80; /* jumpered mode off */ + winbond_writecfg(port, 0x81, reg); + reg = winbond_readcfg(port, 0x83); + reg |= 0xF0; /* local control */ + winbond_writecfg(port, 0x83, reg); + reg = winbond_readcfg(port, 0x85); + reg |= 0xF0; /* programmable timing */ + winbond_writecfg(port, 0x85, reg); + + reg = winbond_readcfg(port, 0x81); + + if (!(reg & 0x03)) /* Disabled */ + return 0; + + for (i = 0; i < 2 ; i ++) { + + if (reg & (1 << i)) { + /* + * Fill in a probe structure first of all + */ + + pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0); + if (pdev == NULL) + return -ENOMEM; + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + + ae.port_ops = &winbond_port_ops; + ae.pio_mask = 0x1F; + + ae.sht = &winbond_sht; + + ae.n_ports = 1; + ae.irq = 14 + i; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae.port[0].cmd_addr = 0x1F0 - (0x80 * i); + ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206; + ae.port[0].ctl_addr = ae.port[0].altstatus_addr; + ata_std_ports(&ae.port[0]); + /* + * Hook in a private data structure per channel + */ + ae.private_data = &winbond_data[nr_winbond_host]; + winbond_data[nr_winbond_host].config = port; + winbond_data[nr_winbond_host].platform_dev = pdev; + + ret = ata_device_add(&ae); + if (ret == 0) { + platform_device_unregister(pdev); + return -ENODEV; + } + winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev); + } + } + + return 0; +} + +/** + * winbond_init - attach winbond interfaces + * + * Attach winbond IDE interfaces by scanning the ports it may occupy. + */ + +static __init int winbond_init(void) +{ + static const unsigned long config[2] = { 0x130, 0x1B0 }; + + int ct = 0; + int i; + + if (probe_winbond == 0) + return -ENODEV; + + /* + * Check both base addresses + */ + + for (i = 0; i < 2; i++) { + if (probe_winbond & (1< Date: Tue, 10 Oct 2006 14:28:12 -0700 Subject: [PATCH] pci_module_init convertion in ata_generic.c pci_module_init convertion in ata_generic.c. Signed-off-by: Henrik Kretzschmar Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 4a80ff9312b8..a44c20c0c757 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -231,7 +231,7 @@ static struct pci_driver ata_generic_pci_driver = { static int __init ata_generic_init(void) { - return pci_module_init(&ata_generic_pci_driver); + return pci_register_driver(&ata_generic_pci_driver); } -- cgit v1.2.3 From 2f27ce03628acdb81ead4abe914c713e04a3229e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 10 Oct 2006 14:28:12 -0700 Subject: [PATCH] pci_module_init-convertion-in-ata_genericc fix Acked-by: Alan Cox but please apply as follows to keep revision id straight Cc: Henrik Kretzschmar Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index a44c20c0c757..1b9ba4dfac65 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.6" +#define DRV_VERSION "0.2.7" /* * A generic parallel ATA driver using libata -- cgit v1.2.3 From fc085150b491bfc186efbca90a14cf907a3060a9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 10 Oct 2006 14:28:11 -0700 Subject: [PATCH] libata: add 40pin "short" cable support, honour drive side speed detection [deweerdt@free.fr: build fix] Signed-off-by: Alan Cox Signed-off-by: Frederik Deweerdt Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 31 ++++++++++++++++++++++++++++++- drivers/ata/libata-core.c | 7 +++++++ drivers/ata/pata_ali.c | 2 +- include/linux/ata.h | 14 ++++++++++++-- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 720174d628fa..14b726b9f985 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -93,7 +93,7 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.00ac6" +#define DRV_VERSION "2.00ac7" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -571,6 +571,23 @@ module_param(force_pcs, int, 0444); MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); +struct ich_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +/* + * List of laptops that use short cables rather than 80 wire + */ + +static const struct ich_laptop ich_laptop[] = { + /* devid, subvendor, subdev */ + { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + /* end marker */ + { 0, } +}; + /** * piix_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired @@ -585,12 +602,24 @@ MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " static void ich_pata_cbl_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); + const struct ich_laptop *lap = &ich_laptop[0]; u8 tmp, mask; /* no 80c support in host controller? */ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) goto cbl40; + /* Check for specials - Acer Aspire 5602WLMi */ + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) { + ap->cbl = ATA_CBL_PATA40_SHORT; + return; + } + lap++; + } + /* check BIOS cable detect results */ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 915a55a6cc14..b896119cccd3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3119,6 +3119,13 @@ static void ata_dev_xfermask(struct ata_device *dev) */ if (ap->cbl == ATA_CBL_PATA40) xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + /* Apply drive side cable rule. Unknown or 80 pin cables reported + * host side are checked drive side as well. Cases where we know a + * 40wire cable is used safely for 80 are not checked here. + */ + if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80)) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + xfer_mask &= ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask, dev->udma_mask); diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 64eed99f6814..e6d2b840e870 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -78,7 +78,7 @@ static int ali_c2_cable_detect(struct ata_port *ap) implement the detect logic */ if (ali_cable_override(pdev)) - return ATA_CBL_PATA80; + return ATA_CBL_PATA40_SHORT; /* Host view cable detect 0x4A bit 0 primary bit 1 secondary Bit set for 40 pin */ diff --git a/include/linux/ata.h b/include/linux/ata.h index d89441907024..1df941648a57 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -200,8 +200,9 @@ enum { ATA_CBL_NONE = 0, ATA_CBL_PATA40 = 1, ATA_CBL_PATA80 = 2, - ATA_CBL_PATA_UNK = 3, - ATA_CBL_SATA = 4, + ATA_CBL_PATA40_SHORT = 3, /* 40 wire cable to high UDMA spec */ + ATA_CBL_PATA_UNK = 4, + ATA_CBL_SATA = 5, /* SATA Status and Control Registers */ SCR_STATUS = 0, @@ -342,6 +343,15 @@ static inline int ata_id_is_cfa(const u16 *id) return 0; } +static inline int ata_drive_40wire(const u16 *dev_id) +{ + if (ata_id_major_version(dev_id) >= 5 && ata_id_is_sata(dev_id)) + return 0; /* SATA */ + if (dev_id[93] & 0x4000) + return 0; /* 80 wire */ + return 1; +} + static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; -- cgit v1.2.3 From 72dc6794fcd7642200a87bf18e3a43e676314b63 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Tue, 10 Oct 2006 14:29:24 -0700 Subject: [PATCH] pci_module_init() conversion for pata_pdc2027x pci_module_init() conversion for pata_pdc2027x Signed-off-by: Henrik Kretzschmar Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc2027x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index beb6d10a234b..ef854299989c 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -854,7 +854,7 @@ static void __devexit pdc2027x_remove_one(struct pci_dev *pdev) */ static int __init pdc2027x_init(void) { - return pci_module_init(&pdc2027x_pci_driver); + return pci_register_driver(&pdc2027x_pci_driver); } /** -- cgit v1.2.3 From 75742cb41e4b5c7913f385b9688aad69c9fa7ada Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:40:06 +0100 Subject: [PATCH] pata_marvell: Marvell 6101/6145 PATA driver This is a legacy mode PATA driver for the 6101/45 and will also drive the SATA ports 1 & 2 in legacy mode as well if desired. Tested and confirmed working by users. The chip supports AHCI type behaviour for SATA and has a more advanced PATA interface as well so this driver will get it working but not get best performance for now. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_marvell.c | 221 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 drivers/ata/pata_marvell.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index b38e2c325ea7..9b07e70bee7d 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -328,6 +328,15 @@ config PATA_TRIFLEX If unsure, say N. +config PATA_MARVELL + tristate "Marvell PATA support via legacy mode" + depends on PCI + help + This option enables limited support for the Marvell 88SE6145 ATA + controller. + + If unsure, say N. + config PATA_MPIIX tristate "Intel PATA MPIIX support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index ff6c6db22baf..ceba7d824a62 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o +obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c new file mode 100644 index 000000000000..2b8e00cb7b9b --- /dev/null +++ b/drivers/ata/pata_marvell.c @@ -0,0 +1,221 @@ +/* + * Marvell PATA driver. + * + * For the moment we drive the PATA port in legacy mode. That + * isn't making full use of the device functionality but it is + * easy to get working. + * + * (c) 2006 Red Hat + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_marvell" +#define DRV_VERSION "0.0.4t" + +/** + * marvell_pre_reset - check for 40/80 pin + * @ap: Port + * + * Perform the PATA port setup we need. + */ + +static int marvell_pre_reset(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 devices; + unsigned long bar5; + void __iomem *barp; + int i; + + /* Check if our port is enabled */ + + bar5 = pci_resource_start(pdev, 5); + barp = ioremap(bar5, 0x10); + if (barp == NULL) + return -ENOMEM; + printk("BAR5:"); + for(i = 0; i <= 0x0F; i++) + printk("%02X:%02X ", i, readb(barp + i)); + printk("\n"); + + devices = readl(barp + 0x0C); + iounmap(barp); + + if (pdev->device == 0x6145 && ap->port_no == 0 && !(devices & 0x10)) /* PATA enable ? */ + return -ENOENT; + + /* Cable type */ + switch(ap->port_no) + { + case 0: + /* Might be backward, docs unclear */ + if(inb(ap->ioaddr.bmdma_addr + 1) & 1) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; + + case 1: /* Legacy SATA port */ + ap->cbl = ATA_CBL_SATA; + break; + } + return ata_std_prereset(ap); +} + +/** + * marvell_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void marvell_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + +/* No PIO or DMA methods needed for this device */ + +static struct scsi_host_template marvell_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations marvell_ops = { + .port_disable = ata_port_disable, + + /* Task file is PCI ATA format, use helpers */ + .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, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = marvell_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + /* BMDMA handling is PCI ATA format, use helpers */ + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, + + /* Timeout handling */ + .eng_timeout = ata_eng_timeout, + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + /* Generic PATA PCI ATA helpers */ + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop, +}; + + +/** + * marvell_init_one - Register Marvell ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in marvell_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &marvell_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x3f, + + .port_ops = &marvell_ops, + }; + static struct ata_port_info info_sata = { + .sht = &marvell_sht, + /* Slave possible as its magically mapped not real */ + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &marvell_ops, + }; + struct ata_port_info *port_info[2] = { &info, &info_sata }; + int n_port = 2; + + if (pdev->device == 0x6101) + n_port = 1; + + return ata_pci_init_one(pdev, port_info, n_port); +} + +static const struct pci_device_id marvell_pci_tbl[] = { + { PCI_DEVICE(0x11AB, 0x6101), }, + { PCI_DEVICE(0x11AB, 0x6145), }, + { } /* terminate list */ +}; + +static struct pci_driver marvell_pci_driver = { + .name = DRV_NAME, + .id_table = marvell_pci_tbl, + .probe = marvell_init_one, + .remove = ata_pci_remove_one, +}; + +static int __init marvell_init(void) +{ + return pci_register_driver(&marvell_pci_driver); +} + +static void __exit marvell_exit(void) +{ + pci_unregister_driver(&marvell_pci_driver); +} + +module_init(marvell_init); +module_exit(marvell_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for Marvell ATA in legacy mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, marvell_pci_tbl); +MODULE_VERSION(DRV_VERSION); + -- cgit v1.2.3 From 6e9d8629b5503175a4425722a1ef13eed232c650 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 21 Oct 2006 15:54:13 -0400 Subject: [libata] pata_marvell: minor and trivial cleanups - use pci_iomap() [Alan, version 0.0.5t] - fix Alan's version 0.0.5t change - line length, trailing whitespace, case indentation cleanups - don't use deprecated ->eng_timeout() in a driver that uses new EH Signed-off-by: Jeff Garzik --- drivers/ata/pata_marvell.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 2b8e00cb7b9b..1ea64075c783 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -20,7 +20,7 @@ #include #define DRV_NAME "pata_marvell" -#define DRV_VERSION "0.0.4t" +#define DRV_VERSION "0.0.5u" /** * marvell_pre_reset - check for 40/80 pin @@ -33,14 +33,12 @@ static int marvell_pre_reset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 devices; - unsigned long bar5; void __iomem *barp; int i; /* Check if our port is enabled */ - bar5 = pci_resource_start(pdev, 5); - barp = ioremap(bar5, 0x10); + barp = pci_iomap(pdev, 5, 0x10); if (barp == NULL) return -ENOMEM; printk("BAR5:"); @@ -49,24 +47,25 @@ static int marvell_pre_reset(struct ata_port *ap) printk("\n"); devices = readl(barp + 0x0C); - iounmap(barp); + pci_iounmap(pdev, barp); - if (pdev->device == 0x6145 && ap->port_no == 0 && !(devices & 0x10)) /* PATA enable ? */ + if ((pdev->device == 0x6145) && (ap->port_no == 0) && + (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; /* Cable type */ switch(ap->port_no) { - case 0: - /* Might be backward, docs unclear */ - if(inb(ap->ioaddr.bmdma_addr + 1) & 1) - ap->cbl = ATA_CBL_PATA80; - else - ap->cbl = ATA_CBL_PATA40; - - case 1: /* Legacy SATA port */ - ap->cbl = ATA_CBL_SATA; - break; + case 0: + /* Might be backward, docs unclear */ + if (inb(ap->ioaddr.bmdma_addr + 1) & 1) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; + + case 1: /* Legacy SATA port */ + ap->cbl = ATA_CBL_SATA; + break; } return ata_std_prereset(ap); } @@ -81,7 +80,8 @@ static int marvell_pre_reset(struct ata_port *ap) static void marvell_error_handler(struct ata_port *ap) { - return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, NULL, ata_std_postreset); + return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); } /* No PIO or DMA methods needed for this device */ @@ -130,7 +130,6 @@ static const struct ata_port_operations marvell_ops = { .data_xfer = ata_pio_data_xfer, /* Timeout handling */ - .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -159,7 +158,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i { static struct ata_port_info info = { .sht = &marvell_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -170,7 +169,7 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i static struct ata_port_info info_sata = { .sht = &marvell_sht, /* Slave possible as its magically mapped not real */ - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -180,10 +179,10 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i }; struct ata_port_info *port_info[2] = { &info, &info_sata }; int n_port = 2; - + if (pdev->device == 0x6101) n_port = 1; - + return ata_pci_init_one(pdev, port_info, n_port); } -- cgit v1.2.3 From fbbb262d9ea9bdbd79d7058271560e9990bc62d3 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Fri, 27 Oct 2006 19:08:41 -0700 Subject: [PATCH] sata_nv ADMA/NCQ support for nForce4 This patch adds support for ADMA mode on NVIDIA nForce4 (CK804/MCP04) SATA controllers to the sata_nv driver. Benefits of ADMA mode include: - NCQ support - Reduced CPU overhead (controller DMAs command information from memory instead of them being pushed in by the CPU) - Full 64-bit DMA support ADMA mode is enabled by default in this version. To disable it, set the module parameter adma_enabled=0. Signed-off-by: Robert Hancock Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 2 +- drivers/ata/sata_nv.c | 934 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 924 insertions(+), 12 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 7645f2b30ccf..e178d6ae8b80 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -732,7 +732,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { u8 host_stat; - host_stat = ata_bmdma_status(ap); + host_stat = ap->ops->bmdma_status(ap); ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index d65ebfd7c7b2..e5615be21565 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -29,6 +29,11 @@ * NV-specific details such as register offsets, SATA phy location, * hotplug info, etc. * + * CK804/MCP04 controllers support an alternate programming interface + * similar to the ADMA specification (with some modifications). + * This allows the use of NCQ. Non-DMA-mapped ATA commands are still + * sent through the legacy interface. + * */ #include @@ -40,10 +45,13 @@ #include #include #include +#include #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "2.0" +#define DRV_VERSION "3.1" + +#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL enum { NV_PORTS = 2, @@ -78,8 +86,137 @@ enum { // For PCI config register 20 NV_MCP_SATA_CFG_20 = 0x50, NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04, + NV_MCP_SATA_CFG_20_PORT0_EN = (1 << 17), + NV_MCP_SATA_CFG_20_PORT1_EN = (1 << 16), + NV_MCP_SATA_CFG_20_PORT0_PWB_EN = (1 << 14), + NV_MCP_SATA_CFG_20_PORT1_PWB_EN = (1 << 12), + + NV_ADMA_MAX_CPBS = 32, + NV_ADMA_CPB_SZ = 128, + NV_ADMA_APRD_SZ = 16, + NV_ADMA_SGTBL_LEN = (1024 - NV_ADMA_CPB_SZ) / + NV_ADMA_APRD_SZ, + NV_ADMA_SGTBL_TOTAL_LEN = NV_ADMA_SGTBL_LEN + 5, + NV_ADMA_SGTBL_SZ = NV_ADMA_SGTBL_LEN * NV_ADMA_APRD_SZ, + NV_ADMA_PORT_PRIV_DMA_SZ = NV_ADMA_MAX_CPBS * + (NV_ADMA_CPB_SZ + NV_ADMA_SGTBL_SZ), + + /* BAR5 offset to ADMA general registers */ + NV_ADMA_GEN = 0x400, + NV_ADMA_GEN_CTL = 0x00, + NV_ADMA_NOTIFIER_CLEAR = 0x30, + + /* BAR5 offset to ADMA ports */ + NV_ADMA_PORT = 0x480, + + /* size of ADMA port register space */ + NV_ADMA_PORT_SIZE = 0x100, + + /* ADMA port registers */ + NV_ADMA_CTL = 0x40, + NV_ADMA_CPB_COUNT = 0x42, + NV_ADMA_NEXT_CPB_IDX = 0x43, + NV_ADMA_STAT = 0x44, + NV_ADMA_CPB_BASE_LOW = 0x48, + NV_ADMA_CPB_BASE_HIGH = 0x4C, + NV_ADMA_APPEND = 0x50, + NV_ADMA_NOTIFIER = 0x68, + NV_ADMA_NOTIFIER_ERROR = 0x6C, + + /* NV_ADMA_CTL register bits */ + NV_ADMA_CTL_HOTPLUG_IEN = (1 << 0), + NV_ADMA_CTL_CHANNEL_RESET = (1 << 5), + NV_ADMA_CTL_GO = (1 << 7), + NV_ADMA_CTL_AIEN = (1 << 8), + NV_ADMA_CTL_READ_NON_COHERENT = (1 << 11), + NV_ADMA_CTL_WRITE_NON_COHERENT = (1 << 12), + + /* CPB response flag bits */ + NV_CPB_RESP_DONE = (1 << 0), + NV_CPB_RESP_ATA_ERR = (1 << 3), + NV_CPB_RESP_CMD_ERR = (1 << 4), + NV_CPB_RESP_CPB_ERR = (1 << 7), + + /* CPB control flag bits */ + NV_CPB_CTL_CPB_VALID = (1 << 0), + NV_CPB_CTL_QUEUE = (1 << 1), + NV_CPB_CTL_APRD_VALID = (1 << 2), + NV_CPB_CTL_IEN = (1 << 3), + NV_CPB_CTL_FPDMA = (1 << 4), + + /* APRD flags */ + NV_APRD_WRITE = (1 << 1), + NV_APRD_END = (1 << 2), + NV_APRD_CONT = (1 << 3), + + /* NV_ADMA_STAT flags */ + NV_ADMA_STAT_TIMEOUT = (1 << 0), + NV_ADMA_STAT_HOTUNPLUG = (1 << 1), + NV_ADMA_STAT_HOTPLUG = (1 << 2), + NV_ADMA_STAT_CPBERR = (1 << 4), + NV_ADMA_STAT_SERROR = (1 << 5), + NV_ADMA_STAT_CMD_COMPLETE = (1 << 6), + NV_ADMA_STAT_IDLE = (1 << 8), + NV_ADMA_STAT_LEGACY = (1 << 9), + NV_ADMA_STAT_STOPPED = (1 << 10), + NV_ADMA_STAT_DONE = (1 << 12), + NV_ADMA_STAT_ERR = NV_ADMA_STAT_CPBERR | + NV_ADMA_STAT_TIMEOUT, + + /* port flags */ + NV_ADMA_PORT_REGISTER_MODE = (1 << 0), + +}; + +/* ADMA Physical Region Descriptor - one SG segment */ +struct nv_adma_prd { + __le64 addr; + __le32 len; + u8 flags; + u8 packet_len; + __le16 reserved; +}; + +enum nv_adma_regbits { + CMDEND = (1 << 15), /* end of command list */ + WNB = (1 << 14), /* wait-not-BSY */ + IGN = (1 << 13), /* ignore this entry */ + CS1n = (1 << (4 + 8)), /* std. PATA signals follow... */ + DA2 = (1 << (2 + 8)), + DA1 = (1 << (1 + 8)), + DA0 = (1 << (0 + 8)), +}; + +/* ADMA Command Parameter Block + The first 5 SG segments are stored inside the Command Parameter Block itself. + If there are more than 5 segments the remainder are stored in a separate + memory area indicated by next_aprd. */ +struct nv_adma_cpb { + u8 resp_flags; /* 0 */ + u8 reserved1; /* 1 */ + u8 ctl_flags; /* 2 */ + /* len is length of taskfile in 64 bit words */ + u8 len; /* 3 */ + u8 tag; /* 4 */ + u8 next_cpb_idx; /* 5 */ + __le16 reserved2; /* 6-7 */ + __le16 tf[12]; /* 8-31 */ + struct nv_adma_prd aprd[5]; /* 32-111 */ + __le64 next_aprd; /* 112-119 */ + __le64 reserved3; /* 120-127 */ }; + +struct nv_adma_port_priv { + struct nv_adma_cpb *cpb; + dma_addr_t cpb_dma; + struct nv_adma_prd *aprd; + dma_addr_t aprd_dma; + u8 flags; +}; + +#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void nv_ck804_host_stop(struct ata_host *host); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); @@ -93,13 +230,27 @@ static void nv_nf2_thaw(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); static void nv_error_handler(struct ata_port *ap); +static int nv_adma_slave_config(struct scsi_device *sdev); +static void nv_adma_qc_prep(struct ata_queued_cmd *qc); +static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc); +static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance); +static void nv_adma_irq_clear(struct ata_port *ap); +static int nv_adma_port_start(struct ata_port *ap); +static void nv_adma_port_stop(struct ata_port *ap); +static void nv_adma_error_handler(struct ata_port *ap); +static void nv_adma_host_stop(struct ata_host *host); +static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc); +static void nv_adma_bmdma_start(struct ata_queued_cmd *qc); +static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc); +static u8 nv_adma_bmdma_status(struct ata_port *ap); enum nv_host_type { GENERIC, NFORCE2, NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ - CK804 + CK804, + ADMA }; static const struct pci_device_id nv_pci_tbl[] = { @@ -160,6 +311,25 @@ static struct scsi_host_template nv_sht = { .bios_param = ata_std_bios_param, }; +static struct scsi_host_template nv_adma_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = NV_ADMA_MAX_CPBS, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN, + .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 = NV_ADMA_DMA_BOUNDARY, + .slave_configure = nv_adma_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + static const struct ata_port_operations nv_generic_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -241,6 +411,33 @@ static const struct ata_port_operations nv_ck804_ops = { .host_stop = nv_ck804_host_stop, }; +static const struct ata_port_operations nv_adma_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + .bmdma_setup = nv_adma_bmdma_setup, + .bmdma_start = nv_adma_bmdma_start, + .bmdma_stop = nv_adma_bmdma_stop, + .bmdma_status = nv_adma_bmdma_status, + .qc_prep = nv_adma_qc_prep, + .qc_issue = nv_adma_qc_issue, + .freeze = nv_ck804_freeze, + .thaw = nv_ck804_thaw, + .error_handler = nv_adma_error_handler, + .post_internal_cmd = nv_adma_bmdma_stop, + .data_xfer = ata_mmio_data_xfer, + .irq_handler = nv_adma_interrupt, + .irq_clear = nv_adma_irq_clear, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, + .port_start = nv_adma_port_start, + .port_stop = nv_adma_port_stop, + .host_stop = nv_adma_host_stop, +}; + static struct ata_port_info nv_port_info[] = { /* generic */ { @@ -269,6 +466,16 @@ static struct ata_port_info nv_port_info[] = { .udma_mask = NV_UDMA_MASK, .port_ops = &nv_ck804_ops, }, + /* ADMA */ + { + .sht = &nv_adma_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_adma_ops, + }, }; MODULE_AUTHOR("NVIDIA"); @@ -277,6 +484,614 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); +static int adma_enabled = 1; + +static int nv_adma_slave_config(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + u64 bounce_limit; + unsigned long segment_boundary; + unsigned short sg_tablesize; + int rc; + + rc = ata_scsi_slave_config(sdev); + + if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun) + /* Not a proper libata device, ignore */ + return rc; + + if (ap->device[sdev->id].class == ATA_DEV_ATAPI) { + /* + * NVIDIA reports that ADMA mode does not support ATAPI commands. + * Therefore ATAPI commands are sent through the legacy interface. + * However, the legacy interface only supports 32-bit DMA. + * Restrict DMA parameters as required by the legacy interface + * when an ATAPI device is connected. + */ + bounce_limit = ATA_DMA_MASK; + segment_boundary = ATA_DMA_BOUNDARY; + /* Subtract 1 since an extra entry may be needed for padding, see + libata-scsi.c */ + sg_tablesize = LIBATA_MAX_PRD - 1; + } + else { + bounce_limit = *ap->dev->dma_mask; + segment_boundary = NV_ADMA_DMA_BOUNDARY; + sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; + } + + blk_queue_bounce_limit(sdev->request_queue, bounce_limit); + blk_queue_segment_boundary(sdev->request_queue, segment_boundary); + blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); + ata_port_printk(ap, KERN_INFO, + "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n", + (unsigned long long)bounce_limit, segment_boundary, sg_tablesize); + return rc; +} + +static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb) +{ + unsigned int idx = 0; + + cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB); + + if ((tf->flags & ATA_TFLAG_LBA48) == 0) { + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + } + else { + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah); + } + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah); + + cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND); + + return idx; +} + +static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio, + unsigned int port_no) +{ + mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE; + return mmio; +} + +static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap) +{ + return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no); +} + +static inline void __iomem *nv_adma_gen_block(struct ata_port *ap) +{ + return (ap->host->mmio_base + NV_ADMA_GEN); +} + +static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap) +{ + return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no)); +} + +static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) +{ + struct nv_adma_port_priv *pp = ap->private_data; + int complete = 0, have_err = 0; + u16 flags = pp->cpb[cpb_num].resp_flags; + + VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); + + if (flags & NV_CPB_RESP_DONE) { + VPRINTK("CPB flags done, flags=0x%x\n", flags); + complete = 1; + } + if (flags & NV_CPB_RESP_ATA_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if (flags & NV_CPB_RESP_CMD_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if (flags & NV_CPB_RESP_CPB_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if(complete || force_err) + { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); + if(likely(qc)) { + u8 ata_status = 0; + /* Only use the ATA port status for non-NCQ commands. + For NCQ commands the current status may have nothing to do with + the command just completed. */ + if(qc->tf.protocol != ATA_PROT_NCQ) + ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4)); + + if(have_err || force_err) + ata_status |= ATA_ERR; + + qc->err_mask |= ac_err_mask(ata_status); + DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, + qc->err_mask); + ata_qc_complete(qc); + } + } +} + +static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + int i, handled = 0; + + spin_lock(&host->lock); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 status; + u32 gen_ctl; + int have_global_err = 0; + u32 notifier, notifier_error; + + /* if in ATA register mode, use standard ata interrupt handler */ + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + struct ata_queued_cmd *qc; + VPRINTK("in ATA register mode\n"); + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) + handled += ata_host_intr(ap, qc); + else { + /* No request pending? Clear interrupt status + anyway, in case there's one pending. */ + ap->ops->check_status(ap); + handled++; + } + continue; + } + + notifier = readl(mmio + NV_ADMA_NOTIFIER); + notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + + gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + + /* Seems necessary to clear notifiers even when they were 0. + Otherwise we seem to stop receiving further interrupts. + Unsure why. */ + writel(notifier | notifier_error, nv_adma_notifier_clear_block(ap)); + + if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier && + !notifier_error) + /* Nothing to do */ + continue; + + status = readw(mmio + NV_ADMA_STAT); + + /* Clear status. Ensure the controller sees the clearing before we start + looking at any of the CPB statuses, so that any CPB completions after + this point in the handler will raise another interrupt. */ + writew(status, mmio + NV_ADMA_STAT); + readw(mmio + NV_ADMA_STAT); /* flush posted write */ + rmb(); + + /* freeze if hotplugged */ + if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) { + ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n"); + ata_port_freeze(ap); + handled++; + continue; + } + + if (status & NV_ADMA_STAT_TIMEOUT) { + ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status); + have_global_err = 1; + } + if (status & NV_ADMA_STAT_CPBERR) { + ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status); + have_global_err = 1; + } + if ((status & NV_ADMA_STAT_DONE) || have_global_err) { + /** Check CPBs for completed commands */ + + if(ata_tag_valid(ap->active_tag)) + /* Non-NCQ command */ + nv_adma_check_cpb(ap, ap->active_tag, have_global_err || + (notifier_error & (1 << ap->active_tag))); + else { + int pos; + u32 active = ap->sactive; + while( (pos = ffs(active)) ) { + pos--; + nv_adma_check_cpb(ap, pos, have_global_err || + (notifier_error & (1 << pos)) ); + active &= ~(1 << pos ); + } + } + } + + handled++; /* irq handled if we got here */ + } + } + + spin_unlock(&host->lock); + + return IRQ_RETVAL(handled); +} + +static void nv_adma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 status = readw(mmio + NV_ADMA_STAT); + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + + /* clear ADMA status */ + writew(status, mmio + NV_ADMA_STAT); + writel(notifier | notifier_error, + nv_adma_notifier_clear_block(ap)); + + /** clear legacy status */ + ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_irq_clear(ap); + ap->flags |= ATA_FLAG_MMIO; +} + +static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + WARN_ON(1); + return; + } + + qc->ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_setup(qc); + qc->ap->flags |= ATA_FLAG_MMIO; +} + +static void nv_adma_bmdma_start(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + WARN_ON(1); + return; + } + + qc->ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_start(qc); + qc->ap->flags |= ATA_FLAG_MMIO; +} + +static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) + return; + + qc->ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_stop(qc); + qc->ap->flags |= ATA_FLAG_MMIO; +} + +static u8 nv_adma_bmdma_status(struct ata_port *ap) +{ + u8 status; + struct nv_adma_port_priv *pp = ap->private_data; + + WARN_ON(pp->flags & NV_ADMA_PORT_REGISTER_MODE); + + ap->flags &= ~ATA_FLAG_MMIO; + status = ata_bmdma_status(ap); + ap->flags |= ATA_FLAG_MMIO; + return status; +} + +static void nv_adma_register_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) + return; + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags |= NV_ADMA_PORT_REGISTER_MODE; +} + +static void nv_adma_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) + return; + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE; +} + +static int nv_adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + struct nv_adma_port_priv *pp; + int rc; + void *mem; + dma_addr_t mem_dma; + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 tmp; + + VPRINTK("ENTER\n"); + + rc = ata_port_start(ap); + if (rc) + return rc; + + pp = kzalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + rc = -ENOMEM; + goto err_out; + } + + mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, + &mem_dma, GFP_KERNEL); + + if (!mem) { + rc = -ENOMEM; + goto err_out_kfree; + } + memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: + * 128-byte command parameter block (CPB) + * one for each command tag + */ + pp->cpb = mem; + pp->cpb_dma = mem_dma; + + writel(mem_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW); + writel((mem_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH); + + mem += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ; + mem_dma += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ; + + /* + * Second item: block of ADMA_SGTBL_LEN s/g entries + */ + pp->aprd = mem; + pp->aprd_dma = mem_dma; + + ap->private_data = pp; + + /* clear any outstanding interrupt conditions */ + writew(0xffff, mmio + NV_ADMA_STAT); + + /* initialize port variables */ + pp->flags = NV_ADMA_PORT_REGISTER_MODE; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* clear GO for register mode */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + + return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void nv_adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(ap); + + VPRINTK("ENTER\n"); + + writew(0, mmio + NV_ADMA_CTL); + + ap->private_data = NULL; + dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma); + kfree(pp); + ata_port_stop(ap); +} + + +static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) +{ + void __iomem *mmio = probe_ent->mmio_base; + struct ata_ioports *ioport = &probe_ent->port[port]; + + VPRINTK("ENTER\n"); + + mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE; + + ioport->cmd_addr = (unsigned long) mmio; + ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4); + ioport->error_addr = + ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4); + ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4); + ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4); + ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4); + ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4); + ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4); + ioport->status_addr = + ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4); + ioport->altstatus_addr = + ioport->ctl_addr = (unsigned long) mmio + 0x20; +} + +static int nv_adma_host_init(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + unsigned int i; + u32 tmp32; + + VPRINTK("ENTER\n"); + + /* enable ADMA on the ports */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + tmp32 |= NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN | + NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN; + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + + for (i = 0; i < probe_ent->n_ports; i++) + nv_adma_setup_port(probe_ent, i); + + for (i = 0; i < probe_ent->n_ports; i++) { + void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i); + u16 tmp; + + /* enable interrupt, clear reset if not already clear */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + } + + return 0; +} + +static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, + struct scatterlist *sg, + int idx, + struct nv_adma_prd *aprd) +{ + u32 flags; + + memset(aprd, 0, sizeof(struct nv_adma_prd)); + + flags = 0; + if (qc->tf.flags & ATA_TFLAG_WRITE) + flags |= NV_APRD_WRITE; + if (idx == qc->n_elem - 1) + flags |= NV_APRD_END; + else if (idx != 4) + flags |= NV_APRD_CONT; + + aprd->addr = cpu_to_le64(((u64)sg_dma_address(sg))); + aprd->len = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */ + aprd->flags = cpu_to_le32(flags); +} + +static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + unsigned int idx; + struct nv_adma_prd *aprd; + struct scatterlist *sg; + + VPRINTK("ENTER\n"); + + idx = 0; + + ata_for_each_sg(sg, qc) { + aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)]; + nv_adma_fill_aprd(qc, sg, idx, aprd); + idx++; + } + if (idx > 5) + cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); +} + +static void nv_adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + struct nv_adma_cpb *cpb = &pp->cpb[qc->tag]; + u8 ctl_flags = NV_CPB_CTL_CPB_VALID | + NV_CPB_CTL_APRD_VALID | + NV_CPB_CTL_IEN; + + VPRINTK("qc->flags = 0x%lx\n", qc->flags); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP) || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + ata_qc_prep(qc); + return; + } + + memset(cpb, 0, sizeof(struct nv_adma_cpb)); + + cpb->len = 3; + cpb->tag = qc->tag; + cpb->next_cpb_idx = 0; + + /* turn on NCQ flags for NCQ commands */ + if (qc->tf.protocol == ATA_PROT_NCQ) + ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA; + + nv_adma_tf_to_cpb(&qc->tf, cpb->tf); + + nv_adma_fill_sg(qc, cpb); + + /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are + finished filling in all of the contents */ + wmb(); + cpb->ctl_flags = ctl_flags; +} + +static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) +{ + void __iomem *mmio = nv_adma_ctl_block(qc->ap); + + VPRINTK("ENTER\n"); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP) || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + /* use ATA register mode */ + VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags); + nv_adma_register_mode(qc->ap); + return ata_qc_issue_prot(qc); + } else + nv_adma_mode(qc->ap); + + /* write append register, command tag in lower 8 bits + and (number of cpbs to append -1) in top 8 bits */ + wmb(); + writew(qc->tag, mmio + NV_ADMA_APPEND); + + DPRINTK("Issued tag %u\n",qc->tag); + + return 0; +} + static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; @@ -466,6 +1281,56 @@ static void nv_error_handler(struct ata_port *ap) nv_hardreset, ata_std_postreset); } +static void nv_adma_error_handler(struct ata_port *ap) +{ + struct nv_adma_port_priv *pp = ap->private_data; + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { + void __iomem *mmio = nv_adma_ctl_block(ap); + int i; + u16 tmp; + + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + u32 status = readw(mmio + NV_ADMA_STAT); + + ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " + "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n", + notifier, notifier_error, gen_ctl, status); + + for( i=0;icpb[i]; + if( cpb->ctl_flags || cpb->resp_flags ) + ata_port_printk(ap, KERN_ERR, + "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", + i, cpb->ctl_flags, cpb->resp_flags); + } + + /* Push us back into port register mode for error handling. */ + nv_adma_register_mode(ap); + + ata_port_printk(ap, KERN_ERR, "Resetting port\n"); + + /* Mark all of the CPBs as invalid to prevent them from being executed */ + for( i=0;icpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* Reset channel */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + } + + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, + nv_hardreset, ata_std_postreset); +} + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -475,6 +1340,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; u32 bar; unsigned long base; + unsigned long type = ent->driver_data; + int mask_set = 0; // Make sure this is a SATA controller by counting the number of bars // (NVIDIA SATA controllers will always have six bars). Otherwise, @@ -483,7 +1350,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_resource_start(pdev, bar) == 0) return -ENODEV; - if (!printed_version++) + if ( !printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); @@ -496,16 +1363,26 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_disable; } - rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - goto err_out_regions; - rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - goto err_out_regions; + if(type >= CK804 && adma_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); + type = ADMA; + if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && + !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) + mask_set = 1; + } + + if(!mask_set) { + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + } rc = -ENOMEM; - ppi[0] = ppi[1] = &nv_port_info[ent->driver_data]; + ppi[0] = ppi[1] = &nv_port_info[type]; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; @@ -522,7 +1399,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; /* enable SATA space for CK804 */ - if (ent->driver_data == CK804) { + if (type >= CK804) { u8 regval; pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); @@ -532,6 +1409,12 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); + if (type == ADMA) { + rc = nv_adma_host_init(probe_ent); + if (rc) + goto err_out_iounmap; + } + rc = ata_device_add(probe_ent); if (rc != NV_PORTS) goto err_out_iounmap; @@ -566,6 +1449,33 @@ static void nv_ck804_host_stop(struct ata_host *host) ata_pci_host_stop(host); } +static void nv_adma_host_stop(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + int i; + u32 tmp32; + + for (i = 0; i < host->n_ports; i++) { + void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i); + u16 tmp; + + /* disable interrupt */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + } + + /* disable ADMA on the ports */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN | + NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN); + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + + nv_ck804_host_stop(host); +} + static int __init nv_init(void) { return pci_register_driver(&nv_pci_driver); @@ -578,3 +1488,5 @@ static void __exit nv_exit(void) module_init(nv_init); module_exit(nv_exit); +module_param_named(adma, adma_enabled, bool, 0444); +MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); -- cgit v1.2.3 From 6919a0a6cfdad9e83d02cef5973826acd416560c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 27 Oct 2006 19:08:46 -0700 Subject: [PATCH] libata: Revamp blacklist support to allow multiple kinds of blacklisting flaws Signed-off-by: Alan Cox Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 123 ++++++++++++++++++++++++++++------------------ include/linux/libata.h | 3 ++ 2 files changed, 78 insertions(+), 48 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b896119cccd3..b4fbfebafd26 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1345,7 +1345,10 @@ static void ata_dev_config_ncq(struct ata_device *dev, desc[0] = '\0'; return; } - + if (ata_device_blacklisted(dev) & ATA_HORKAGE_NONCQ) { + snprintf(desc, desc_sz, "NCQ (not used)"); + return; + } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; @@ -3014,37 +3017,55 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) return rc; } -static const char * const ata_dma_blacklist [] = { - "WDC AC11000H", NULL, - "WDC AC22100H", NULL, - "WDC AC32500H", NULL, - "WDC AC33100H", NULL, - "WDC AC31600H", NULL, - "WDC AC32100H", "24.09P07", - "WDC AC23200L", "21.10N21", - "Compaq CRD-8241B", NULL, - "CRD-8400B", NULL, - "CRD-8480B", NULL, - "CRD-8482B", NULL, - "CRD-84", NULL, - "SanDisk SDP3B", NULL, - "SanDisk SDP3B-64", NULL, - "SANYO CD-ROM CRD", NULL, - "HITACHI CDR-8", NULL, - "HITACHI CDR-8335", NULL, - "HITACHI CDR-8435", NULL, - "Toshiba CD-ROM XM-6202B", NULL, - "TOSHIBA CD-ROM XM-1702BC", NULL, - "CD-532E-A", NULL, - "E-IDE CD-ROM CR-840", NULL, - "CD-ROM Drive/F5A", NULL, - "WPI CDD-820", NULL, - "SAMSUNG CD-ROM SC-148C", NULL, - "SAMSUNG CD-ROM SC", NULL, - "SanDisk SDP3B-64", NULL, - "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL, - "_NEC DV5800A", NULL, - "SAMSUNG CD-ROM SN-124", "N001" +struct ata_blacklist_entry { + const char *model_num; + const char *model_rev; + unsigned long horkage; +}; + +static const struct ata_blacklist_entry ata_device_blacklist [] = { + /* Devices with DMA related problems under Linux */ + { "WDC AC11000H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC22100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32500H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC33100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC31600H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32100H", "24.09P07", ATA_HORKAGE_NODMA }, + { "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA }, + { "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8400B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8480B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8482B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-84", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA }, + { "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA }, + { "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA }, + { "CD-532E-A", NULL, ATA_HORKAGE_NODMA }, + { "E-IDE CD-ROM CR-840",NULL, ATA_HORKAGE_NODMA }, + { "CD-ROM Drive/F5A", NULL, ATA_HORKAGE_NODMA }, + { "WPI CDD-820", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC-148C", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA }, + { "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA }, + + /* Devices we expect to fail diagnostics */ + + /* Devices where NCQ should be avoided */ + /* NCQ is slow */ + { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ }, + + /* Devices with NCQ limits */ + + /* End Marker */ + { } }; static int ata_strim(char *s, size_t len) @@ -3059,20 +3080,12 @@ static int ata_strim(char *s, size_t len) return len; } -static int ata_dma_blacklisted(const struct ata_device *dev) +unsigned long ata_device_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; unsigned char model_rev[16]; unsigned int nlen, rlen; - int i; - - /* We don't support polling DMA. - * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) - * if the LLDD handles only interrupts in the HSM_ST_LAST state. - */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && - (dev->flags & ATA_DFLAG_CDB_INTR)) - return 1; + const struct ata_blacklist_entry *ad = ata_device_blacklist; ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); @@ -3081,17 +3094,30 @@ static int ata_dma_blacklisted(const struct ata_device *dev) nlen = ata_strim(model_num, sizeof(model_num)); rlen = ata_strim(model_rev, sizeof(model_rev)); - for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) { - if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) { - if (ata_dma_blacklist[i+1] == NULL) - return 1; - if (!strncmp(ata_dma_blacklist[i], model_rev, rlen)) - return 1; + while (ad->model_num) { + if (!strncmp(ad->model_num, model_num, nlen)) { + if (ad->model_rev == NULL) + return ad->horkage; + if (!strncmp(ad->model_rev, model_rev, rlen)) + return ad->horkage; } + ad++; } return 0; } +static int ata_dma_blacklisted(const struct ata_device *dev) +{ + /* We don't support polling DMA. + * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) + * if the LLDD handles only interrupts in the HSM_ST_LAST state. + */ + if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + (dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + return (ata_device_blacklisted(dev) & ATA_HORKAGE_NODMA) ? 1 : 0; +} + /** * ata_dev_xfermask - Compute supported xfermask of the given device * @dev: Device to compute xfermask for @@ -6153,6 +6179,7 @@ EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_device_blacklisted); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); diff --git a/include/linux/libata.h b/include/linux/libata.h index abd2debebca2..2300fcc37f80 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -307,6 +307,8 @@ enum { (some horkage may be drive/controller pair dependant */ ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ }; enum hsm_task_states { @@ -787,6 +789,7 @@ extern void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); +extern unsigned long ata_device_blacklisted(const struct ata_device *dev); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); -- cgit v1.2.3 From a20c9e820864e18b59d2a4f2f04e8b6053986c95 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 27 Oct 2006 19:08:48 -0700 Subject: [PATCH] ata: Generic platform_device libata driver needs a changelog Signed-off-by: Paul Mundt Acked-by: Russell King Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_platform.c | 295 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pata_platform.h | 13 ++ 4 files changed, 318 insertions(+) create mode 100644 drivers/ata/pata_platform.c create mode 100644 include/linux/pata_platform.h diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 9b07e70bee7d..98d0f01c90eb 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -499,6 +499,15 @@ config PATA_WINBOND_VLB Support for the Winbond W83759A controller on Vesa Local Bus systems. +config PATA_PLATFORM + tristate "Generic platform device PATA support" + depends on EMBEDDED + help + This option enables support for generic directly connected ATA + devices commonly found on embedded systems. + + If unsure, say N. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index ceba7d824a62..f2b3ea2d15d0 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o +obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c new file mode 100644 index 000000000000..63d6687f0ba9 --- /dev/null +++ b/drivers/ata/pata_platform.c @@ -0,0 +1,295 @@ +/* + * Generic platform device PATA driver + * + * Copyright (C) 2006 Paul Mundt + * + * Based on pata_pcmcia: + * + * Copyright 2005-2006 Red Hat Inc , all rights reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_platform" +#define DRV_VERSION "0.1.2" + +static int pio_mask = 1; + +/* + * Provide our own set_mode() as we don't want to change anything that has + * already been configured.. + */ +static void pata_platform_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_enabled(dev)) { + /* We don't really care */ + dev->pio_mode = dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + } + } +} + +static void pata_platform_host_stop(struct ata_host *host) +{ + int i; + + /* + * Unmap the bases for MMIO + */ + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->flags & ATA_FLAG_MMIO) { + iounmap((void __iomem *)ap->ioaddr.ctl_addr); + iounmap((void __iomem *)ap->ioaddr.cmd_addr); + } + } +} + +static struct scsi_host_template pata_platform_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, +}; + +static struct ata_port_operations pata_platform_port_ops = { + .set_mode = pata_platform_set_mode, + + .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, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_pio_data_xfer_noirq, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = pata_platform_host_stop +}; + +static void pata_platform_setup_port(struct ata_ioports *ioaddr, + struct pata_platform_info *info) +{ + unsigned int shift = 0; + + /* Fixup the port shift for platforms that need it */ + if (info && info->ioport_shift) + shift = info->ioport_shift; + + ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); + ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); + ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); + ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); + ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); + ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); + ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); + ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); + ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); + ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); +} + +/** + * pata_platform_probe - attach a platform interface + * @pdev: platform device + * + * Register a platform bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + * + * Platform devices are expected to contain 3 resources per port: + * + * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) + * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) + * - IRQ (IORESOURCE_IRQ) + * + * If the base resources are both mem types, the ioremap() is handled + * here. For IORESOURCE_IO, it's assumed that there's no remapping + * necessary. + */ +static int __devinit pata_platform_probe(struct platform_device *pdev) +{ + struct resource *io_res, *ctl_res; + struct ata_probe_ent ae; + unsigned int mmio; + int ret; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 3)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the I/O base first + */ + io_res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (io_res == NULL) { + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(io_res == NULL)) + return -EINVAL; + } + + /* + * Then the CTL base + */ + ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (ctl_res == NULL) { + ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (unlikely(ctl_res == NULL)) + return -EINVAL; + } + + /* + * Check for MMIO + */ + mmio = (( io_res->flags == IORESOURCE_MEM) && + (ctl_res->flags == IORESOURCE_MEM)); + + /* + * Now that that's out of the way, wire up the port.. + */ + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = &pata_platform_port_ops; + ae.sht = &pata_platform_sht; + ae.n_ports = 1; + ae.pio_mask = pio_mask; + ae.irq = platform_get_irq(pdev, 0); + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + + /* + * Handle the MMIO case + */ + if (mmio) { + ae.port_flags |= ATA_FLAG_MMIO; + + ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start, + io_res->end - io_res->start + 1); + if (unlikely(!ae.port[0].cmd_addr)) { + dev_err(&pdev->dev, "failed to remap IO base\n"); + return -ENXIO; + } + + ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start, + ctl_res->end - ctl_res->start + 1); + if (unlikely(!ae.port[0].ctl_addr)) { + dev_err(&pdev->dev, "failed to remap CTL base\n"); + ret = -ENXIO; + goto bad_remap; + } + } else { + ae.port[0].cmd_addr = io_res->start; + ae.port[0].ctl_addr = ctl_res->start; + } + + ae.port[0].altstatus_addr = ae.port[0].ctl_addr; + + pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); + + if (unlikely(ata_device_add(&ae) == 0)) { + ret = -ENODEV; + goto add_failed; + } + + return 0; + +add_failed: + if (ae.port[0].ctl_addr && mmio) + iounmap((void __iomem *)ae.port[0].ctl_addr); +bad_remap: + if (ae.port[0].cmd_addr && mmio) + iounmap((void __iomem *)ae.port[0].cmd_addr); + + return ret; +} + +/** + * pata_platform_remove - unplug a platform interface + * @pdev: platform device + * + * A platform bus ATA device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit pata_platform_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_remove(host); + dev_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver pata_platform_driver = { + .probe = pata_platform_probe, + .remove = __devexit_p(pata_platform_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pata_platform_init(void) +{ + return platform_driver_register(&pata_platform_driver); +} + +static void __exit pata_platform_exit(void) +{ + platform_driver_unregister(&pata_platform_driver); +} +module_init(pata_platform_init); +module_exit(pata_platform_exit); + +module_param(pio_mask, int, 0); + +MODULE_AUTHOR("Paul Mundt"); +MODULE_DESCRIPTION("low-level driver for platform device ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/include/linux/pata_platform.h b/include/linux/pata_platform.h new file mode 100644 index 000000000000..2d5fd647e0e9 --- /dev/null +++ b/include/linux/pata_platform.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_PATA_PLATFORM_H +#define __LINUX_PATA_PLATFORM_H + +struct pata_platform_info { + /* + * I/O port shift, for platforms with ports that are + * constantly spaced and need larger than the 1-byte + * spacing used by ata_std_ports(). + */ + unsigned int ioport_shift; +}; + +#endif /* __LINUX_PATA_PLATFORM_H */ -- cgit v1.2.3 From d1adc1bbd6dde3e05a91e2d3e6ab42d202ea61d5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 9 Oct 2006 18:32:15 +0900 Subject: [PATCH] libata: handle 0xff status properly libata waits for !BSY even when the status register reports 0xff. This causes long boot delays when D8 isn't pulled down properly. This patch does the followings. * don't wait if status register is 0xff in all wait functions * make ata_busy_sleep() return 0 on success and -errno on failure. -ENODEV is returned on 0xff status and -EBUSY on other failures. * make ata_bus_softreset() succeed on 0xff status. 0xff status is not reset failure. It indicates no device. This removes unnecessary retries on such ports. Note that the code change assumes unoccupied port reporting 0xff status does not produce valid device signature. Signed-off-by: Tejun Heo Cc: Joe Jin Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 30 ++++++++++++++++++------------ include/linux/libata.h | 9 ++++----- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b4fbfebafd26..d2336673601c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2328,11 +2328,14 @@ static inline void ata_tf_to_host(struct ata_port *ap, * Sleep until ATA Status register bit BSY clears, * or a timeout occurs. * - * LOCKING: None. + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. */ - -unsigned int ata_busy_sleep (struct ata_port *ap, - unsigned long tmout_pat, unsigned long tmout) +int ata_busy_sleep(struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) { unsigned long timer_start, timeout; u8 status; @@ -2340,27 +2343,32 @@ unsigned int ata_busy_sleep (struct ata_port *ap, status = ata_busy_wait(ap, ATA_BUSY, 300); timer_start = jiffies; timeout = timer_start + tmout_pat; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_busy_wait(ap, ATA_BUSY, 3); } - if (status & ATA_BUSY) + if (status != 0xff && (status & ATA_BUSY)) ata_port_printk(ap, KERN_WARNING, "port is slow to respond, please be patient " "(Status 0x%x)\n", status); timeout = timer_start + tmout; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_chk_status(ap); } + if (status == 0xff) + return -ENODEV; + if (status & ATA_BUSY) { ata_port_printk(ap, KERN_ERR, "port failed to respond " "(%lu secs, Status 0x%x)\n", tmout / HZ, status); - return 1; + return -EBUSY; } return 0; @@ -2451,10 +2459,8 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, * the bus shows 0xFF because the odd clown forgets the D7 * pulldown resistor. */ - if (ata_check_status(ap) == 0xFF) { - ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n"); - return AC_ERR_OTHER; - } + if (ata_check_status(ap) == 0xFF) + return 0; ata_bus_post_reset(ap, devmask); diff --git a/include/linux/libata.h b/include/linux/libata.h index 2300fcc37f80..6c003d852a88 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -746,9 +746,8 @@ extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t mesg); extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); -extern unsigned int ata_busy_sleep(struct ata_port *ap, - unsigned long timeout_pat, - unsigned long timeout); +extern int ata_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, unsigned long timeout); extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, @@ -1064,7 +1063,7 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, udelay(10); status = ata_chk_status(ap); max--; - } while ((status & bits) && (max > 0)); + } while (status != 0xff && (status & bits) && (max > 0)); return status; } @@ -1085,7 +1084,7 @@ static inline u8 ata_wait_idle(struct ata_port *ap) { u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - if (status & (ATA_BUSY | ATA_DRQ)) { + if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) { unsigned long l = ap->ioaddr.status_addr; if (ata_msg_warn(ap)) printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", -- cgit v1.2.3 From 90088bb41200b4da962282dfd45db82544adac3b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 9 Oct 2006 11:10:26 +0900 Subject: [PATCH] libata: move ata_irq_on() into libata-sff.c ata_irq_on() isn't used outside of libata core layer. The function is TF/SFF interface specific but currently used by core path with some hack too. Move it from include/linux/libata.h to drivers/ata/libata-sff.c. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 29 +++++++++++++++++++++++++++++ drivers/ata/libata.h | 3 +++ include/linux/libata.h | 31 ------------------------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index e178d6ae8b80..37471d3c1c28 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -38,6 +38,35 @@ #include "libata.h" +/** + * ata_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Enable interrupts on a legacy IDE device using MMIO or PIO, + * wait for idle, clear any pending interrupts. + * + * LOCKING: + * Inherited from caller. + */ +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; +} + /** * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0ed263be652a..c83300055ec5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -120,4 +120,7 @@ extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +/* libata-sff.c */ +extern u8 ata_irq_on(struct ata_port *ap); + #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 6c003d852a88..d3bf7b936c3f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1149,37 +1149,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->result_tf.feature = 0; } -/** - * ata_irq_on - Enable interrupts on a port. - * @ap: Port on which interrupts are enabled. - * - * Enable interrupts on a legacy IDE device using MMIO or PIO, - * wait for idle, clear any pending interrupts. - * - * LOCKING: - * Inherited from caller. - */ - -static inline u8 ata_irq_on(struct ata_port *ap) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; - - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; - - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - tmp = ata_wait_idle(ap); - - ap->ops->irq_clear(ap); - - return tmp; -} - - /** * ata_irq_ack - Acknowledge a device interrupt. * @ap: Port on which interrupts are enabled. -- cgit v1.2.3 From 722420fe6e2ab63bebc5a9ea346016b59076d75d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Sep 2006 17:49:22 +0900 Subject: [PATCH] sata_nv: SRST sometimes fails after hotplug, use HRST_TO_RESUME NV controllers sometimes fail to perform softreset after hotplug. Make it use hardreset to resume link. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_nv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index e5615be21565..a57710107619 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -442,7 +442,8 @@ static struct ata_port_info nv_port_info[] = { /* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -451,7 +452,8 @@ static struct ata_port_info nv_port_info[] = { /* nforce2/3 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -460,7 +462,8 @@ static struct ata_port_info nv_port_info[] = { /* ck804 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, -- cgit v1.2.3 From 309afcb5c87b5a41da51cc0c36f61c0e0d43ca9a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Sep 2006 18:07:17 +0900 Subject: [PATCH] libata: make user scan wait for scan to complete Make user scan wait for scan to complete. This way user can wait for warm plug request to complete and is prevented from causing EH event storm by repetitively issuing scan request while EH is in progress. Signed-off-by: Tejun Heo Cc: Fajun Chen Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 47ea111d5ace..6b2553dae489 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3182,10 +3182,12 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, rc = -EINVAL; } - if (rc == 0) + if (rc == 0) { ata_port_schedule_eh(ap); - - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); + } else + spin_unlock_irqrestore(ap->lock, flags); return rc; } -- cgit v1.2.3 From 28c8f3b4f9ec9a5acffdc846effb0695839ecf37 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Oct 2006 08:47:18 +0900 Subject: [PATCH] sata_sil24: rename PMP related constants Rename PMP related constants for consistency. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 169e200a6a71..64882585a9e3 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -100,10 +100,10 @@ enum { */ PORT_REGS_SIZE = 0x2000, - PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */ + PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ - PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ /* 32 bit regs */ PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ @@ -139,9 +139,9 @@ enum { PORT_CS_INIT = (1 << 2), /* port initialize */ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ - PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ - PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ /* PORT_IRQ_STAT/ENABLE_SET/CLR */ @@ -562,7 +562,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) /* do SRST */ prb->ctrl = cpu_to_le16(PRB_CTRL_SRST); - prb->fis[1] = 0; /* no PM yet */ + prb->fis[1] = 0; /* no PMP yet */ writel((u32)paddr, port + PORT_CMD_ACTIVATE); writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); @@ -1050,7 +1050,8 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports, writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, + port + PORT_CTRL_CLR); } /* Turn on interrupts */ -- cgit v1.2.3 From c0c559083a084f9a19443d522b7d95a33701505a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Oct 2006 08:47:18 +0900 Subject: [PATCH] sata_sil24: add PMP related constants Add PMP related constants. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 64882585a9e3..5aa288d2fb86 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -104,6 +104,10 @@ enum { PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ + PORT_PMP_STATUS = 0x0000, /* port device status offset */ + PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ + PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ + /* 32 bit regs */ PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ @@ -126,6 +130,7 @@ enum { PORT_PHY_CFG = 0x1050, PORT_SLOT_STAT = 0x1800, PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_CONTEXT = 0x1e04, PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ PORT_SCONTROL = 0x1f00, -- cgit v1.2.3 From 4aeb0e3283351351a5381a495ea24537f3bc21cb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 17:58:33 +0900 Subject: [PATCH] ahci: kill AHCI_FLAG_RESET_NEEDS_CLO Now that ahci_softreset() is fixed to automatically perform CLO if BSY/DRQ is set on entry, AHCI_FLAG_RESET_NEEDS_CLO is redundant. Kill it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index bddb14e91d3c..413270b2c794 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -167,9 +167,8 @@ enum { AHCI_FLAG_MSI = (1 << 0), /* ap->flags bits */ - AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24), - AHCI_FLAG_NO_NCQ = (1 << 25), - AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 26), /* ignore IRQ_IF_ERR */ + AHCI_FLAG_NO_NCQ = (1 << 24), + AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ }; struct ahci_cmd_hdr { @@ -291,8 +290,7 @@ static const struct ata_port_info ahci_port_info[] = { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | - AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ, + ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_NO_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, @@ -729,17 +727,6 @@ static int ahci_clo(struct ata_port *ap) return 0; } -static int ahci_prereset(struct ata_port *ap) -{ - if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) && - (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) { - /* ATA_BUSY hasn't cleared, so send a CLO */ - ahci_clo(ap); - } - - return ata_std_prereset(ap); -} - static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_port_priv *pp = ap->private_data; @@ -1196,7 +1183,7 @@ static void ahci_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset, + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, ahci_postreset); } -- cgit v1.2.3 From b6103f6d1659e2024776bc759d28613fb36344a8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 17:59:53 +0900 Subject: [PATCH] libata: separate out and export sata_port_hardreset() Separate out sata_port_hardreset() from sata_std_hardreset(). This will be used by LLD hardreset implementation and later by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 52 ++++++++++++++++++++++++++++++++++++++--------- include/linux/libata.h | 2 ++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d2336673601c..315f46841f68 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2786,9 +2786,9 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) } /** - * sata_std_hardreset - reset host port via SATA phy reset + * sata_port_hardreset - reset port via SATA phy reset * @ap: port to reset - * @class: resulting class of attached device + * @timing: timing parameters { interval, duratinon, timeout } in msec * * SATA phy-reset host port using DET bits of SControl register. * @@ -2798,10 +2798,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) { - struct ata_eh_context *ehc = &ap->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); u32 scontrol; int rc; @@ -2814,24 +2812,24 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) * and Sil3124. */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x304; if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; sata_set_spd(ap); } /* issue phy wake/reset */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x301; if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. @@ -2839,7 +2837,40 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) msleep(1); /* bring phy back */ - sata_phy_resume(ap, timing); + rc = sata_phy_resume(ap, timing); + out: + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_std_hardreset - reset host port via SATA phy reset + * @ap: port to reset + * @class: resulting class of attached device + * + * SATA phy-reset host port using DET bits of SControl register, + * wait for !BSY and classify the attached device. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +{ + const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_port_hardreset(ap, timing); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } /* TODO: phy layer with polling, timeouts, etc. */ if (ata_port_offline(ap)) { @@ -6159,6 +6190,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); +EXPORT_SYMBOL_GPL(sata_port_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); diff --git a/include/linux/libata.h b/include/linux/libata.h index d3bf7b936c3f..41fa0890dbfb 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -702,6 +702,8 @@ extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param); extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param); extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); +extern int sata_port_hardreset(struct ata_port *ap, + const unsigned long *timing); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); extern void ata_port_disable(struct ata_port *); -- cgit v1.2.3 From ad616ffbda8caf3ce76d2b43027e789d732abf48 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 18:00:24 +0900 Subject: [PATCH] ahci: update ahci-vt8251 reset sequence ahci-vt8251 * requires hardreset after PHY status change * doesn't clear BSY on signature FIS after hardreset * needs SError cleared for the port to operate after hardreset This patch implements ahci_vt8251_hardreset() and sets ATA_FLAG_HRST_TO_RESUME to handle the above behaviors. This fixes EH including hotplug on vt8251. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 413270b2c794..8a1f4f059a43 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -215,6 +215,7 @@ static u8 ahci_check_status(struct ata_port *ap); static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap); +static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_port_resume(struct ata_port *ap); @@ -274,6 +275,37 @@ static const struct ata_port_operations ahci_ops = { .port_stop = ahci_port_stop, }; +static const struct ata_port_operations ahci_vt8251_ops = { + .port_disable = ata_port_disable, + + .check_status = ahci_check_status, + .check_altstatus = ahci_check_status, + .dev_select = ata_noop_dev_select, + + .tf_read = ahci_tf_read, + + .qc_prep = ahci_qc_prep, + .qc_issue = ahci_qc_issue, + + .irq_handler = ahci_interrupt, + .irq_clear = ahci_irq_clear, + + .scr_read = ahci_scr_read, + .scr_write = ahci_scr_write, + + .freeze = ahci_freeze, + .thaw = ahci_thaw, + + .error_handler = ahci_vt8251_error_handler, + .post_internal_cmd = ahci_post_internal_cmd, + + .port_suspend = ahci_port_suspend, + .port_resume = ahci_port_resume, + + .port_start = ahci_port_start, + .port_stop = ahci_port_stop, +}; + static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { @@ -290,10 +322,11 @@ static const struct ata_port_info ahci_port_info[] = { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_NO_NCQ, + ATA_FLAG_SKIP_D2H_BSY | + ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &ahci_ops, + .port_ops = &ahci_vt8251_ops, }, /* board_ahci_ign_iferr */ { @@ -864,6 +897,31 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) return rc; } +static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) +{ + void __iomem *mmio = ap->host->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + int rc; + + DPRINTK("ENTER\n"); + + ahci_stop_engine(port_mmio); + + rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); + + /* vt8251 needs SError cleared for the port to operate */ + ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); + + ahci_start_engine(port_mmio); + + DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); + + /* vt8251 doesn't clear BSY on signature FIS reception, + * request follow-up softreset. + */ + return rc ?: -EAGAIN; +} + static void ahci_postreset(struct ata_port *ap, unsigned int *class) { void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; @@ -1187,6 +1245,22 @@ static void ahci_error_handler(struct ata_port *ap) ahci_postreset); } +static void ahci_vt8251_error_handler(struct ata_port *ap) +{ + void __iomem *mmio = ap->host->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { + /* restart engine */ + ahci_stop_engine(port_mmio); + ahci_start_engine(port_mmio); + } + + /* perform recovery */ + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, + ahci_postreset); +} + static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; -- cgit v1.2.3 From efdaedc443e935eda82e9e78a6e65d1f993d242f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 18:38:52 +0900 Subject: [PATCH] libata: implement ATA_EHI_PRINTINFO Implement ehi flag ATA_EHI_PRINTINFO. This flag is set when device configuration needs to print out device info. This used to be handled by @print_info argument to ata_dev_configure() but LLDs also need to know about it in ->dev_config() callback. This patch replaces @print_info w/ ATA_EHI_PRINTINFO and make sata_sil print workaround messages only on the initial configuration. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 10 ++++++---- drivers/ata/libata-eh.c | 7 +++++-- drivers/ata/libata.h | 2 +- drivers/ata/sata_sil.c | 11 +++++++---- include/linux/libata.h | 1 + 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 315f46841f68..e294731a7edd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1377,7 +1377,6 @@ static void ata_set_port_max_cmd_len(struct ata_port *ap) /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure - * @print_info: Enable device info printout * * Configure @dev according to @dev->id. Generic and low-level * driver specific fixups are also applied. @@ -1388,9 +1387,10 @@ static void ata_set_port_max_cmd_len(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise */ -int ata_dev_configure(struct ata_device *dev, int print_info) +int ata_dev_configure(struct ata_device *dev) { struct ata_port *ap = dev->ap; + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ @@ -1638,7 +1638,9 @@ int ata_bus_probe(struct ata_port *ap) if (rc) goto fail; - rc = ata_dev_configure(dev, 1); + ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } @@ -3045,7 +3047,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ - rc = ata_dev_configure(dev, 0); + rc = ata_dev_configure(dev); if (rc == 0) return 0; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 02b2b2787d9b..7c446442616c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1661,8 +1661,11 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, dev->class = ehc->classes[dev->devno]; rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); - if (rc == 0) - rc = ata_dev_configure(dev, 1); + if (rc == 0) { + ehc->i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ehc->i.flags &= ~ATA_EHI_PRINTINFO; + } if (rc) { dev->class = ATA_DEV_UNKNOWN; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index c83300055ec5..e4ffb2e38992 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -54,7 +54,7 @@ extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int post_reset, u16 *id); extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); -extern int ata_dev_configure(struct ata_device *dev, int print_info); +extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index ca8d99312472..f844a1faba18 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -534,6 +534,7 @@ static void sil_thaw(struct ata_port *ap) */ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[41]; @@ -549,16 +550,18 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) if (slow_down || ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE))) { - ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix " - "(mod15write workaround)\n"); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Seagate " + "errata fix (mod15write workaround)\n"); dev->max_sectors = 15; return; } /* limit to udma5 */ if (quirks & SIL_QUIRK_UDMA5MAX) { - ata_dev_printk(dev, KERN_INFO, - "applying Maxtor errata fix %s\n", model_num); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Maxtor " + "errata fix %s\n", model_num); dev->udma_mask &= ATA_UDMA5; return; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 41fa0890dbfb..949484627e67 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -283,6 +283,7 @@ enum { ATA_EHI_QUIET = (1 << 3), /* be quiet */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ + ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, -- cgit v1.2.3 From baa1e78a834c917984a4659fd282f712c17ee3bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 18:39:27 +0900 Subject: [PATCH] libata: implement ATA_EHI_SETMODE and ATA_EHI_POST_SETMODE libata EH used to perform ata_set_mode() iff the EH session performed reset as indicated by ATA_EHI_DID_RESET. This is incorrect because ->dev_config() called by revalidation is allowed to modify transfer mode which ata_set_mode() should take care of. This patch implements the following two flags. * ATA_EHI_SETMODE: set during EH to schedule ata_set_mode(). Both new device attachment and revalidation set this flag. * ATA_EHI_POST_SETMODE: set while the device is revalidated after ata_set_mode(). Post-setmode revalidation is different from initial configuaration and EH revalidation in that ->dev_config() is not allowed tune transfer mode. LLD can use this flag to determine whether it's allowed to tune transfer mode. Note that POST_SETMODE ->dev_config() is guaranteed to be preceded by non-POST_SETMODE ->dev_config(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 3 +++ drivers/ata/libata-eh.c | 13 +++++++++++-- include/linux/libata.h | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e294731a7edd..5028396029b3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2158,6 +2158,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_eh_context *ehc = &dev->ap->eh_context; unsigned int err_mask; int rc; @@ -2172,7 +2173,9 @@ static int ata_dev_set_mode(struct ata_device *dev) return -EIO; } + ehc->i.flags |= ATA_EHI_POST_SETMODE; rc = ata_dev_revalidate(dev, 0); + ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7c446442616c..477648801a65 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1653,6 +1653,11 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + /* Configuration may have changed, reconfigure + * transfer mode. + */ + ehc->i.flags |= ATA_EHI_SETMODE; + /* schedule the scsi_rescan_device() here */ queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); } else if (dev->class == ATA_DEV_UNKNOWN && @@ -1675,6 +1680,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; spin_unlock_irqrestore(ap->lock, flags); + + /* new device discovered, configure transfer mode */ + ehc->i.flags |= ATA_EHI_SETMODE; } } @@ -1990,13 +1998,14 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc) goto dev_fail; - /* configure transfer mode if the port has been reset */ - if (ehc->i.flags & ATA_EHI_DID_RESET) { + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(ap, &dev); if (rc) { down_xfermask = 1; goto dev_fail; } + ehc->i.flags &= ~ATA_EHI_SETMODE; } /* suspend devices */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 949484627e67..0d0ddeaee73f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -284,6 +284,8 @@ enum { ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 18), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 19), /* revaildating after setmode */ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, -- cgit v1.2.3 From 914ed354b373680b648d913161cca6f742f32791 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 18:39:55 +0900 Subject: [PATCH] libata: move dev->max_sectors configuration into ata_dev_configure() Move dev->max_sectors configuration from ata_scsi_dev_config() to ata_dev_configure(). * more consistent. * allows LLDs to peek at the default dev->max_sectors value. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 +++++ drivers/ata/libata-scsi.c | 19 +++---------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5028396029b3..f531a89c26c9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1533,6 +1533,11 @@ int ata_dev_configure(struct ata_device *dev) cdb_intr_string); } + /* determine max_sectors */ + dev->max_sectors = ATA_MAX_SECTORS; + if (dev->flags & ATA_DFLAG_LBA48) + dev->max_sectors = ATA_MAX_SECTORS_LBA48; + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { /* Let the user know. We don't want to disallow opens for rescue purposes, or in case the vendor is just a blithering diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 6b2553dae489..f13dd07a5331 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -807,23 +807,10 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) static void ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) { - unsigned int max_sectors; + /* configure max sectors */ + blk_queue_max_sectors(sdev->request_queue, dev->max_sectors); - /* TODO: 2048 is an arbitrary number, not the - * hardware maximum. This should be increased to - * 65534 when Jens Axboe's patch for dynamically - * determining max_sectors is merged. - */ - max_sectors = ATA_MAX_SECTORS; - if (dev->flags & ATA_DFLAG_LBA48) - max_sectors = ATA_MAX_SECTORS_LBA48; - if (dev->max_sectors) - max_sectors = dev->max_sectors; - - blk_queue_max_sectors(sdev->request_queue, max_sectors); - - /* - * SATA DMA transfers must be multiples of 4 byte, so + /* SATA DMA transfers must be multiples of 4 byte, so * we need to pad ATAPI transfers using an extra sg. * Decrement max hw segments accordingly. */ -- cgit v1.2.3 From 415ae2b5c03b6ed1a041a473885e502d297e1d37 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 1 Nov 2006 05:10:42 -0500 Subject: [libata] ahci: Match PCI class code for AHCI Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 8a1f4f059a43..bc6599e4f474 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -403,6 +403,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ + /* Generic, PCI class code for AHCI */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + 0x010601, 0xffffff, board_ahci }, + { } /* terminate list */ }; -- cgit v1.2.3 From ada406c8246b0792afe4d7f8ae7606093052de87 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 3 Nov 2006 13:18:06 +0000 Subject: [PATCH] pdc202xx_old: Fix name clashes with PA-RISC pdc_* functions are part of the global namespace for the PDC on PA-RISC systems and this means our choice of pdc_ causes collisions between the PDC globals and our static functions. Rename them to pdc202xx where they are for both 2024x and 2026x. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc202xx_old.c | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 6baf51b2fda1..ed8d98557f16 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -21,7 +21,7 @@ #include #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.2.1" +#define DRV_VERSION "0.2.2" /** * pdc2024x_pre_reset - probe begin @@ -63,7 +63,7 @@ static void pdc2026x_error_handler(struct ata_port *ap) } /** - * pdc_configure_piomode - set chip PIO timing + * pdc202xx_configure_piomode - set chip PIO timing * @ap: ATA interface * @adev: ATA device * @pio: PIO mode @@ -73,7 +73,7 @@ static void pdc2026x_error_handler(struct ata_port *ap) * versa */ -static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) +static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; @@ -98,7 +98,7 @@ static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, } /** - * pdc_set_piomode - set initial PIO mode data + * pdc202xx_set_piomode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device * @@ -106,13 +106,13 @@ static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, * but we want to set the PIO timing by default. */ -static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev) { - pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); + pdc202xx_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); } /** - * pdc_configure_dmamode - set DMA mode in chip + * pdc202xx_configure_dmamode - set DMA mode in chip * @ap: ATA interface * @adev: ATA device * @@ -120,7 +120,7 @@ static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev) * to occur. */ -static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev) +static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; @@ -184,7 +184,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) /* The DMA clocks may have been trashed by a reset. FIXME: make conditional and move to qc_issue ? */ - pdc_set_dmamode(ap, qc->dev); + pdc202xx_set_dmamode(ap, qc->dev); /* Cases the state machine will not complete correctly without help */ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) @@ -254,7 +254,7 @@ static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev) adev->max_sectors = 256; } -static struct scsi_host_template pdc_sht = { +static struct scsi_host_template pdc202xx_sht = { .module = THIS_MODULE, .name = DRV_NAME, .ioctl = ata_scsi_ioctl, @@ -275,8 +275,8 @@ static struct scsi_host_template pdc_sht = { static struct ata_port_operations pdc2024x_port_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_set_piomode, - .set_dmamode = pdc_set_dmamode, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -308,8 +308,8 @@ static struct ata_port_operations pdc2024x_port_ops = { static struct ata_port_operations pdc2026x_port_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_set_piomode, - .set_dmamode = pdc_set_dmamode, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -340,11 +340,11 @@ static struct ata_port_operations pdc2026x_port_ops = { .host_stop = ata_host_stop }; -static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) +static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static struct ata_port_info info[3] = { { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -352,7 +352,7 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &pdc2024x_port_ops }, { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -360,7 +360,7 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &pdc2026x_port_ops }, { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -386,7 +386,7 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } -static const struct pci_device_id pdc[] = { +static const struct pci_device_id pdc202xx[] = { { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 }, { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 }, { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 }, @@ -396,28 +396,28 @@ static const struct pci_device_id pdc[] = { { }, }; -static struct pci_driver pdc_pci_driver = { +static struct pci_driver pdc202xx_pci_driver = { .name = DRV_NAME, - .id_table = pdc, - .probe = pdc_init_one, + .id_table = pdc202xx, + .probe = pdc202xx_init_one, .remove = ata_pci_remove_one }; -static int __init pdc_init(void) +static int __init pdc202xx_init(void) { - return pci_register_driver(&pdc_pci_driver); + return pci_register_driver(&pdc202xx_pci_driver); } -static void __exit pdc_exit(void) +static void __exit pdc202xx_exit(void) { - pci_unregister_driver(&pdc_pci_driver); + pci_unregister_driver(&pdc202xx_pci_driver); } MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, pdc); +MODULE_DEVICE_TABLE(pci, pdc202xx); MODULE_VERSION(DRV_VERSION); -module_init(pdc_init); -module_exit(pdc_exit); +module_init(pdc202xx_init); +module_exit(pdc202xx_exit); -- cgit v1.2.3 From 98fa4b60c673526fdd478d9719e41cd9e2b84986 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Nov 2006 12:17:23 +0900 Subject: [PATCH] ahci: preserve PORTS_IMPL over host resets Instead of writing 0xf blindly, preserve the content of write-once PORTS_IMPL register over host resets. This patch is taken from Jeff Garzik's AHCI init update patch. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index bc6599e4f474..f2277be70c0f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -421,6 +421,11 @@ static struct pci_driver ahci_pci_driver = { }; +static inline int ahci_nr_ports(u32 cap) +{ + return (cap & 0x1f) + 1; +} + static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port) { return base + 0x100 + (port * 0x80); @@ -630,11 +635,12 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) { - u32 cap_save, tmp; + u32 cap_save, impl_save, tmp; cap_save = readl(mmio + HOST_CAP); cap_save &= ( (1<<28) | (1<<17) ); cap_save |= (1 << 27); + impl_save = readl(mmio + HOST_PORTS_IMPL); /* global controller reset */ tmp = readl(mmio + HOST_CTL); @@ -655,10 +661,21 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) return -EIO; } + /* turn on AHCI mode */ writel(HOST_AHCI_EN, mmio + HOST_CTL); (void) readl(mmio + HOST_CTL); /* flush */ + + /* These write-once registers are normally cleared on reset. + * Restore BIOS values... which we HOPE were present before + * reset. + */ + if (!impl_save) { + impl_save = (1 << ahci_nr_ports(cap_save)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "PORTS_IMPL is zero, forcing 0x%x\n", impl_save); + } writel(cap_save, mmio + HOST_CAP); - writel(0xf, mmio + HOST_PORTS_IMPL); + writel(impl_save, mmio + HOST_PORTS_IMPL); (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { @@ -1467,7 +1484,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) hpriv->cap = readl(mmio + HOST_CAP); hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); - probe_ent->n_ports = (hpriv->cap & 0x1f) + 1; + probe_ent->n_ports = ahci_nr_ports(hpriv->cap); VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", hpriv->cap, hpriv->port_map, probe_ent->n_ports); -- cgit v1.2.3 From 4adccf6f447dfa7af6f3af7e12f87829a6fac8dd Mon Sep 17 00:00:00 2001 From: Uwe Koziolek Date: Wed, 8 Nov 2006 09:57:00 +0100 Subject: [PATCH] sata_sis: slave support on SiS965 SiS965 and SiS180 chips must support slave mode, SiS965L and SiS964 chips must not support slave mode. SCR_STATUS for SATA ports in powerdown state fixed. Now returning 0x0113 instead of 0x0117. Avoids problem on detecting sata_sis controller. Signed-off-by: Uwe Koziolek Signed-off-by: Jeff Garzik --- drivers/ata/sata_sis.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 9d1235ba06b1..9c25a1e91730 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -173,7 +173,7 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) pci_read_config_dword(pdev, cfg_addr+0x10, &val2); - return val|val2; + return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */ } static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) @@ -212,7 +212,7 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); - return val | val2; + return (val | val2) & 0xfffffffb; } static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) @@ -239,7 +239,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int printed_version; struct ata_probe_ent *probe_ent = NULL; int rc; - u32 genctl; + u32 genctl, val; struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi }; int pci_dev_busy = 0; u8 pmr; @@ -285,17 +285,24 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (ent->device != 0x182) { if ((pmr & SIS_PMR_COMBINED) == 0) { dev_printk(KERN_INFO, &pdev->dev, - "Detected SiS 180/181 chipset in SATA mode\n"); + "Detected SiS 180/181/964 chipset in SATA mode\n"); port2_start = 64; } else { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 180/181 chipset in combined mode\n"); port2_start=0; + pi.flags |= ATA_FLAG_SLAVE_POSS; } } else { - dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n"); + pci_read_config_dword ( pdev, 0x6C, &val); + if (val & (1L << 31)) { + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n"); + pi.flags |= ATA_FLAG_SLAVE_POSS; + } + else + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n"); port2_start = 0x20; } -- cgit v1.2.3 From 0df0d0a0ea9ffcee4e56f96cd9d9e32b0644eb21 Mon Sep 17 00:00:00 2001 From: Alessandro Zummo Date: Tue, 14 Nov 2006 13:43:21 -0500 Subject: [libata] ARM: add ixp4xx PATA driver Signed-off-by: Alessandro Zummo Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 10 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_ixp4xx_cf.c | 271 +++++++++++++++++++++++++++++++++ include/asm-arm/arch-ixp4xx/platform.h | 13 ++ 4 files changed, 295 insertions(+) create mode 100644 drivers/ata/pata_ixp4xx_cf.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 98d0f01c90eb..984ab284382a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -508,6 +508,16 @@ config PATA_PLATFORM If unsure, say N. +config PATA_IXP4XX_CF + tristate "IXP4XX Compact Flash support" + depends on ARCH_IXP4XX + help + This option enables support for a Compact Flash connected on + the ixp4xx expansion bus. This driver had been written for + Loft/Avila boards in mind but can work with others. + + If unsure, say N. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index f2b3ea2d15d0..bc3d81ae757e 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o +obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c new file mode 100644 index 000000000000..d2268bfe6f55 --- /dev/null +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -0,0 +1,271 @@ +/* + * ixp4xx PATA/Compact Flash driver + * Copyright (c) 2006 Tower Technologies + * Author: Alessandro Zummo + * + * An ATA driver to handle a Compact Flash connected + * to the ixp4xx expansion bus in TrueIDE mode. The CF + * must have it chip selects connected to two CS lines + * on the ixp4xx. The interrupt line is optional, if not + * specified the driver will run in polling mode. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_ixp4xx_cf" +#define DRV_VERSION "0.1.1" + +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_enabled(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); +} + +static void ixp4xx_mmio_data_xfer(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; + struct ata_port *ap = adev->ap; + void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + struct ixp4xx_pata_data *data = ap->host->dev->platform_data; + + /* set the expansion bus in 16bit mode and restore + * 8 bit mode after the transaction. + */ + *data->cs0_cfg &= ~(0x01); + udelay(100); + + /* 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(align_buf[0], mmio); + } else { + align_buf[0] = readw(mmio); + memcpy(trailing_buf, align_buf, 1); + } + } + + udelay(100); + *data->cs0_cfg |= 0x01; +} + +static void ixp4xx_irq_clear(struct ata_port *ap) +{ +} + +static void ixp4xx_host_stop (struct ata_host *host) +{ + struct ixp4xx_pata_data *data = host->dev->platform_data; + + iounmap(data->cs0); + iounmap(data->cs1); +} + +static struct scsi_host_template ixp4xx_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, +}; + +static struct ata_port_operations ixp4xx_port_ops = { + .set_mode = ixp4xx_set_mode, + .mode_filter = ata_pci_default_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 = ixp4xx_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ixp4xx_host_stop, + + .phy_reset = ixp4xx_phy_reset, +}; + +static void ixp4xx_setup_port(struct ata_ioports *ioaddr, + struct ixp4xx_pata_data *data) +{ + ioaddr->cmd_addr = (unsigned long) data->cs0; + ioaddr->altstatus_addr = (unsigned long) data->cs1 + 0x06; + ioaddr->ctl_addr = (unsigned long) data->cs1 + 0x06; + + ata_std_ports(ioaddr); + +#ifndef __ARMEB__ + + /* adjust the addresses to handle the address swizzling of the + * ixp4xx in little endian mode. + */ + + 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 __devinit int ixp4xx_pata_probe(struct platform_device *pdev) +{ + int ret; + unsigned int irq; + struct resource *cs0, *cs1; + struct ata_probe_ent ae; + + struct ixp4xx_pata_data *data = pdev->dev.platform_data; + + cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + if (!cs0 || !cs1) + return -EINVAL; + + pdev->dev.coherent_dma_mask = DMA_32BIT_MASK; + + data->cs0 = ioremap(cs0->start, 0x1000); + data->cs1 = ioremap(cs1->start, 0x1000); + + irq = platform_get_irq(pdev, 0); + if (irq) + set_irq_type(irq, IRQT_HIGH); + + /* Setup expansion bus chip selects */ + *data->cs0_cfg = data->cs0_bits; + *data->cs1_cfg = data->cs1_bits; + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + + ae.dev = &pdev->dev; + ae.port_ops = &ixp4xx_port_ops; + ae.sht = &ixp4xx_sht; + ae.n_ports = 1; + ae.pio_mask = 0x1f; /* PIO4 */ + ae.irq = irq; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY + | ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST; + + /* run in polling mode if no irq has been assigned */ + if (!irq) + ae.port_flags |= ATA_FLAG_PIO_POLLING; + + ixp4xx_setup_port(&ae.port[0], data); + + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); + + ret = ata_device_add(&ae); + if (ret == 0) + return -ENODEV; + + return 0; +} + +static __devexit int ixp4xx_pata_remove(struct platform_device *dev) +{ + struct ata_host *host = platform_get_drvdata(dev); + + ata_host_remove(host); + platform_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver ixp4xx_pata_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ixp4xx_pata_probe, + .remove = __devexit_p(ixp4xx_pata_remove), +}; + +static int __init ixp4xx_pata_init(void) +{ + return platform_driver_register(&ixp4xx_pata_platform_driver); +} + +static void __exit ixp4xx_pata_exit(void) +{ + platform_driver_unregister(&ixp4xx_pata_platform_driver); +} + +MODULE_AUTHOR("Alessandro Zummo "); +MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(ixp4xx_pata_init); +module_exit(ixp4xx_pata_exit); diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index 8d10a9187693..ab194e5f6653 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -86,6 +86,19 @@ struct ixp4xx_i2c_pins { unsigned long scl_pin; }; +/* + * This structure provide a means for the board setup code + * to give information to th pata_ixp4xx driver. It is + * passed as platform_data. + */ +struct ixp4xx_pata_data { + volatile u32 *cs0_cfg; + volatile u32 *cs1_cfg; + unsigned long cs0_bits; + unsigned long cs1_bits; + void __iomem *cs0; + void __iomem *cs1; +}; struct sys_timer; -- cgit v1.2.3 From 648a88be4a016d2637ace3ae74b85a0512255ee8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 9 Nov 2006 15:08:40 +0900 Subject: [PATCH] ahci: honor PORTS_IMPL on ICH8s Some ICH8s use non-linear port mapping. ahci driver didn't use to honor PORTS_IMPL and this made ports after hole nonfunctional. This patch makes ahci mark those ports as dummy and properly initialize all the implemented ports after the dummies. As it's unknown whether other AHCIs implement PORTS_IMPL register properly, new board id board_ahci_pi is added and selectively applied to ICH8s. All other AHCIs continue to use linear mapping regardless of PORTS_IMPL value. Signed-off-by: Tejun Heo Cc: Robin H. Johnson Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 95 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f2277be70c0f..af3565d1fefe 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -53,6 +53,7 @@ enum { AHCI_PCI_BAR = 5, + AHCI_MAX_PORTS = 32, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, AHCI_USE_CLUSTERING = 0, @@ -77,8 +78,9 @@ enum { RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, - board_ahci_vt8251 = 1, - board_ahci_ign_iferr = 2, + board_ahci_pi = 1, + board_ahci_vt8251 = 2, + board_ahci_ign_iferr = 3, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -169,6 +171,7 @@ enum { /* ap->flags bits */ AHCI_FLAG_NO_NCQ = (1 << 24), AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ + AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ }; struct ahci_cmd_hdr { @@ -317,6 +320,16 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, + /* board_ahci_pi */ + { + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &ahci_ops, + }, /* board_ahci_vt8251 */ { .sht = &ahci_sht, @@ -353,22 +366,22 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ - { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ /* JMicron */ { PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */ @@ -691,7 +704,8 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) } static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, - int n_ports, u32 cap) + int n_ports, unsigned int port_flags, + struct ahci_host_priv *hpriv) { int i, rc; u32 tmp; @@ -700,13 +714,12 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, void __iomem *port_mmio = ahci_port_base(mmio, i); const char *emsg = NULL; -#if 0 /* BIOSen initialize this incorrectly */ - if (!(hpriv->port_map & (1 << i))) + if ((port_flags & AHCI_FLAG_HONOR_PI) && + !(hpriv->port_map & (1 << i))) continue; -#endif /* make sure port is not active */ - rc = ahci_deinit_port(port_mmio, cap, &emsg); + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); if (rc) dev_printk(KERN_WARNING, &pdev->dev, "%s (%d)\n", emsg, rc); @@ -1363,7 +1376,8 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) if (rc) return rc; - ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap); + ahci_init_controller(mmio, pdev, host->n_ports, + host->ports[0]->flags, hpriv); } ata_host_resume(host); @@ -1475,7 +1489,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); void __iomem *mmio = probe_ent->mmio_base; - unsigned int i, using_dac; + unsigned int i, cap_n_ports, using_dac; int rc; rc = ahci_reset_controller(mmio, pdev); @@ -1484,10 +1498,34 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) hpriv->cap = readl(mmio + HOST_CAP); hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); - probe_ent->n_ports = ahci_nr_ports(hpriv->cap); + cap_n_ports = ahci_nr_ports(hpriv->cap); VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", - hpriv->cap, hpriv->port_map, probe_ent->n_ports); + hpriv->cap, hpriv->port_map, cap_n_ports); + + if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { + unsigned int n_ports = cap_n_ports; + u32 port_map = hpriv->port_map; + int max_port = 0; + + for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { + if (port_map & (1 << i)) { + n_ports--; + port_map &= ~(1 << i); + max_port = i; + } else + probe_ent->dummy_port_mask |= 1 << i; + } + + if (n_ports || port_map) + dev_printk(KERN_WARNING, &pdev->dev, + "nr_ports (%u) and implemented port map " + "(0x%x) don't match\n", + cap_n_ports, hpriv->port_map); + + probe_ent->n_ports = max_port + 1; + } else + probe_ent->n_ports = cap_n_ports; using_dac = hpriv->cap & HOST_CAP_64; if (using_dac && @@ -1519,7 +1557,8 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) for (i = 0; i < probe_ent->n_ports; i++) ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); - ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap); + ahci_init_controller(mmio, pdev, probe_ent->n_ports, + probe_ent->port_flags, hpriv); pci_set_master(pdev); -- cgit v1.2.3 From 6fc49adb9417b9c793e8f88d485387bb89ceb733 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 11 Nov 2006 20:10:45 +0900 Subject: [PATCH] libata: use FLUSH_EXT only when driver is larger than LBA28 limit Many drives support LBA48 even when its capacity is smaller than 1<<28, as LBA48 is required for many functionalities. FLUSH_EXT is mandatory for drives w/ LBA48 support. Interestingly, at least one of such drives (ST960812A) has problems dealing with FLUSH_EXT. It eventually completes the command but takes around 7 seconds to finish in many cases thus drastically slowing down IO transactions. This seems to be a firmware bug which sneaked into production probably because no other ATA driver including linux IDE issues FLUSH_EXT to drives which report support for LBA48 & FLUSH_EXT but is smaller than 1<<28 blocks. This patch adds ATA_DFLAG_FLUSH_EXT which is set iff the drive supports LBA48 & FLUSH_EXT and is larger than LBA28 limit. Both cache flush paths are updated to issue FLUSH_EXT only when the flag is set. Note that the changed behavior is more inline with the rest of libata. libata prefers shorter commands whenever possible. Signed-off-by: Tejun Heo Cc: Danny Kukawka Cc: Stefan Seyfried Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +++++- drivers/ata/libata-scsi.c | 3 +-- include/linux/libata.h | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f531a89c26c9..d94b8a02c340 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1457,6 +1457,10 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_lba48(id)) { dev->flags |= ATA_DFLAG_LBA48; lba_desc = "LBA48"; + + if (dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + dev->flags |= ATA_DFLAG_FLUSH_EXT; } /* config NCQ */ @@ -5128,7 +5132,7 @@ int ata_flush_cache(struct ata_device *dev) if (!ata_try_flush_cache(dev)) return 0; - if (ata_id_has_flush_ext(dev->id)) + if (dev->flags & ATA_DFLAG_FLUSH_EXT) cmd = ATA_CMD_FLUSH_EXT; else cmd = ATA_CMD_FLUSH; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f13dd07a5331..7a55c2e4ea6e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1027,8 +1027,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((qc->dev->flags & ATA_DFLAG_LBA48) && - (ata_id_has_flush_ext(qc->dev->id))) + if (qc->dev->flags & ATA_DFLAG_FLUSH_EXT) tf->command = ATA_CMD_FLUSH_EXT; else tf->command = ATA_CMD_FLUSH; diff --git a/include/linux/libata.h b/include/linux/libata.h index 0d0ddeaee73f..36e233cc3886 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -140,6 +140,7 @@ enum { ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */ ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ + ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ -- cgit v1.2.3 From b3362f88a8f938fb700fdedf074ec222cba7cf83 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Nov 2006 18:08:10 +0900 Subject: [PATCH] ata_piix: clean up port flags * move common flags into PIIX_PATA_FLAGS and PIIX_SATA_FLAGS * kill unnecessary ATA_FLAG_SRST Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 14b726b9f985..90ac33a7bdc7 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -106,6 +106,9 @@ enum { PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ + PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, + PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + /* combined mode. if set, PATA is channel 0. * if clear, PATA is channel 1. */ @@ -438,7 +441,7 @@ static struct ata_port_info piix_port_info[] = { /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */ { .sht = &piix_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ .udma_mask = ATA_UDMA_MASK_40C, @@ -448,7 +451,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ .udma_mask = ATA_UDMA2, /* UDMA33 */ @@ -457,7 +460,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_66: 2 ICH controllers up to 66MHz */ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ .udma_mask = ATA_UDMA4, @@ -467,7 +470,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_100: 3 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR, + .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -477,7 +480,7 @@ static struct ata_port_info piix_port_info[] = { /* ich_pata_133: 4 ICH with full UDMA6 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR, + .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ .udma_mask = ATA_UDMA6, /* UDMA133 */ @@ -487,8 +490,7 @@ static struct ata_port_info piix_port_info[] = { /* ich5_sata: 5 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | - PIIX_FLAG_IGNORE_PCS, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_IGNORE_PCS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -498,8 +500,7 @@ static struct ata_port_info piix_port_info[] = { /* i6300esb_sata: 6 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_IGNORE_PCS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -509,8 +510,7 @@ static struct ata_port_info piix_port_info[] = { /* ich6_sata: 7 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -520,8 +520,7 @@ static struct ata_port_info piix_port_info[] = { /* ich6_sata_ahci: 8 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -532,8 +531,7 @@ static struct ata_port_info piix_port_info[] = { /* ich6m_sata_ahci: 9 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -544,8 +542,7 @@ static struct ata_port_info piix_port_info[] = { /* ich8_sata_ahci: 10 */ { .sht = &piix_sht, - .flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ -- cgit v1.2.3 From bff0464769f2a1bd348265de704471747378e247 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Nov 2006 18:08:10 +0900 Subject: [PATCH] libata: convert @post_reset to @flags in ata_dev_read_id() Make ata_dev_read_id() take @flags instead of @post_reset. Currently there is only one flag defined - ATA_READID_POSTRESET, which is equivalent to @post_reset. This is preparation for polling presence detection. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 17 +++++++++-------- drivers/ata/libata-eh.c | 11 +++++++---- drivers/ata/libata.h | 9 +++++++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d94b8a02c340..090abe443820 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1224,7 +1224,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * ata_dev_read_id - Read ID data from the specified device * @dev: target device * @p_class: pointer to class of the target device (may be changed) - * @post_reset: is this read ID post-reset? + * @flags: ATA_READID_* flags * @id: buffer to read IDENTIFY data into * * Read ID data from the specified device. ATA_CMD_ID_ATA is @@ -1239,7 +1239,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * 0 on success, -errno otherwise. */ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - int post_reset, u16 *id) + unsigned int flags, u16 *id) { struct ata_port *ap = dev->ap; unsigned int class = *p_class; @@ -1294,7 +1294,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, goto err_out; } - if (post_reset && class == ATA_DEV_ATA) { + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { /* * The exact sequence expected by certain pre-ATA4 drives is: * SRST RESET @@ -1314,7 +1314,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, /* current CHS translation info (id[53-58]) might be * changed. reread the identify device info. */ - post_reset = 0; + flags &= ~ATA_READID_POSTRESET; goto retry; } } @@ -1643,7 +1643,8 @@ int ata_bus_probe(struct ata_port *ap) if (!ata_dev_enabled(dev)) continue; - rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); + rc = ata_dev_read_id(dev, &dev->class, ATA_READID_POSTRESET, + dev->id); if (rc) goto fail; @@ -3023,7 +3024,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, /** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate - * @post_reset: is this revalidation after reset? + * @readid_flags: read ID flags * * Re-read IDENTIFY page and make sure @dev is still attached to * the port. @@ -3034,7 +3035,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_device *dev, int post_reset) +int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) { unsigned int class = dev->class; u16 *id = (void *)dev->ap->sector_buf; @@ -3046,7 +3047,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) } /* read ID data */ - rc = ata_dev_read_id(dev, &class, post_reset, id); + rc = ata_dev_read_id(dev, &class, readid_flags, id); if (rc) goto fail; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 477648801a65..755fc68b5374 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1634,11 +1634,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, DPRINTK("ENTER\n"); for (i = 0; i < ATA_MAX_DEVICES; i++) { - unsigned int action; + unsigned int action, readid_flags = 0; dev = &ap->device[i]; action = ata_eh_dev_action(dev); + if (ehc->i.flags & ATA_EHI_DID_RESET) + readid_flags |= ATA_READID_POSTRESET; + if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { if (ata_port_offline(ap)) { rc = -EIO; @@ -1646,8 +1649,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, } ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); - rc = ata_dev_revalidate(dev, - ehc->i.flags & ATA_EHI_DID_RESET); + rc = ata_dev_revalidate(dev, readid_flags); if (rc) break; @@ -1665,7 +1667,8 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); + rc = ata_dev_read_id(dev, &dev->class, readid_flags, + dev->id); if (rc == 0) { ehc->i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index e4ffb2e38992..bb98390aa01a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -39,6 +39,11 @@ struct ata_scsi_args { }; /* libata-core.c */ +enum { + /* flags for ata_dev_read_id() */ + ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ +}; + extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; @@ -52,8 +57,8 @@ extern unsigned ata_exec_internal(struct ata_device *dev, int dma_dir, void *buf, unsigned int buflen); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - int post_reset, u16 *id); -extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); + unsigned int flags, u16 *id); +extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags); extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); -- cgit v1.2.3 From 55a8e2c83ce50548dfef74bb19dfe2b809cb3099 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Nov 2006 18:08:10 +0900 Subject: [PATCH] libata: implement presence detection via polling IDENTIFY On some controllers (ICHs in piix mode), there is *NO* reliable way to determine device presence other than issuing IDENTIFY and see how the transaction proceeds by watching the TF status register. libata acted this way before irq-pio and phantom devices caused very little problem but now that IDENTIFY is performed using IRQ drive PIO, such phantom devices now result in multiple 30sec timeouts during boot. This patch implements ATA_FLAG_DETECT_POLLING. If a LLD sets this flag, libata core issues the initial IDENTIFY in polling mode and if the initial data transfer fails w/ HSM violation, the port is considered to be empty thus replicating the old libata and IDE behavior. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 19 +++++++++++++++++-- drivers/ata/libata-eh.c | 23 ++++++++++++++++++----- drivers/ata/libata.h | 2 ++ include/linux/libata.h | 3 +++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 090abe443820..21f8d61e5879 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1272,9 +1272,20 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.protocol = ATA_PROT_PIO; + /* presence detection using polling IDENTIFY? */ + if (flags & ATA_READID_DETECT) + tf.flags |= ATA_TFLAG_POLLING; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { + if ((flags & ATA_READID_DETECT) && + (err_mask & AC_ERR_NODEV_HINT)) { + DPRINTK("ata%u.%d: NODEV after polling detection\n", + ap->id, dev->devno); + return -ENOENT; + } + rc = -EIO; reason = "I/O error"; goto err_out; @@ -4285,8 +4296,12 @@ fsm_start: /* device stops HSM for abort/error */ qc->err_mask |= AC_ERR_DEV; else - /* HSM violation. Let EH handle this */ - qc->err_mask |= AC_ERR_HSM; + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | + AC_ERR_NODEV_HINT; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 755fc68b5374..e69f3df2ea39 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1667,12 +1667,23 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; + if (ap->flags & ATA_FLAG_DETECT_POLLING) + readid_flags |= ATA_READID_DETECT; + rc = ata_dev_read_id(dev, &dev->class, readid_flags, dev->id); if (rc == 0) { ehc->i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); ehc->i.flags &= ~ATA_EHI_PRINTINFO; + } else if (rc == -ENOENT) { + /* IDENTIFY was issued to non-existent + * device. No need to reset. Just + * thaw and kill the device. + */ + ata_eh_thaw_port(ap); + dev->class = ATA_DEV_UNKNOWN; + rc = 0; } if (rc) { @@ -1680,12 +1691,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, break; } - spin_lock_irqsave(ap->lock, flags); - ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; - spin_unlock_irqrestore(ap->lock, flags); + if (ata_dev_enabled(dev)) { + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; + spin_unlock_irqrestore(ap->lock, flags); - /* new device discovered, configure transfer mode */ - ehc->i.flags |= ATA_EHI_SETMODE; + /* new device discovered, configure xfermode */ + ehc->i.flags |= ATA_EHI_SETMODE; + } } } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index bb98390aa01a..be2ac39f013b 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -42,6 +42,8 @@ struct ata_scsi_args { enum { /* flags for ata_dev_read_id() */ ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ + ATA_READID_DETECT = (1 << 1), /* perform presence detection + * using polling IDENTIFY */ }; extern struct workqueue_struct *ata_aux_wq; diff --git a/include/linux/libata.h b/include/linux/libata.h index 36e233cc3886..9080789913f7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -176,6 +176,8 @@ enum { ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by + * polling IDENTIFY */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be @@ -335,6 +337,7 @@ enum ata_completion_errors { AC_ERR_SYSTEM = (1 << 6), /* system error */ AC_ERR_INVALID = (1 << 7), /* invalid argument */ AC_ERR_OTHER = (1 << 8), /* unknown */ + AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ }; /* forward declarations */ -- cgit v1.2.3 From 228c1590be39872022006ab81fda112a4f35ce47 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Nov 2006 18:08:10 +0900 Subject: [PATCH] ata_piix: apply device detection via polling IDENTIFY PATA PIIX uses reset signature + TF r/w test for device presence detection, which doesn't always work. It sometimes reports phantom device which results in IDENTIFY timeouts. SATA PIIX uses some combination of PCS + reset signature + TF r/w test for device presence detection. No combination satifies all and for some controllers, there doesn't seem to be any combination which works reliably. This patch makes both PATA and SATA piix's use reset signature + TF r/w + polling IDENTIFY for device detection. This is what the old libata (before irq-pio and new EH) did and what IDE does. This patch also removes now obsolete PIIX_FLAG_IGNORE_PCS, force_pcs and related code. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 104 +++---------------------------------------------- 1 file changed, 6 insertions(+), 98 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 90ac33a7bdc7..7bf238638e8e 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -101,13 +101,13 @@ enum { ICH5_PCS = 0x92, /* port control and status */ PIIX_SCC = 0x0A, /* sub-class code register */ - PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */ PIIX_FLAG_SCR = (1 << 26), /* SCR available */ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ - PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, - PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS | ATA_FLAG_DETECT_POLLING, + PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | + ATA_FLAG_DETECT_POLLING, /* combined mode. if set, PATA is channel 0. * if clear, PATA is channel 1. @@ -490,7 +490,7 @@ static struct ata_port_info piix_port_info[] = { /* ich5_sata: 5 */ { .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_IGNORE_PCS, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -500,7 +500,7 @@ static struct ata_port_info piix_port_info[] = { /* i6300esb_sata: 6 */ { .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_IGNORE_PCS, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -563,11 +563,6 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, piix_pci_tbl); MODULE_VERSION(DRV_VERSION); -static int force_pcs = 0; -module_param(force_pcs, int, 0444); -MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " - "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); - struct ich_laptop { u16 device; u16 subvendor; @@ -685,84 +680,9 @@ static void ich_pata_error_handler(struct ata_port *ap) ata_std_postreset); } -/** - * piix_sata_present_mask - determine present mask for SATA host controller - * @ap: Target port - * - * Reads SATA PCI device's PCI config register Port Configuration - * and Status (PCS) to determine port and device availability. - * - * LOCKING: - * None (inherited from caller). - * - * RETURNS: - * determined present_mask - */ -static unsigned int piix_sata_present_mask(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - struct piix_host_priv *hpriv = ap->host->private_data; - const unsigned int *map = hpriv->map; - int base = 2 * ap->port_no; - unsigned int present_mask = 0; - int port, i; - u16 pcs; - - pci_read_config_word(pdev, ICH5_PCS, &pcs); - DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base); - - for (i = 0; i < 2; i++) { - port = map[base + i]; - if (port < 0) - continue; - if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || - (pcs & 1 << (hpriv->map_db->present_shift + port))) - present_mask |= 1 << i; - } - - DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", - ap->id, pcs, present_mask); - - return present_mask; -} - -/** - * piix_sata_softreset - reset SATA host port via ATA SRST - * @ap: port to reset - * @classes: resulting classes of attached devices - * - * Reset SATA host port via ATA SRST. On controllers with - * reliable PCS present bits, the bits are used to determine - * device presence. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) -{ - unsigned int present_mask; - int i, rc; - - present_mask = piix_sata_present_mask(ap); - - rc = ata_std_softreset(ap, classes); - if (rc) - return rc; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - if (!(present_mask & (1 << i))) - classes[i] = ATA_DEV_NONE; - } - - return 0; -} - static void piix_sata_error_handler(struct ata_port *ap) { - ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, ata_std_postreset); } @@ -1077,18 +997,6 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev, pci_write_config_word(pdev, ICH5_PCS, new_pcs); msleep(150); } - - if (force_pcs == 1) { - dev_printk(KERN_INFO, &pdev->dev, - "force ignoring PCS (0x%x)\n", new_pcs); - pinfo[0].flags |= PIIX_FLAG_IGNORE_PCS; - pinfo[1].flags |= PIIX_FLAG_IGNORE_PCS; - } else if (force_pcs == 2) { - dev_printk(KERN_INFO, &pdev->dev, - "force honoring PCS (0x%x)\n", new_pcs); - pinfo[0].flags &= ~PIIX_FLAG_IGNORE_PCS; - pinfo[1].flags &= ~PIIX_FLAG_IGNORE_PCS; - } } static void __devinit piix_init_sata_map(struct pci_dev *pdev, -- cgit v1.2.3 From 5e56a37c3706498b25049bb556928c461875250f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Nov 2006 18:08:10 +0900 Subject: [PATCH] ata_piix: strip now unneded MAP related stuff Now that PCS isn't used for device detection anymore... * esb_sata is identical to ich5_sata * no reason to know present_shift * no reason to store map_db in host private area The MAP table itself is left because it can be used for SCR access. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 7bf238638e8e..788a269206e6 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -125,11 +125,10 @@ enum { ich_pata_100 = 3, /* ICH up to UDMA 100 */ ich_pata_133 = 4, /* ICH up to UDMA 133 */ ich5_sata = 5, - esb_sata = 6, - ich6_sata = 7, - ich6_sata_ahci = 8, - ich6m_sata_ahci = 9, - ich8_sata_ahci = 10, + ich6_sata = 6, + ich6_sata_ahci = 7, + ich6m_sata_ahci = 8, + ich8_sata_ahci = 9, /* constants for mapping table */ P0 = 0, /* port 0 */ @@ -146,13 +145,11 @@ enum { struct piix_map_db { const u32 mask; const u16 port_enable; - const int present_shift; const int map[][4]; }; struct piix_host_priv { const int *map; - const struct piix_map_db *map_db; }; static int piix_init_one (struct pci_dev *pdev, @@ -217,9 +214,9 @@ static const struct pci_device_id piix_pci_tbl[] = { /* 82801EB (ICH5) */ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 6300ESB (ICH5 variant with broken PCS present bits) */ - { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata }, + { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 6300ESB pretending RAID */ - { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata }, + { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 82801FB/FW (ICH6/ICH6W) */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, /* 82801FR/FRW (ICH6R/ICH6RW) */ @@ -370,7 +367,6 @@ static const struct ata_port_operations piix_sata_ops = { static const struct piix_map_db ich5_map_db = { .mask = 0x7, .port_enable = 0x3, - .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, NA, P1, NA }, /* 000b */ @@ -387,7 +383,6 @@ static const struct piix_map_db ich5_map_db = { static const struct piix_map_db ich6_map_db = { .mask = 0x3, .port_enable = 0xf, - .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, P2, P1, P3 }, /* 00b */ @@ -400,7 +395,6 @@ static const struct piix_map_db ich6_map_db = { static const struct piix_map_db ich6m_map_db = { .mask = 0x3, .port_enable = 0x5, - .present_shift = 4, /* Map 01b isn't specified in the doc but some notebooks use * it anyway. MAP 01b have been spotted on both ICH6M and @@ -418,7 +412,6 @@ static const struct piix_map_db ich6m_map_db = { static const struct piix_map_db ich8_map_db = { .mask = 0x3, .port_enable = 0x3, - .present_shift = 8, .map = { /* PM PS SM SS MAP */ { P0, P2, P1, P3 }, /* 00b (hardwired when in AHCI) */ @@ -430,7 +423,6 @@ static const struct piix_map_db ich8_map_db = { static const struct piix_map_db *piix_map_db_table[] = { [ich5_sata] = &ich5_map_db, - [esb_sata] = &ich5_map_db, [ich6_sata] = &ich6_map_db, [ich6_sata_ahci] = &ich6_map_db, [ich6m_sata_ahci] = &ich6m_map_db, @@ -497,17 +489,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* i6300esb_sata: 6 */ - { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 */ - .port_ops = &piix_sata_ops, - }, - - /* ich6_sata: 7 */ + /* ich6_sata: 6 */ { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, @@ -517,7 +499,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata_ahci: 8 */ + /* ich6_sata_ahci: 7 */ { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -528,7 +510,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6m_sata_ahci: 9 */ + /* ich6m_sata_ahci: 8 */ { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -539,7 +521,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich8_sata_ahci: 10 */ + /* ich8_sata_ahci: 9 */ { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -1046,7 +1028,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, "invalid MAP value %u\n", map_value); hpriv->map = map; - hpriv->map_db = map_db; } /** -- cgit v1.2.3 From 8a93758170a58b5afe3e45d7d5bebbdd401a24c2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:36:12 +0900 Subject: [PATCH] libata: improve failed qc reporting Improve failed qc reporting. The original message didn't include the actual command nor full error status and it was necessary to temporarily patch the code to find out exactly which command is causing problem. This patch makes EH report full command and result TFs along with data direction and length. This change will make bug reports more useful. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e69f3df2ea39..3771eb83875f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1433,16 +1433,38 @@ static void ata_eh_report(struct ata_port *ap) } for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + static const char *dma_str[] = { + [DMA_BIDIRECTIONAL] = "bidi", + [DMA_TO_DEVICE] = "out", + [DMA_FROM_DEVICE] = "in", + [DMA_NONE] = "", + }; struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; + unsigned int nbytes; if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) continue; - ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x " - "Emask 0x%x stat 0x%x err 0x%x (%s)\n", - qc->tag, qc->tf.command, qc->err_mask, - qc->result_tf.command, qc->result_tf.feature, - ata_err_string(qc->err_mask)); + nbytes = qc->nbytes; + if (!nbytes) + nbytes = qc->nsect << 9; + + ata_dev_printk(qc->dev, KERN_ERR, + "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " + "tag %d data %u %s\n " + "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " + "Emask 0x%x (%s)\n", + cmd->command, cmd->feature, cmd->nsect, + cmd->lbal, cmd->lbam, cmd->lbah, + cmd->hob_feature, cmd->hob_nsect, + cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, + cmd->device, qc->tag, nbytes, dma_str[qc->dma_dir], + res->command, res->feature, res->nsect, + res->lbal, res->lbam, res->lbah, + res->hob_feature, res->hob_nsect, + res->hob_lbal, res->hob_lbam, res->hob_lbah, + res->device, qc->err_mask, ata_err_string(qc->err_mask)); } } -- cgit v1.2.3 From 61c0596c5fbef99df5518ae449be4ab49a2c2233 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:35:43 +0900 Subject: [PATCH] libata: trivial updates to ata_sg_init_one() There's no need to memset &qc->sgent manually, sg_init_one() clears sgent inside it. Also, kill not-so-necessary sg local variable. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 21f8d61e5879..a52c07198839 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3491,19 +3491,15 @@ void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) { - struct scatterlist *sg; - qc->flags |= ATA_QCFLAG_SINGLE; - memset(&qc->sgent, 0, sizeof(qc->sgent)); qc->__sg = &qc->sgent; qc->n_elem = 1; qc->orig_n_elem = 1; qc->buf_virt = buf; qc->nbytes = buflen; - sg = qc->__sg; - sg_init_one(sg, buf, buflen); + sg_init_one(&qc->sgent, buf, buflen); } /** -- cgit v1.2.3 From 39599a5334decc2669ba794fb0ccd2b112ef1ba4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:37:35 +0900 Subject: [PATCH] libata: sync result_tf.flags w/ command tf.flags libata didn't initialize result_tf.flags which indicates transfer type (RW/FUA) and address type (CHS/LBA/LBA48). ata_gen_fixed_sense() assumed result_tf.flags equals command tf.flags and failed to report the first failed block to SCSI layer because zero tf flags indicates CHS and bad block reporting for CHS is not implemented. Implement fill_result_tf() which sets result_tf.flags to command tf.flags and use it to fill result_tf. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a52c07198839..13dcef809e5c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4536,6 +4536,14 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) qc->complete_fn(qc); } +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + ap->ops->tf_read(ap, &qc->result_tf); + qc->result_tf.flags = qc->tf.flags; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -4573,7 +4581,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { if (!ata_tag_internal(qc->tag)) { /* always fill result TF for failed qc */ - ap->ops->tf_read(ap, &qc->result_tf); + fill_result_tf(qc); ata_qc_schedule_eh(qc); return; } @@ -4581,7 +4589,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) /* read result TF if requested */ if (qc->flags & ATA_QCFLAG_RESULT_TF) - ap->ops->tf_read(ap, &qc->result_tf); + fill_result_tf(qc); __ata_qc_complete(qc); } else { @@ -4590,7 +4598,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) /* read result TF if failed or requested */ if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) - ap->ops->tf_read(ap, &qc->result_tf); + fill_result_tf(qc); __ata_qc_complete(qc); } -- cgit v1.2.3 From f38621b3109068adc8430bc2d170ccea59df4261 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:37:35 +0900 Subject: [PATCH] libata: fix passthru sense data header sb[7] should contain the length of whole information sense data descriptor while desc[1] should contain the number of following bytes in the descriptor. ie. 14 for sb[7] but 12 for desc[1]. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7a55c2e4ea6e..87f82827c1bf 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -713,12 +713,9 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) desc[0] = 0x09; - /* - * Set length of additional sense data. - * Since we only populate descriptor 0, the total - * length is the same (fixed) length as descriptor 0. - */ - desc[1] = sb[7] = 14; + /* set length of additional sense data */ + sb[7] = 14; + desc[1] = 12; /* * Copy registers into sense buffer. -- cgit v1.2.3 From 750426aa1ad1ddd1fa8bb4ed531a7956f3b9a27c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:37:35 +0900 Subject: [PATCH] libata: cosmetic changes to sense generation functions * s/ata_gen_ata_desc_sense/ata_gen_passthru_sense/ * s/ata_gen_fixed_sense/ata_gen_ata_sense/ * make both functions static * neither function has locking requirement, change it to None. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 87f82827c1bf..6626ee1d57dc 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -671,7 +671,7 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, } /* - * ata_gen_ata_desc_sense - Generate check condition sense block. + * ata_gen_passthru_sense - Generate check condition sense block. * @qc: Command that completed. * * This function is specific to the ATA descriptor format sense @@ -681,9 +681,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, * block. Clear sense key, ASC & ASCQ if there is no error. * * LOCKING: - * spin_lock_irqsave(host lock) + * None. */ -void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) +static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; @@ -743,16 +743,16 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) } /** - * ata_gen_fixed_sense - generate a SCSI fixed sense block + * ata_gen_ata_sense - generate a SCSI fixed sense block * @qc: Command that we are erroring out * * Leverage ata_to_sense_error() to give us the codes. Fit our * LBA in here if there's room. * * LOCKING: - * inherited from caller + * None. */ -void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +static void ata_gen_ata_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; @@ -1460,7 +1460,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) */ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && ((cdb[2] & 0x20) || need_sense)) { - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } else { if (!need_sense) { cmd->result = SAM_STAT_GOOD; @@ -1471,7 +1471,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * good for smaller LBA (and maybe CHS?) * devices. */ - ata_gen_fixed_sense(qc); + ata_gen_ata_sense(qc); } } @@ -2302,7 +2302,7 @@ static void atapi_sense_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } qc->scsidone(qc->scsicmd); @@ -2377,7 +2377,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * sense descriptors, since that's only * correct for ATA, not ATAPI */ - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } /* SCSI EH automatically locks door if sdev->locked is @@ -2410,7 +2410,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - ata_gen_ata_desc_sense(qc); + ata_gen_passthru_sense(qc); } else { u8 *scsicmd = cmd->cmnd; -- cgit v1.2.3 From 35b649fe2587b2e569c17c022ba3506ba441b6a2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:37:35 +0900 Subject: [PATCH] libata: implement ata_tf_read_block() Implement ata_tf_read_block(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 1 + 2 files changed, 44 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 13dcef809e5c..3fd7c7932707 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -239,6 +239,49 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc) return -1; } +/** + * ata_tf_read_block - Read block address from ATA taskfile + * @tf: ATA taskfile of interest + * @dev: ATA device @tf belongs to + * + * LOCKING: + * None. + * + * Read block address from @tf. This function can handle all + * three address formats - LBA, LBA48 and CHS. tf->protocol and + * flags select the address format to use. + * + * RETURNS: + * Block address read from @tf. + */ +u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) +{ + u64 block = 0; + + if (tf->flags & ATA_TFLAG_LBA) { + if (tf->flags & ATA_TFLAG_LBA48) { + block |= (u64)tf->hob_lbah << 40; + block |= (u64)tf->hob_lbam << 32; + block |= tf->hob_lbal << 24; + } else + block |= (tf->device & 0xf) << 24; + + block |= tf->lbah << 16; + block |= tf->lbam << 8; + block |= tf->lbal; + } else { + u32 cyl, head, sect; + + cyl = tf->lbam | (tf->lbah << 8); + head = tf->device & 0xf; + sect = tf->lbal; + + block = (cyl * dev->heads + head) * dev->sectors + sect; + } + + return block; +} + /** * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask * @pio_mask: pio_mask diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index be2ac39f013b..2d532da8c398 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -52,6 +52,7 @@ extern int atapi_dmadir; extern int libata_fua; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); +extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, -- cgit v1.2.3 From d25614bad6eec8fb80f3ef5bffbf720ebb7d2412 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:37:35 +0900 Subject: [PATCH] libata: improve SCSI sense data generation Update ata_gen_ata_sense() to use desc format sense data to report the first failed block. The first failed block is read from result_tf using ata_tf_read_block() which can handle all three address formats. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 6626ee1d57dc..56d7e1ea9d72 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -746,53 +746,53 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) * ata_gen_ata_sense - generate a SCSI fixed sense block * @qc: Command that we are erroring out * - * Leverage ata_to_sense_error() to give us the codes. Fit our - * LBA in here if there's room. + * Generate sense block for a failed ATA command @qc. Descriptor + * format is used to accomodate LBA48 block address. * * LOCKING: * None. */ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) { + struct ata_device *dev = qc->dev; struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8; int verbose = qc->ap->ops->error_handler == NULL; + u64 block; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - /* - * Use ata_to_sense_error() to map status register bits + /* sense data is current and format is descriptor */ + sb[0] = 0x72; + + /* Use ata_to_sense_error() to map status register bits * onto sense key, asc & ascq. */ if (qc->err_mask || tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->id, tf->command, tf->feature, - &sb[2], &sb[12], &sb[13], verbose); - sb[2] &= 0x0f; + &sb[1], &sb[2], &sb[3], verbose); + sb[1] &= 0x0f; } - sb[0] = 0x70; - sb[7] = 0x0a; + block = ata_tf_read_block(&qc->result_tf, dev); - if (tf->flags & ATA_TFLAG_LBA48) { - /* TODO: find solution for LBA48 descriptors */ - } + /* information sense data descriptor */ + sb[7] = 12; + desc[0] = 0x00; + desc[1] = 10; - else if (tf->flags & ATA_TFLAG_LBA) { - /* A small (28b) LBA will fit in the 32b info field */ - sb[0] |= 0x80; /* set valid bit */ - sb[3] = tf->device & 0x0f; - sb[4] = tf->lbah; - sb[5] = tf->lbam; - sb[6] = tf->lbal; - } - - else { - /* TODO: C/H/S */ - } + desc[2] |= 0x80; /* valid */ + desc[6] = block >> 40; + desc[7] = block >> 32; + desc[8] = block >> 24; + desc[9] = block >> 16; + desc[10] = block >> 8; + desc[11] = block; } static void ata_scsi_sdev_config(struct scsi_device *sdev) -- cgit v1.2.3 From 46b027cc30b6f6571191826afc718fa942403fc8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 14 Nov 2006 14:46:17 -0500 Subject: [libata] sata_promise: fix TBG mode register offset Fixes crashes on sparc, and may correct weird behavior reported on occasions, because we were never programming this register correctly (or at all). Signed-off-by: Jeff Garzik --- drivers/ata/sata_promise.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 72eda5160fad..9c4389b5689a 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -46,15 +46,14 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "1.04" +#define DRV_VERSION "1.05" enum { PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ - PDC_TBG_MODE = 0x41, /* TBG mode */ + PDC_TBG_MODE = 0x41C, /* TBG mode */ PDC_FLASH_CTL = 0x44, /* Flash control register */ - PDC_PCI_CTL = 0x48, /* PCI control and status register */ PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */ -- cgit v1.2.3 From b2d1eee1e99e15a80fa9623724d6861a81d2aba4 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Wed, 22 Nov 2006 22:00:15 +0100 Subject: [PATCH] sata_promise fixes and updates This patch updates the sata_promise driver as follows: - Correct typo in definition of PDC_TBG_MODE: it's at 0x41C not 0x41 in first-generation chips. This error caused PCI access alignment exceptions on SPARC64, and on all platforms it disabled the expected initialisation of TBG mode. - Add flags field to struct pdc_host_priv. Define PDC_FLAG_GEN_II and use it to distinguish first- and second-generation chips. - Prevent the FLASH_CTL FIFO_SHD bit from being set to 1 on second- generation chips. This matches Promises' ulsata2 driver. - Prevent TBG mode and SLEW rate initialisation in second-generation chips. These two registers have moved, TBG mode has been redefined, and Promise's ulsata2 driver no longer attempts to initialise them. - Correct PCI device table so devices 0x3570, 0x3571, and 0x3d73 are marked as 2057x (2nd gen) not 2037x (1st gen). - Correct PCI device table so device 0x3d17 is marked as 40518 (2nd gen 4 ports) not 20319 (1st gen 4 ports). - Correct pdc_ata_init_one() to treat 20771 as a second-generation chip. Tested on 0x3d75 (2nd gen), 0x3d73 (2nd gen), and 0x3373 (1st gen) chips. The information comes from the newly uploaded Promise SATA HW specs, Promise's ultra and ulsata2 drivers, and debugging on 3d75/3d73/3373 chips. hp->hotplug_offset could now be removed and its value recomputed in pdc_host_init() using hp->flags, but that would be a cleanup not a functional change, so I'm ignoring it for now. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik --- drivers/ata/sata_promise.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 9c4389b5689a..8daf5d67dfe2 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -52,13 +52,13 @@ enum { PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ - PDC_TBG_MODE = 0x41C, /* TBG mode */ PDC_FLASH_CTL = 0x44, /* Flash control register */ PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */ - PDC_SLEW_CTL = 0x470, /* slew rate control reg */ + PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */ + PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */ PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<8) | (1<<9) | (1<<10), @@ -77,6 +77,9 @@ enum { PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, + + /* hp->flags bits */ + PDC_FLAG_GEN_II = (1 << 0), }; @@ -86,6 +89,7 @@ struct pdc_port_priv { }; struct pdc_host_priv { + unsigned long flags; int hotplug_offset; }; @@ -234,20 +238,20 @@ static const struct ata_port_info pdc_port_info[] = { static const struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VDEVICE(PROMISE, 0x3371), board_2037x }, - { PCI_VDEVICE(PROMISE, 0x3570), board_2037x }, - { PCI_VDEVICE(PROMISE, 0x3571), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3373), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3375), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3376), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3570), board_2057x }, + { PCI_VDEVICE(PROMISE, 0x3571), board_2057x }, { PCI_VDEVICE(PROMISE, 0x3574), board_2057x }, + { PCI_VDEVICE(PROMISE, 0x3d73), board_2057x }, { PCI_VDEVICE(PROMISE, 0x3d75), board_2057x }, - { PCI_VDEVICE(PROMISE, 0x3d73), board_2037x }, { PCI_VDEVICE(PROMISE, 0x3318), board_20319 }, { PCI_VDEVICE(PROMISE, 0x3319), board_20319 }, { PCI_VDEVICE(PROMISE, 0x3515), board_20319 }, { PCI_VDEVICE(PROMISE, 0x3519), board_20319 }, - { PCI_VDEVICE(PROMISE, 0x3d17), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3d17), board_40518 }, { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 }, { PCI_VDEVICE(PROMISE, 0x6629), board_20619 }, @@ -639,9 +643,11 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) * "TODO: figure out why we do this" */ - /* change FIFO_SHD to 8 dwords, enable BMR_BURST */ + /* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */ tmp = readl(mmio + PDC_FLASH_CTL); - tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */ + tmp |= 0x02000; /* bit 13 (enable bmr burst) */ + if (!(hp->flags & PDC_FLAG_GEN_II)) + tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */ writel(tmp, mmio + PDC_FLASH_CTL); /* clear plug/unplug flags for all ports */ @@ -652,6 +658,10 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) tmp = readl(mmio + hotplug_offset); writel(tmp | 0xff0000, mmio + hotplug_offset); + /* don't initialise TBG or SLEW on 2nd generation chips */ + if (hp->flags & PDC_FLAG_GEN_II) + return; + /* reduce TBG clock to 133 Mhz. */ tmp = readl(mmio + PDC_TBG_MODE); tmp &= ~0x30000; /* clear bit 17, 16*/ @@ -745,6 +755,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* notice 4-port boards */ switch (board_idx) { case board_40518: + hp->flags |= PDC_FLAG_GEN_II; /* Override hotplug offset for SATAII150 */ hp->hotplug_offset = PDC2_SATA_PLUG_CSR; /* Fall through */ @@ -758,15 +769,14 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->port[3].scr_addr = base + 0x700; break; case board_2057x: + case board_20771: + hp->flags |= PDC_FLAG_GEN_II; /* Override hotplug offset for SATAII150 */ hp->hotplug_offset = PDC2_SATA_PLUG_CSR; /* Fall through */ case board_2037x: probe_ent->n_ports = 2; break; - case board_20771: - probe_ent->n_ports = 2; - break; case board_20619: probe_ent->n_ports = 4; -- cgit v1.2.3 From 54083f114efad2d4fa993c52024f8973c70b9edb Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 15 Nov 2006 16:17:13 +0000 Subject: [PATCH] pata_hpt366 enablebits More enablebits Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt366.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index c0e150a9586b..c15c8dc3a6db 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.5" +#define DRV_VERSION "0.5.1" struct hpt_clock { u8 xfer_speed; @@ -222,9 +222,17 @@ static u32 hpt36x_find_mode(struct ata_port *ap, int speed) static int hpt36x_pre_reset(struct ata_port *ap) { + static const struct pci_bits hpt36x_enable_bits[] = { + { 0x50, 1, 0x04, 0x04 }, + { 0x54, 1, 0x04, 0x04 } + }; + u8 ata66; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no])) + return -ENOENT; + pci_read_config_byte(pdev, 0x5A, &ata66); if (ata66 & (1 << ap->port_no)) ap->cbl = ATA_CBL_PATA40; -- cgit v1.2.3 From f7e37ba83fd3e92411dfc97d08eaf9d85dfac2ee Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:21:03 +0000 Subject: [PATCH] pata_cs5530: suspend/resume support The 5530 needs various set up performing both at init time and resume time. To keep the code clean the common setup code is moved into a new function and called from both handlers. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_cs5530.c | 99 +++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 37 deletions(-) diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 981f49223469..265012b16bbb 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "pata_cs5530" -#define DRV_VERSION "0.6" +#define DRV_VERSION "0.7.1" /** * cs5530_set_piomode - PIO setup @@ -182,6 +182,8 @@ static struct scsi_host_template cs5530_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cs5530_port_ops = { @@ -239,38 +241,18 @@ static int cs5530_is_palmax(void) return 0; } + /** - * cs5530_init_one - Initialise a CS5530 - * @dev: PCI device - * @id: Entry in match table + * cs5530_init_chip - Chipset init * - * Install a driver for the newly found CS5530 companion chip. Most of - * this is just housekeeping. We have to set the chip up correctly and - * turn off various bits of emulation magic. + * Perform the chip initialisation work that is shared between both + * setup and resume paths */ - -static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) + +static int cs5530_init_chip(void) { - int compiler_warning_pointless_fix; - struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; - static struct ata_port_info info = { - .sht = &cs5530_sht, - .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x07, - .port_ops = &cs5530_port_ops - }; - /* The docking connector doesn't do UDMA, and it seems not MWDMA */ - static struct ata_port_info info_palmax_secondary = { - .sht = &cs5530_sht, - .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, - .pio_mask = 0x1f, - .port_ops = &cs5530_port_ops - }; - static struct ata_port_info *port_info[2] = { &info, &info }; + struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL; - dev = NULL; while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { switch (dev->device) { case PCI_DEVICE_ID_CYRIX_PCI_MASTER: @@ -291,7 +273,7 @@ static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) } pci_set_master(cs5530_0); - compiler_warning_pointless_fix = pci_set_mwi(cs5530_0); + pci_set_mwi(cs5530_0); /* * Set PCI CacheLineSize to 16-bytes: @@ -339,13 +321,7 @@ static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) pci_dev_put(master_0); pci_dev_put(cs5530_0); - - if (cs5530_is_palmax()) - port_info[1] = &info_palmax_secondary; - - /* Now kick off ATA set up */ - return ata_pci_init_one(dev, port_info, 2); - + return 0; fail_put: if (master_0) pci_dev_put(master_0); @@ -354,6 +330,53 @@ fail_put: return -ENODEV; } +/** + * cs5530_init_one - Initialise a CS5530 + * @dev: PCI device + * @id: Entry in match table + * + * Install a driver for the newly found CS5530 companion chip. Most of + * this is just housekeeping. We have to set the chip up correctly and + * turn off various bits of emulation magic. + */ + +static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &cs5530_sht, + .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x07, + .port_ops = &cs5530_port_ops + }; + /* The docking connector doesn't do UDMA, and it seems not MWDMA */ + static struct ata_port_info info_palmax_secondary = { + .sht = &cs5530_sht, + .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, + .pio_mask = 0x1f, + .port_ops = &cs5530_port_ops + }; + static struct ata_port_info *port_info[2] = { &info, &info }; + + /* Chip initialisation */ + if (cs5530_init_chip()) + return -ENODEV; + + if (cs5530_is_palmax()) + port_info[1] = &info_palmax_secondary; + + /* Now kick off ATA set up */ + return ata_pci_init_one(pdev, port_info, 2); +} + +static int cs5530_reinit_one(struct pci_dev *pdev) +{ + /* If we fail on resume we are doomed */ + BUG_ON(cs5530_init_chip()); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id cs5530[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, @@ -364,7 +387,9 @@ static struct pci_driver cs5530_pci_driver = { .name = DRV_NAME, .id_table = cs5530, .probe = cs5530_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = cs5530_reinit_one, }; static int __init cs5530_init(void) -- cgit v1.2.3 From d39ca896fb9a25f80465d3e52872cf5c510762a8 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:18:30 +0000 Subject: [PATCH] pata_jmicron: fix JMB368 support, add suspend/resume handling This (and the pci resume quirk code) get the JMicron controllers to resume properly. Without this patch the drive mapping changes when you suspend/resume which is not good at all.... Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_jmicron.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 0210b10d49cd..c9f0a543b27b 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -19,7 +19,7 @@ #include #define DRV_NAME "pata_jmicron" -#define DRV_VERSION "0.1.2" +#define DRV_VERSION "0.1.4" typedef enum { PORT_PATA0 = 0, @@ -213,12 +213,11 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i /* FIXME: We may want a way to override this in future */ pci_write_config_byte(pdev, 0x41, 0xa1); - } - - /* PATA controller is fn 1, AHCI is fn 0 */ - if (PCI_FUNC(pdev->devfn) != 1) - return -ENODEV; + /* PATA controller is fn 1, AHCI is fn 0 */ + if (PCI_FUNC(pdev->devfn) != 1) + return -ENODEV; + } if ( id->driver_data == 365 || id->driver_data == 366) { /* The 365/66 have two PATA channels, redirect the second */ pci_read_config_dword(pdev, 0x80, ®); @@ -229,6 +228,27 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i return ata_pci_init_one(pdev, port_info, 2); } +static int jmicron_reinit_one(struct pci_dev *pdev) +{ + u32 reg; + + switch(pdev->device) { + case PCI_DEVICE_ID_JMICRON_JMB368: + break; + case PCI_DEVICE_ID_JMICRON_JMB365: + case PCI_DEVICE_ID_JMICRON_JMB366: + /* Restore mapping or disks swap and boy does it get ugly */ + pci_read_config_dword(pdev, 0x80, ®); + reg |= (1 << 24); /* IDE1 to PATA IDE secondary */ + pci_write_config_dword(pdev, 0x80, reg); + /* Fall through */ + default: + /* Make sure AHCI is turned back on */ + pci_write_config_byte(pdev, 0x41, 0xa1); + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id jmicron_pci_tbl[] = { { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361}, { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363}, @@ -244,6 +264,8 @@ static struct pci_driver jmicron_pci_driver = { .id_table = jmicron_pci_tbl, .probe = jmicron_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = jmicron_reinit_one, }; static int __init jmicron_init(void) -- cgit v1.2.3 From 34d8dfb1e6b51dbd6eefcb449b531c7ee773664c Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:26:06 +0000 Subject: [PATCH] pata_ali: suspend/resume support Various chipset functions must be reprogrammed on a resume from RAM, without this things like ATAPI DMA stop working on resume with some chipset variants. Split the chipset programming and init time method selection into two functions. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_ali.c | 135 ++++++++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index e6d2b840e870..ae6d573574cd 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.6.6" +#define DRV_VERSION "0.7.1" /* * Cable special cases @@ -348,6 +348,8 @@ static struct scsi_host_template ali_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; /* @@ -497,6 +499,69 @@ static struct ata_port_operations ali_c5_port_ops = { .host_stop = ata_host_stop }; + +/** + * ali_init_chipset - chip setup function + * @pdev: PCI device of ATA controller + * + * Perform the setup on the device that must be done both at boot + * and at resume time. + */ + +static void ali_init_chipset(struct pci_dev *pdev) +{ + u8 rev, tmp; + struct pci_dev *north, *isa_bridge; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + + /* + * The chipset revision selects the driver operations and + * mode data. + */ + + if (rev >= 0x20 && rev < 0xC2) { + /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ + pci_read_config_byte(pdev, 0x4B, &tmp); + /* Clear CD-ROM DMA write bit */ + tmp &= 0x7F; + pci_write_config_byte(pdev, 0x4B, tmp); + } else if (rev >= 0xC2) { + /* Enable cable detection logic */ + pci_read_config_byte(pdev, 0x4B, &tmp); + pci_write_config_byte(pdev, 0x4B, tmp | 0x08); + } + north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + + if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { + /* Configure the ALi bridge logic. For non ALi rely on BIOS. + Set the south bridge enable bit */ + pci_read_config_byte(isa_bridge, 0x79, &tmp); + if (rev == 0xC2) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); + else if (rev > 0xC2) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); + } + if (rev >= 0x20) { + /* + * CD_ROM DMA on (0x53 bit 0). Enable this even if we want + * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control + * via 0x54/55. + */ + pci_read_config_byte(pdev, 0x53, &tmp); + if (rev <= 0x20) + tmp &= ~0x02; + if (rev >= 0xc7) + tmp |= 0x03; + else + tmp |= 0x01; /* CD_ROM enable for DMA */ + pci_write_config_byte(pdev, 0x53, tmp); + } + pci_dev_put(isa_bridge); + pci_dev_put(north); + ata_pci_clear_simplex(pdev); +} /** * ali_init_one - discovery callback * @pdev: PCI device ID @@ -570,7 +635,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static struct ata_port_info *port_info[2]; u8 rev, tmp; - struct pci_dev *north, *isa_bridge; + struct pci_dev *isa_bridge; pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); @@ -582,11 +647,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (rev < 0x20) { port_info[0] = port_info[1] = &info_early; } else if (rev < 0xC2) { - /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ - pci_read_config_byte(pdev, 0x4B, &tmp); - /* Clear CD-ROM DMA write bit */ - tmp &= 0x7F; - pci_write_config_byte(pdev, 0x4B, tmp); port_info[0] = port_info[1] = &info_20; } else if (rev == 0xC2) { port_info[0] = port_info[1] = &info_c2; @@ -597,54 +657,25 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } else port_info[0] = port_info[1] = &info_c5; - if (rev >= 0xC2) { - /* Enable cable detection logic */ - pci_read_config_byte(pdev, 0x4B, &tmp); - pci_write_config_byte(pdev, 0x4B, tmp | 0x08); - } - - north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); + ali_init_chipset(pdev); + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - - if (north && north->vendor == PCI_VENDOR_ID_AL) { - /* Configure the ALi bridge logic. For non ALi rely on BIOS. - Set the south bridge enable bit */ - pci_read_config_byte(isa_bridge, 0x79, &tmp); - if (rev == 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); - else if (rev > 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); + if (isa_bridge && rev >= 0x20 && rev < 0xC2) { + /* Are we paired with a UDMA capable chip */ + pci_read_config_byte(isa_bridge, 0x5E, &tmp); + if ((tmp & 0x1E) == 0x12) + port_info[0] = port_info[1] = &info_20_udma; + pci_dev_put(isa_bridge); } - - if (rev >= 0x20) { - if (rev < 0xC2) { - /* Are we paired with a UDMA capable chip */ - pci_read_config_byte(isa_bridge, 0x5E, &tmp); - if ((tmp & 0x1E) == 0x12) - port_info[0] = port_info[1] = &info_20_udma; - } - /* - * CD_ROM DMA on (0x53 bit 0). Enable this even if we want - * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control - * via 0x54/55. - */ - pci_read_config_byte(pdev, 0x53, &tmp); - if (rev <= 0x20) - tmp &= ~0x02; - if (rev >= 0xc7) - tmp |= 0x03; - else - tmp |= 0x01; /* CD_ROM enable for DMA */ - pci_write_config_byte(pdev, 0x53, tmp); - } - - pci_dev_put(isa_bridge); - pci_dev_put(north); - - ata_pci_clear_simplex(pdev); return ata_pci_init_one(pdev, port_info, 2); } +static int ali_reinit_one(struct pci_dev *pdev) +{ + ali_init_chipset(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id ali[] = { { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, @@ -656,7 +687,9 @@ static struct pci_driver ali_pci_driver = { .name = DRV_NAME, .id_table = ali, .probe = ali_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ali_reinit_one, }; static int __init ali_init(void) -- cgit v1.2.3 From ad4a42d287546888349ad24d351673a59f429ee8 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:23:37 +0000 Subject: [PATCH] pata_rz1000: Force readahead off on resume The RZ1000 is a generic device except that it has a readahead fifo flaw that corrupts. We force this off at init time but we want to be paranoid and force it off at resume as well. I don't know of any actual hardware that supports both RZ1000 and suspend to RAM but given its a disk muncher better safe than sorry. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_rz1000.c | 48 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index e4e5ea423fef..21567aba82d2 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -21,7 +21,7 @@ #include #define DRV_NAME "pata_rz1000" -#define DRV_VERSION "0.2.2" +#define DRV_VERSION "0.2.3" /** @@ -92,6 +92,8 @@ static struct scsi_host_template rz1000_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations rz1000_port_ops = { @@ -129,6 +131,19 @@ static struct ata_port_operations rz1000_port_ops = { .host_stop = ata_host_stop }; +static int rz1000_fifo_disable(struct pci_dev *pdev) +{ + u16 reg; + /* Be exceptionally paranoid as we must be sure to apply the fix */ + if (pci_read_config_word(pdev, 0x40, ®) != 0) + return -1; + reg &= 0xDFFF; + if (pci_write_config_word(pdev, 0x40, reg) != 0) + return -1; + printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n"); + return 0; +} + /** * rz1000_init_one - Register RZ1000 ATA PCI device with kernel services * @pdev: PCI device to register @@ -143,7 +158,6 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en { static int printed_version; struct ata_port_info *port_info[2]; - u16 reg; static struct ata_port_info info = { .sht = &rz1000_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, @@ -154,23 +168,25 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); - /* Be exceptionally paranoid as we must be sure to apply the fix */ - if (pci_read_config_word(pdev, 0x40, ®) != 0) - goto fail; - reg &= 0xDFFF; - if (pci_write_config_word(pdev, 0x40, reg) != 0) - goto fail; - printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n"); - - port_info[0] = &info; - port_info[1] = &info; - return ata_pci_init_one(pdev, port_info, 2); -fail: + if (rz1000_fifo_disable(pdev) == 0) { + port_info[0] = &info; + port_info[1] = &info; + return ata_pci_init_one(pdev, port_info, 2); + } printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n"); /* Not safe to use so skip */ return -ENODEV; } +static int rz1000_reinit_one(struct pci_dev *pdev) +{ + /* If this fails on resume (which is a "cant happen" case), we + must stop as any progress risks data loss */ + if (rz1000_fifo_disable(pdev)) + panic("rz1000 fifo"); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id pata_rz1000[] = { { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), }, { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), }, @@ -182,7 +198,9 @@ static struct pci_driver rz1000_pci_driver = { .name = DRV_NAME, .id_table = pata_rz1000, .probe = rz1000_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = rz1000_reinit_one, }; static int __init rz1000_init(void) -- cgit v1.2.3 From 8550c1637ba7dd96a76353eb52d31088f9c2f5fe Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:28:41 +0000 Subject: [PATCH] pata_sil680 suspend/resume The SI680 can come back from s2ram with the clocks disabled (crash time) or wrong (ugly as this can cause CRC errors, and in theory corruption). On a resume we must put the clock back. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_sil680.c | 82 +++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 11942fd03b55..5d3b42ec8e47 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -33,7 +33,7 @@ #include #define DRV_NAME "pata_sil680" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.4.1" /** * sil680_selreg - return register base @@ -263,32 +263,20 @@ static struct ata_port_operations sil680_port_ops = { .host_stop = ata_host_stop }; -static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +/** + * sil680_init_chip - chip setup + * @pdev: PCI device + * + * Perform all the chip setup which must be done both when the device + * is powered up on boot and when we resume in case we resumed from RAM. + * Returns the final clock settings. + */ + +static u8 sil680_init_chip(struct pci_dev *pdev) { - static struct ata_port_info info = { - .sht = &sil680_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - .port_ops = &sil680_port_ops - }; - static struct ata_port_info info_slow = { - .sht = &sil680_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x3f, - .port_ops = &sil680_port_ops - }; - static struct ata_port_info *port_info[2] = {&info, &info}; - static int printed_version; u32 class_rev = 0; u8 tmpbyte = 0; - if (!printed_version++) - dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; /* FIXME: double check */ @@ -323,8 +311,6 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_read_config_byte(pdev, 0x8A, &tmpbyte); printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n", tmpbyte & 1, tmpbyte & 0x30); - if ((tmpbyte & 0x30) == 0) - port_info[0] = port_info[1] = &info_slow; pci_write_config_byte(pdev, 0xA1, 0x72); pci_write_config_word(pdev, 0xA2, 0x328A); @@ -343,11 +329,51 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break; /* This last case is _NOT_ ok */ case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n"); - return -EIO; + } + return tmpbyte & 0x30; +} + +static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &sil680_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + .port_ops = &sil680_port_ops + }; + static struct ata_port_info info_slow = { + .sht = &sil680_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x3f, + .port_ops = &sil680_port_ops + }; + static struct ata_port_info *port_info[2] = {&info, &info}; + static int printed_version; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + + switch(sil680_init_chip(pdev)) + { + case 0: + port_info[0] = port_info[1] = &info_slow; + break; + case 0x30: + return -ENODEV; } return ata_pci_init_one(pdev, port_info, 2); } +static int sil680_reinit_one(struct pci_dev *pdev) +{ + sil680_init_chip(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id sil680[] = { { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), }, @@ -358,7 +384,9 @@ static struct pci_driver sil680_pci_driver = { .name = DRV_NAME, .id_table = sil680, .probe = sil680_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = sil680_reinit_one, }; static int __init sil680_init(void) -- cgit v1.2.3 From 30ced0f0d211999f316930eff7287aa5a9995bef Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 16:57:36 +0000 Subject: [PATCH] PATA libata: suspend/resume simple cases This patch adds the suspend/resume callbacks for drivers which don't need any additional help (beyond the pci resume quirk patch I posted earlier anyway). Also bring version numbers back inline with master copies. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 8 ++++++-- drivers/ata/pata_atiixp.c | 8 ++++++-- drivers/ata/pata_cs5535.c | 6 +++++- drivers/ata/pata_cypress.c | 8 ++++++-- drivers/ata/pata_efar.c | 6 +++++- drivers/ata/pata_marvell.c | 6 +++++- drivers/ata/pata_mpiix.c | 8 ++++++-- drivers/ata/pata_netcell.c | 6 +++++- drivers/ata/pata_ns87410.c | 8 ++++++-- drivers/ata/pata_oldpiix.c | 4 ++++ drivers/ata/pata_opti.c | 33 ++++++--------------------------- drivers/ata/pata_optidma.c | 8 ++++++-- drivers/ata/pata_radisys.c | 4 ++++ drivers/ata/pata_sc1200.c | 8 ++++++-- drivers/ata/pata_triflex.c | 8 ++++++-- 15 files changed, 82 insertions(+), 47 deletions(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 1b9ba4dfac65..c7e8f033125d 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.7" +#define DRV_VERSION "0.2.10" /* * A generic parallel ATA driver using libata @@ -118,6 +118,8 @@ static struct scsi_host_template generic_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations generic_port_ops = { @@ -226,7 +228,9 @@ static struct pci_driver ata_generic_pci_driver = { .name = DRV_NAME, .id_table = ata_generic, .probe = ata_generic_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init ata_generic_init(void) diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 4e1d3b59adbb..7d9e391b0d18 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -22,7 +22,7 @@ #include #define DRV_NAME "pata_atiixp" -#define DRV_VERSION "0.4.3" +#define DRV_VERSION "0.4.4" enum { ATIIXP_IDE_PIO_TIMING = 0x40, @@ -218,6 +218,8 @@ static struct scsi_host_template atiixp_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations atiixp_port_ops = { @@ -281,7 +283,9 @@ static struct pci_driver atiixp_pci_driver = { .name = DRV_NAME, .id_table = atiixp, .probe = atiixp_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .resume = ata_pci_device_resume, + .suspend = ata_pci_device_suspend, }; static int __init atiixp_init(void) diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 8dafa4a49fdc..38c00f628761 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -39,7 +39,7 @@ #include #define DRV_NAME "cs5535" -#define DRV_VERSION "0.2.10" +#define DRV_VERSION "0.2.11" /* * The Geode (Aka Athlon GX now) uses an internal MSR based @@ -186,6 +186,8 @@ static struct scsi_host_template cs5535_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cs5535_port_ops = { @@ -269,6 +271,8 @@ static struct pci_driver cs5535_pci_driver = { .id_table = cs5535, .probe = cs5535_init_one, .remove = ata_pci_remove_one + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init cs5535_init(void) diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 5a0b811907ee..6352bc7df603 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -18,7 +18,7 @@ #include #define DRV_NAME "pata_cypress" -#define DRV_VERSION "0.1.2" +#define DRV_VERSION "0.1.4" /* here are the offset definitions for the registers */ @@ -137,6 +137,8 @@ static struct scsi_host_template cy82c693_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cy82c693_port_ops = { @@ -204,7 +206,9 @@ static struct pci_driver cy82c693_pci_driver = { .name = DRV_NAME, .id_table = cy82c693, .probe = cy82c693_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init cy82c693_init(void) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 755f79279de3..56589834483d 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -22,7 +22,7 @@ #include #define DRV_NAME "pata_efar" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" /** * efar_pre_reset - check for 40/80 pin @@ -235,6 +235,8 @@ static struct scsi_host_template efar_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations efar_ops = { @@ -316,6 +318,8 @@ static struct pci_driver efar_pci_driver = { .id_table = efar_pci_tbl, .probe = efar_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init efar_init(void) diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 1ea64075c783..a5953c389264 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -20,7 +20,7 @@ #include #define DRV_NAME "pata_marvell" -#define DRV_VERSION "0.0.5u" +#define DRV_VERSION "0.1.1" /** * marvell_pre_reset - check for 40/80 pin @@ -103,6 +103,8 @@ static struct scsi_host_template marvell_sht = { .slave_configure = ata_scsi_slave_config, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations marvell_ops = { @@ -197,6 +199,8 @@ static struct pci_driver marvell_pci_driver = { .id_table = marvell_pci_tbl, .probe = marvell_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init marvell_init(void) diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index e00d406bfdf5..752a7418ed51 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "pata_mpiix" -#define DRV_VERSION "0.7.2" +#define DRV_VERSION "0.7.3" enum { IDETIM = 0x6C, /* IDE control register */ @@ -168,6 +168,8 @@ static struct scsi_host_template mpiix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations mpiix_port_ops = { @@ -285,7 +287,9 @@ static struct pci_driver mpiix_pci_driver = { .name = DRV_NAME, .id_table = mpiix, .probe = mpiix_init_one, - .remove = mpiix_remove_one + .remove = mpiix_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init mpiix_init(void) diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 1963a4d35873..956616789ba1 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -16,7 +16,7 @@ #include #define DRV_NAME "pata_netcell" -#define DRV_VERSION "0.1.5" +#define DRV_VERSION "0.1.6" /** * netcell_probe_init - check for 40/80 pin @@ -65,6 +65,8 @@ static struct scsi_host_template netcell_sht = { .slave_destroy = ata_scsi_slave_destroy, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations netcell_ops = { @@ -153,6 +155,8 @@ static struct pci_driver netcell_pci_driver = { .id_table = netcell_pci_tbl, .probe = netcell_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init netcell_init(void) diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 7ec800f00ec8..428e6b511a2f 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -28,7 +28,7 @@ #include #define DRV_NAME "pata_ns87410" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" /** * ns87410_pre_reset - probe begin @@ -158,6 +158,8 @@ static struct scsi_host_template ns87410_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations ns87410_port_ops = { @@ -210,7 +212,9 @@ static struct pci_driver ns87410_pci_driver = { .name = DRV_NAME, .id_table = ns87410, .probe = ns87410_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init ns87410_init(void) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 8837256632e9..1283fb71bd5d 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -233,6 +233,8 @@ static struct scsi_host_template oldpiix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations oldpiix_pata_ops = { @@ -314,6 +316,8 @@ static struct pci_driver oldpiix_pci_driver = { .id_table = oldpiix_pci_tbl, .probe = oldpiix_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init oldpiix_init(void) diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index c6319cf50de4..66f561db2ab1 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_opti" -#define DRV_VERSION "0.2.5" +#define DRV_VERSION "0.2.7" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -109,30 +109,6 @@ static void opti_write_reg(struct ata_port *ap, u8 val, int reg) outb(0x83, regio + 2); } -#if 0 -/** - * opti_read_reg - control register read - * @ap: ATA port - * @reg: control register number - * - * The Opti uses magic 'trapdoor' register accesses to do configuration - * rather than using PCI space as other controllers do. The double inw - * on the error register activates configuration mode. We can then read - * the control register - */ - -static u8 opti_read_reg(struct ata_port *ap, int reg) -{ - unsigned long regio = ap->ioaddr.cmd_addr; - u8 ret; - inw(regio + 1); - inw(regio + 1); - outb(3, regio + 2); - ret = inb(regio + reg); - outb(0x83, regio + 2); -} -#endif - /** * opti_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -204,12 +180,13 @@ static struct scsi_host_template opti_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations opti_port_ops = { .port_disable = ata_port_disable, .set_piomode = opti_set_piomode, -/* .set_dmamode = opti_set_dmamode, */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -267,7 +244,9 @@ static struct pci_driver opti_pci_driver = { .name = DRV_NAME, .id_table = opti, .probe = opti_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init opti_init(void) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 2f4770cce04e..d898e42f99e8 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -33,7 +33,7 @@ #include #define DRV_NAME "pata_optidma" -#define DRV_VERSION "0.2.2" +#define DRV_VERSION "0.2.3" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -361,6 +361,8 @@ static struct scsi_host_template optidma_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations optidma_port_ops = { @@ -522,7 +524,9 @@ static struct pci_driver optidma_pci_driver = { .name = DRV_NAME, .id_table = optidma, .probe = optidma_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init optidma_init(void) diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 048c2bb21ef1..5fe7ffce5284 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -229,6 +229,8 @@ static struct scsi_host_template radisys_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations radisys_pata_ops = { @@ -311,6 +313,8 @@ static struct pci_driver radisys_pci_driver = { .id_table = radisys_pci_tbl, .probe = radisys_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init radisys_init(void) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 0c75dae74764..0c5393a73970 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -40,7 +40,7 @@ #include #define DRV_NAME "sc1200" -#define DRV_VERSION "0.2.3" +#define DRV_VERSION "0.2.4" #define SC1200_REV_A 0x00 #define SC1200_REV_B1 0x01 @@ -195,6 +195,8 @@ static struct scsi_host_template sc1200_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations sc1200_port_ops = { @@ -264,7 +266,9 @@ static struct pci_driver sc1200_pci_driver = { .name = DRV_NAME, .id_table = sc1200, .probe = sc1200_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init sc1200_init(void) diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index bfda1f7e760a..ece9cb7c2f4d 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -43,7 +43,7 @@ #include #define DRV_NAME "pata_triflex" -#define DRV_VERSION "0.2.5" +#define DRV_VERSION "0.2.7" /** * triflex_prereset - probe begin @@ -194,6 +194,8 @@ static struct scsi_host_template triflex_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations triflex_port_ops = { @@ -258,7 +260,9 @@ static struct pci_driver triflex_pci_driver = { .name = DRV_NAME, .id_table = triflex, .probe = triflex_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init triflex_init(void) -- cgit v1.2.3 From 8501120f1df1aa6abe38b51ab91df08ccaa1b971 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:01:06 +0000 Subject: [PATCH] pata_cs5520: resume support The CS5520 doesn't need much help to resume but we do need to restore pcicfg which may have been reset to the BIOS default which is sometimes incorrect. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_cs5520.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 33d2b88f9c79..f839c0304b3a 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -41,7 +41,7 @@ #include #define DRV_NAME "pata_cs5520" -#define DRV_VERSION "0.6.2" +#define DRV_VERSION "0.6.3" struct pio_clocks { @@ -168,6 +168,8 @@ static struct scsi_host_template cs5520_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cs5520_port_ops = { @@ -297,6 +299,22 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev) dev_set_drvdata(dev, NULL); } +/** + * cs5520_reinit_one - device resume + * @pdev: PCI device + * + * Do any reconfiguration work needed by a resume from RAM. We need + * to restore DMA mode support on BIOSen which disabled it + */ + +static int cs5520_reinit_one(struct pci_dev *pdev) +{ + u8 pcicfg; + pci_read_config_byte(pdev, 0x60, &pcicfg); + if ((pcicfg & 0x40) == 0) + pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); + return ata_pci_device_resume(pdev); +} /* For now keep DMA off. We can set it for all but A rev CS5510 once the core ATA code can handle it */ @@ -311,7 +329,9 @@ static struct pci_driver cs5520_pci_driver = { .name = DRV_NAME, .id_table = pata_cs5520, .probe = cs5520_init_one, - .remove = cs5520_remove_one + .remove = cs5520_remove_one, + .suspend = ata_pci_device_suspend, + .resume = cs5520_reinit_one, }; static int __init cs5520_init(void) -- cgit v1.2.3 From 7f72a379146913dc5f2751383722cdedb8998bc9 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 16:59:07 +0000 Subject: [PATCH] pata_cmd64x: suspend/resume On a resume of the CMD64x we must restore MRDMODE and latency if the BIOS didn't get them right originally. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 29a60df465da..3376f3f4bad9 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -31,7 +31,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.1" +#define DRV_VERSION "0.2.2" /* * CMD64x specific registers definition. @@ -277,6 +277,8 @@ static struct scsi_host_template cmd64x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations cmd64x_port_ops = { @@ -469,6 +471,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +static int cmd64x_reinit_one(struct pci_dev *pdev) +{ + u8 mrdmode; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(pdev, MRDMODE, &mrdmode); + mrdmode &= ~ 0x30; /* IRQ set up */ + mrdmode |= 0x02; /* Memory read line enable */ + pci_write_config_byte(pdev, MRDMODE, mrdmode); +#ifdef CONFIG_PPC + pci_write_config_byte(pdev, UDIDETCR0, 0xF0); +#endif + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id cmd64x[] = { { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 }, { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 }, @@ -482,7 +498,9 @@ static struct pci_driver cmd64x_pci_driver = { .name = DRV_NAME, .id_table = cmd64x, .probe = cmd64x_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = cmd64x_reinit_one, }; static int __init cmd64x_init(void) -- cgit v1.2.3 From 38e0d56e67849720d306e2d7cd1a2793deec9644 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:16:35 +0000 Subject: [PATCH] pata_serverworks suspend/resume The Serverworks chips need various fixups doing on a resume from RAM. Conveniently the needed functions were already split out ready for re-use Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_serverworks.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index be7f60efcb61..0fa803e6399c 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -41,7 +41,7 @@ #include #define DRV_NAME "pata_serverworks" -#define DRV_VERSION "0.3.7" +#define DRV_VERSION "0.3.9" #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ @@ -327,6 +327,8 @@ static struct scsi_host_template serverworks_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations serverworks_osb4_port_ops = { @@ -554,6 +556,30 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id return ata_pci_init_one(pdev, port_info, ports); } +static int serverworks_reinit_one(struct pci_dev *pdev) +{ + /* Force master latency timer to 64 PCI clocks */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + + switch (pdev->device) + { + case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: + serverworks_fixup_osb4(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + ata_pci_clear_simplex(pdev); + /* fall through */ + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + serverworks_fixup_csb(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: + serverworks_fixup_ht1000(pdev); + break; + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id serverworks[] = { { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2}, @@ -568,7 +594,9 @@ static struct pci_driver serverworks_pci_driver = { .name = DRV_NAME, .id_table = serverworks, .probe = serverworks_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = serverworks_reinit_one, }; static int __init serverworks_init(void) -- cgit v1.2.3 From f535d53f3f8bc8243ad2167d7127f6efba9b46cb Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:14:36 +0000 Subject: [PATCH] pata_it821x: Suspend/Resume support If you are using the noraid option then after a suspend/resume sequence we need to reset the card back out of raid mode again. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_it821x.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 7f68f14be6fd..d57ac741cc08 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -80,7 +80,7 @@ #define DRV_NAME "pata_it821x" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.3.3" struct it821x_dev { @@ -677,6 +677,8 @@ static struct scsi_host_template it821x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations it821x_smart_port_ops = { @@ -809,6 +811,14 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +static int it821x_reinit_one(struct pci_dev *pdev) +{ + /* Resume - turn raid back off if need be */ + if (it8212_noraid) + it821x_disable_raid(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id it821x[] = { { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), }, { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), }, @@ -820,7 +830,9 @@ static struct pci_driver it821x_pci_driver = { .name = DRV_NAME, .id_table = it821x, .probe = it821x_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = it821x_reinit_one, }; static int __init it821x_init(void) -- cgit v1.2.3 From c304193a005b5262671c1389b1cae96d7afc952a Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:21:24 +0000 Subject: [PATCH] pata_amd: suspend/resume Early AMD chips require FIFO and/or simplex flag clearing work on resume from RAM. Most devices need no help Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_amd.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 8be46a63af74..d9571206e580 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.2.4" +#define DRV_VERSION "0.2.7" /** * timing_setup - shared timing computation and load @@ -335,6 +335,8 @@ static struct scsi_host_template amd_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations amd33_port_ops = { @@ -662,6 +664,23 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +static int amd_reinit_one(struct pci_dev *pdev) +{ + if (pdev->vendor == PCI_VENDOR_ID_AMD) { + u8 fifo; + pci_read_config_byte(pdev, 0x41, &fifo); + if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) + /* FIFO is broken */ + pci_write_config_byte(pdev, 0x41, fifo & 0x0F); + else + pci_write_config_byte(pdev, 0x41, fifo | 0xF0); + if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 || + pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401) + ata_pci_clear_simplex(pdev); + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id amd[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 }, @@ -689,7 +708,9 @@ static struct pci_driver amd_pci_driver = { .name = DRV_NAME, .id_table = amd, .probe = amd_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = amd_reinit_one, }; static int __init amd_init(void) -- cgit v1.2.3 From 627d2d3261a42c9b5b0a02a1f8d0ae5414729cb9 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:19:36 +0000 Subject: [PATCH] pata_via suspend/resume support The major VIA issues were handled by the quirks update for resume quirks. The ATA driver also has to do some work however when resuming from RAM. Certain chips need the FIFO reconfiguring, and the 66MHz clock setup updating. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 94 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index c5f1616d224d..489bd5796e73 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -60,7 +60,7 @@ #include #define DRV_NAME "pata_via" -#define DRV_VERSION "0.1.14" +#define DRV_VERSION "0.2.0" /* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx @@ -297,6 +297,8 @@ static struct scsi_host_template via_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations via_port_ops = { @@ -369,9 +371,43 @@ static struct ata_port_operations via_port_ops_noirq = { .host_stop = ata_host_stop }; +/** + * via_config_fifo - set up the FIFO + * @pdev: PCI device + * @flags: configuration flags + * + * Set the FIFO properties for this device if neccessary. Used both on + * set up and on and the resume path + */ + +static void via_config_fifo(struct pci_dev *pdev, unsigned int flags) +{ + u8 enable; + + /* 0x40 low bits indicate enabled channels */ + pci_read_config_byte(pdev, 0x40 , &enable); + enable &= 3; + + if (flags & VIA_SET_FIFO) { + u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; + u8 fifo; + + pci_read_config_byte(pdev, 0x43, &fifo); + + /* Clear PREQ# until DDACK# for errata */ + if (flags & VIA_BAD_PREQ) + fifo &= 0x7F; + else + fifo &= 0x9f; + /* Turn on FIFO for enabled channels */ + fifo |= fifo_setting[enable]; + pci_write_config_byte(pdev, 0x43, fifo); + } +} + /** * via_init_one - discovery callback - * @pdev: PCI device ID + * @pdev: PCI device * @id: PCI table info * * A VIA IDE interface has been discovered. Figure out what revision @@ -471,21 +507,8 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* Initialise the FIFO for the enabled channels. */ - if (config->flags & VIA_SET_FIFO) { - u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; - u8 fifo; - - pci_read_config_byte(pdev, 0x43, &fifo); - - /* Clear PREQ# until DDACK# for errata */ - if (config->flags & VIA_BAD_PREQ) - fifo &= 0x7F; - else - fifo &= 0x9f; - /* Turn on FIFO for enabled channels */ - fifo |= fifo_setting[enable]; - pci_write_config_byte(pdev, 0x43, fifo); - } + via_config_fifo(pdev, config->flags); + /* Clock set up */ switch(config->flags & VIA_UDMA) { case VIA_UDMA_NONE: @@ -529,6 +552,39 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +/** + * via_reinit_one - reinit after resume + * @pdev; PCI device + * + * Called when the VIA PATA device is resumed. We must then + * reconfigure the fifo and other setup we may have altered. In + * addition the kernel needs to have the resume methods on PCI + * quirk supported. + */ + +static int via_reinit_one(struct pci_dev *pdev) +{ + u32 timing; + struct ata_host *host = dev_get_drvdata(&pdev->dev); + const struct via_isa_bridge *config = host->private_data; + + via_config_fifo(pdev, config->flags); + + if ((config->flags & VIA_UDMA) == VIA_UDMA_66) { + /* The 66 MHz devices require we enable the clock */ + pci_read_config_dword(pdev, 0x50, &timing); + timing |= 0x80008; + pci_write_config_dword(pdev, 0x50, timing); + } + if (config->flags & VIA_BAD_CLK66) { + /* Disable the 66MHz clock on problem devices */ + pci_read_config_dword(pdev, 0x50, &timing); + timing &= ~0x80008; + pci_write_config_dword(pdev, 0x50, timing); + } + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id via[] = { { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), }, { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), }, @@ -542,7 +598,9 @@ static struct pci_driver via_pci_driver = { .name = DRV_NAME, .id_table = via, .probe = via_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = via_reinit_one, }; static int __init via_init(void) -- cgit v1.2.3 From aa54ab1eff30f1e5859acf4e15f0730288373ee5 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:24:15 +0000 Subject: [PATCH] hpt36x: Suspend/resume support Another chipset which needs some reconfiguration after a resume. All the chip setup is moved to a new function called in both setup and resume. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt366.c | 49 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index c15c8dc3a6db..25d3cd7e74f1 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.5.1" +#define DRV_VERSION "0.5.3" struct hpt_clock { u8 xfer_speed; @@ -339,6 +339,8 @@ static struct scsi_host_template hpt36x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; /* @@ -380,6 +382,27 @@ static struct ata_port_operations hpt366_port_ops = { .host_stop = ata_host_stop }; +/** + * hpt36x_init_chipset - common chip setup + * @dev: PCI device + * + * Perform the chip setup work that must be done at both init and + * resume time + */ + +static void hpt36x_init_chipset(struct pci_dev *dev) +{ + u8 drive_fast; + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); + pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); + pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + + pci_read_config_byte(dev, 0x51, &drive_fast); + if (drive_fast & 0x80) + pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); +} + /** * hpt36x_init_one - Initialise an HPT366/368 * @dev: PCI device @@ -415,7 +438,6 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) u32 class_rev; u32 reg1; - u8 drive_fast; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xFF; @@ -425,14 +447,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (class_rev > 2) return -ENODEV; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); - pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); - pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - - pci_read_config_byte(dev, 0x51, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); + hpt36x_init_chipset(dev); pci_read_config_dword(dev, 0x40, ®1); @@ -453,9 +468,15 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } +static int hpt36x_reinit_one(struct pci_dev *dev) +{ + hpt36x_init_chipset(dev); + return ata_pci_device_resume(dev); +} + + static const struct pci_device_id hpt36x[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, - { }, }; @@ -463,7 +484,9 @@ static struct pci_driver hpt36x_pci_driver = { .name = DRV_NAME, .id_table = hpt36x, .probe = hpt36x_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = hpt36x_reinit_one, }; static int __init hpt36x_init(void) @@ -471,13 +494,11 @@ static int __init hpt36x_init(void) return pci_register_driver(&hpt36x_pci_driver); } - static void __exit hpt36x_exit(void) { pci_unregister_driver(&hpt36x_pci_driver); } - MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 62d64ae0ec76360736c9dc4ca2067ae8de0ba9f2 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:27:20 +0000 Subject: [PATCH] pata : more drivers that need only standard suspend and resume Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc202xx_old.c | 8 ++++++-- drivers/ata/pata_sis.c | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index ed8d98557f16..81a134cca3cd 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -21,7 +21,7 @@ #include #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.2.2" +#define DRV_VERSION "0.2.3" /** * pdc2024x_pre_reset - probe begin @@ -271,6 +271,8 @@ static struct scsi_host_template pdc202xx_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations pdc2024x_port_ops = { @@ -400,7 +402,9 @@ static struct pci_driver pdc202xx_pci_driver = { .name = DRV_NAME, .id_table = pdc202xx, .probe = pdc202xx_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init pdc202xx_init(void) diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 91e85f90941d..695e571540cc 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_sis" -#define DRV_VERSION "0.4.4" +#define DRV_VERSION "0.4.5" struct sis_chipset { u16 device; /* PCI host ID */ @@ -547,6 +547,8 @@ static struct scsi_host_template sis_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations sis_133_ops = { @@ -1000,6 +1002,8 @@ static struct pci_driver sis_pci_driver = { .id_table = sis_pci_tbl, .probe = sis_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, }; static int __init sis_init(void) -- cgit v1.2.3 From aff0df0593f4beea42800115c0658f58c03dfe9f Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:25:51 +0000 Subject: [PATCH] pata_hpt3x3: suspend/resume support Again split the chipset init away and call it both on resume and on setup Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt3x3.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index d216cc564b56..e9fb029f28b7 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -23,7 +23,7 @@ #include #define DRV_NAME "pata_hpt3x3" -#define DRV_VERSION "0.4.1" +#define DRV_VERSION "0.4.2" static int hpt3x3_probe_init(struct ata_port *ap) { @@ -120,6 +120,8 @@ static struct scsi_host_template hpt3x3_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; static struct ata_port_operations hpt3x3_port_ops = { @@ -157,6 +159,27 @@ static struct ata_port_operations hpt3x3_port_ops = { .host_stop = ata_host_stop }; +/** + * hpt3x3_init_chipset - chip setup + * @dev: PCI device + * + * Perform the setup required at boot and on resume. + */ + +static void hpt3x3_init_chipset(struct pci_dev *dev) +{ + u16 cmd; + /* Initialize the board */ + pci_write_config_word(dev, 0x80, 0x00); + /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_MEMORY) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); + else + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); +} + + /** * hpt3x3_init_one - Initialise an HPT343/363 * @dev: PCI device @@ -178,21 +201,18 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &hpt3x3_port_ops }; static struct ata_port_info *port_info[2] = { &info, &info }; - u16 cmd; - - /* Initialize the board */ - pci_write_config_word(dev, 0x80, 0x00); - /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (cmd & PCI_COMMAND_MEMORY) - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); - else - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + hpt3x3_init_chipset(dev); /* Now kick off ATA set up */ return ata_pci_init_one(dev, port_info, 2); } +static int hpt3x3_reinit_one(struct pci_dev *dev) +{ + hpt3x3_init_chipset(dev); + return ata_pci_device_resume(dev); +} + static const struct pci_device_id hpt3x3[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), }, @@ -203,7 +223,9 @@ static struct pci_driver hpt3x3_pci_driver = { .name = DRV_NAME, .id_table = hpt3x3, .probe = hpt3x3_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = hpt3x3_reinit_one, }; static int __init hpt3x3_init(void) -- cgit v1.2.3 From 099156db555aabf54dc80b40abb628ce35d90065 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 27 Nov 2006 16:37:52 +0000 Subject: [PATCH] pata_marvell: merge Mandriva patches Correct and complete the Marvell PATA cable detection logic. From: Arnaud Patard Signed-off-by: Arnaud Patard Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_marvell.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index a5953c389264..25f7a79a8e25 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -57,11 +57,11 @@ static int marvell_pre_reset(struct ata_port *ap) switch(ap->port_no) { case 0: - /* Might be backward, docs unclear */ if (inb(ap->ioaddr.bmdma_addr + 1) & 1) - ap->cbl = ATA_CBL_PATA80; - else ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + break; case 1: /* Legacy SATA port */ ap->cbl = ATA_CBL_SATA; -- cgit v1.2.3 From 2dec7555e6bf2772749113ea0ad454fcdb8cf861 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Sun, 26 Nov 2006 14:20:19 -0600 Subject: [PATCH] sata_nv: fix ATAPI in ADMA mode The attached patch against 2.6.19-rc6-mm1 fixes some problems in sata_nv with ATAPI devices on controllers running in ADMA mode. Some of the logic in the nv_adma_bmdma_* functions was inverted causing a bunch of warnings and caused those functions not to work properly. Also, when an ATAPI device is connected, we need to use the legacy DMA engine. The code now disables the PCI configuration register bits for ADMA so that this works, and ensures that no ATAPI DMA commands go through until this is done. Fixes Bugzilla http://bugzilla.kernel.org/show_bug.cgi?id=7538 Signed-off-by: Robert Hancock Signed-off-by: Jeff Garzik --- drivers/ata/sata_nv.c | 318 +++++++++++++++++++++++++++++--------------------- 1 file changed, 188 insertions(+), 130 deletions(-) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index a57710107619..27d2225c9083 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -49,7 +49,7 @@ #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "3.1" +#define DRV_VERSION "3.2" #define NV_ADMA_DMA_BOUNDARY 0xffffffffUL @@ -165,6 +165,7 @@ enum { /* port flags */ NV_ADMA_PORT_REGISTER_MODE = (1 << 0), + NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1), }; @@ -231,6 +232,7 @@ static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); static void nv_error_handler(struct ata_port *ap); static int nv_adma_slave_config(struct scsi_device *sdev); +static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc); static void nv_adma_qc_prep(struct ata_queued_cmd *qc); static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc); static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance); @@ -415,6 +417,7 @@ static const struct ata_port_operations nv_adma_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, + .check_atapi_dma = nv_adma_check_atapi_dma, .exec_command = ata_exec_command, .check_status = ata_check_status, .dev_select = ata_std_dev_select, @@ -489,13 +492,71 @@ MODULE_VERSION(DRV_VERSION); static int adma_enabled = 1; +static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio, + unsigned int port_no) +{ + mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE; + return mmio; +} + +static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap) +{ + return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no); +} + +static inline void __iomem *nv_adma_gen_block(struct ata_port *ap) +{ + return (ap->host->mmio_base + NV_ADMA_GEN); +} + +static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap) +{ + return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no)); +} + +static void nv_adma_register_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) + return; + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags |= NV_ADMA_PORT_REGISTER_MODE; +} + +static void nv_adma_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) + return; + + WARN_ON(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE; +} + static int nv_adma_slave_config(struct scsi_device *sdev) { struct ata_port *ap = ata_shost_to_port(sdev->host); + struct nv_adma_port_priv *pp = ap->private_data; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); u64 bounce_limit; unsigned long segment_boundary; unsigned short sg_tablesize; int rc; + int adma_enable; + u32 current_reg, new_reg, config_mask; rc = ata_scsi_slave_config(sdev); @@ -516,13 +577,40 @@ static int nv_adma_slave_config(struct scsi_device *sdev) /* Subtract 1 since an extra entry may be needed for padding, see libata-scsi.c */ sg_tablesize = LIBATA_MAX_PRD - 1; + + /* Since the legacy DMA engine is in use, we need to disable ADMA + on the port. */ + adma_enable = 0; + nv_adma_register_mode(ap); } else { bounce_limit = *ap->dev->dma_mask; segment_boundary = NV_ADMA_DMA_BOUNDARY; sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; + adma_enable = 1; } - + + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, ¤t_reg); + + if(ap->port_no == 1) + config_mask = NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN; + else + config_mask = NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN; + + if(adma_enable) { + new_reg = current_reg | config_mask; + pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE; + } + else { + new_reg = current_reg & ~config_mask; + pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE; + } + + if(current_reg != new_reg) + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg); + blk_queue_bounce_limit(sdev->request_queue, bounce_limit); blk_queue_segment_boundary(sdev->request_queue, segment_boundary); blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); @@ -532,7 +620,13 @@ static int nv_adma_slave_config(struct scsi_device *sdev) return rc; } -static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb) +static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); +} + +static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb) { unsigned int idx = 0; @@ -563,33 +657,11 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb) return idx; } -static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio, - unsigned int port_no) -{ - mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE; - return mmio; -} - -static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap) -{ - return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no); -} - -static inline void __iomem *nv_adma_gen_block(struct ata_port *ap) -{ - return (ap->host->mmio_base + NV_ADMA_GEN); -} - -static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap) -{ - return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no)); -} - static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) { struct nv_adma_port_priv *pp = ap->private_data; int complete = 0, have_err = 0; - u16 flags = pp->cpb[cpb_num].resp_flags; + u8 flags = pp->cpb[cpb_num].resp_flags; VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); @@ -634,15 +706,48 @@ static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) } } +static int nv_host_intr(struct ata_port *ap, u8 irq_stat) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + int handled; + + /* freeze if hotplugged */ + if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { + ata_port_freeze(ap); + return 1; + } + + /* bail out if not our interrupt */ + if (!(irq_stat & NV_INT_DEV)) + return 0; + + /* DEV interrupt w/ no active qc? */ + if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { + ata_check_status(ap); + return 1; + } + + /* handle interrupt */ + handled = ata_host_intr(ap, qc); + if (unlikely(!handled)) { + /* spurious, clear it */ + ata_check_status(ap); + } + + return 1; +} + static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; int i, handled = 0; + u32 notifier_clears[2]; spin_lock(&host->lock); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + notifier_clears[i] = 0; if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { struct nv_adma_port_priv *pp = ap->private_data; @@ -654,30 +759,18 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) /* if in ATA register mode, use standard ata interrupt handler */ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { - struct ata_queued_cmd *qc; - VPRINTK("in ATA register mode\n"); - qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) - handled += ata_host_intr(ap, qc); - else { - /* No request pending? Clear interrupt status - anyway, in case there's one pending. */ - ap->ops->check_status(ap); - handled++; - } + u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) + >> (NV_INT_PORT_SHIFT * i); + handled += nv_host_intr(ap, irq_stat); continue; } notifier = readl(mmio + NV_ADMA_NOTIFIER); notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + notifier_clears[i] = notifier | notifier_error; gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); - /* Seems necessary to clear notifiers even when they were 0. - Otherwise we seem to stop receiving further interrupts. - Unsure why. */ - writel(notifier | notifier_error, nv_adma_notifier_clear_block(ap)); - if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier && !notifier_error) /* Nothing to do */ @@ -730,6 +823,15 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) handled++; /* irq handled if we got here */ } } + + if(notifier_clears[0] || notifier_clears[1]) { + /* Note: Both notifier clear registers must be written + if either is set, even if one is zero, according to NVIDIA. */ + writel(notifier_clears[0], + nv_adma_notifier_clear_block(host->ports[0])); + writel(notifier_clears[1], + nv_adma_notifier_clear_block(host->ports[1])); + } spin_unlock(&host->lock); @@ -742,6 +844,7 @@ static void nv_adma_irq_clear(struct ata_port *ap) u16 status = readw(mmio + NV_ADMA_STAT); u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; /* clear ADMA status */ writew(status, mmio + NV_ADMA_STAT); @@ -749,92 +852,76 @@ static void nv_adma_irq_clear(struct ata_port *ap) nv_adma_notifier_clear_block(ap)); /** clear legacy status */ - ap->flags &= ~ATA_FLAG_MMIO; - ata_bmdma_irq_clear(ap); - ap->flags |= ATA_FLAG_MMIO; + outb(inb(dma_stat_addr), dma_stat_addr); } static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) { - struct nv_adma_port_priv *pp = qc->ap->private_data; + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + struct nv_adma_port_priv *pp = ap->private_data; + u8 dmactl; - if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { WARN_ON(1); return; } - qc->ap->flags &= ~ATA_FLAG_MMIO; - ata_bmdma_setup(qc); - qc->ap->flags |= ATA_FLAG_MMIO; + /* load PRD table addr. */ + outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + + outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + + /* issue r/w command */ + ata_exec_command(ap, &qc->tf); } static void nv_adma_bmdma_start(struct ata_queued_cmd *qc) { - struct nv_adma_port_priv *pp = qc->ap->private_data; + struct ata_port *ap = qc->ap; + struct nv_adma_port_priv *pp = ap->private_data; + u8 dmactl; - if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { WARN_ON(1); return; } - qc->ap->flags &= ~ATA_FLAG_MMIO; - ata_bmdma_start(qc); - qc->ap->flags |= ATA_FLAG_MMIO; + /* start host DMA transaction */ + dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + outb(dmactl | ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) { - struct nv_adma_port_priv *pp = qc->ap->private_data; - - if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) - return; - - qc->ap->flags &= ~ATA_FLAG_MMIO; - ata_bmdma_stop(qc); - qc->ap->flags |= ATA_FLAG_MMIO; -} - -static u8 nv_adma_bmdma_status(struct ata_port *ap) -{ - u8 status; - struct nv_adma_port_priv *pp = ap->private_data; - - WARN_ON(pp->flags & NV_ADMA_PORT_REGISTER_MODE); - - ap->flags &= ~ATA_FLAG_MMIO; - status = ata_bmdma_status(ap); - ap->flags |= ATA_FLAG_MMIO; - return status; -} - -static void nv_adma_register_mode(struct ata_port *ap) -{ - void __iomem *mmio = nv_adma_ctl_block(ap); + struct ata_port *ap = qc->ap; struct nv_adma_port_priv *pp = ap->private_data; - u16 tmp; - if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) return; - tmp = readw(mmio + NV_ADMA_CTL); - writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + /* clear start/stop bit */ + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - pp->flags |= NV_ADMA_PORT_REGISTER_MODE; + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ } -static void nv_adma_mode(struct ata_port *ap) +static u8 nv_adma_bmdma_status(struct ata_port *ap) { - void __iomem *mmio = nv_adma_ctl_block(ap); struct nv_adma_port_priv *pp = ap->private_data; - u16 tmp; - - if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) - return; - tmp = readw(mmio + NV_ADMA_CTL); - writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)); - pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE; + return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } static int nv_adma_port_start(struct ata_port *ap) @@ -997,7 +1084,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, int idx, struct nv_adma_prd *aprd) { - u32 flags; + u8 flags; memset(aprd, 0, sizeof(struct nv_adma_prd)); @@ -1011,7 +1098,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, aprd->addr = cpu_to_le64(((u64)sg_dma_address(sg))); aprd->len = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */ - aprd->flags = cpu_to_le32(flags); + aprd->flags = flags; } static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) @@ -1045,7 +1132,8 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc) VPRINTK("qc->flags = 0x%lx\n", qc->flags); if (!(qc->flags & ATA_QCFLAG_DMAMAP) || - qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { + nv_adma_register_mode(qc->ap); ata_qc_prep(qc); return; } @@ -1072,12 +1160,13 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc) static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) { + struct nv_adma_port_priv *pp = qc->ap->private_data; void __iomem *mmio = nv_adma_ctl_block(qc->ap); VPRINTK("ENTER\n"); if (!(qc->flags & ATA_QCFLAG_DMAMAP) || - qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { /* use ATA register mode */ VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags); nv_adma_register_mode(qc->ap); @@ -1128,37 +1217,6 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) return IRQ_RETVAL(handled); } -static int nv_host_intr(struct ata_port *ap, u8 irq_stat) -{ - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); - int handled; - - /* freeze if hotplugged */ - if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { - ata_port_freeze(ap); - return 1; - } - - /* bail out if not our interrupt */ - if (!(irq_stat & NV_INT_DEV)) - return 0; - - /* DEV interrupt w/ no active qc? */ - if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { - ata_check_status(ap); - return 1; - } - - /* handle interrupt */ - handled = ata_host_intr(ap, qc); - if (unlikely(!handled)) { - /* spurious, clear it */ - ata_check_status(ap); - } - - return 1; -} - static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat) { int i, handled = 0; -- cgit v1.2.3 From 664e8503fee2f299d0f96eaab0f5f8fae8fad325 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Nov 2006 16:05:34 +0900 Subject: [PATCH] libata: print cdb[0] in failed qc report Print cdb[0] in failed qc report. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 3771eb83875f..5aa7f0907e83 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1452,14 +1452,15 @@ static void ata_eh_report(struct ata_port *ap) ata_dev_printk(qc->dev, KERN_ERR, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " - "tag %d data %u %s\n " + "tag %d cdb 0x%x data %u %s\n " "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "Emask 0x%x (%s)\n", cmd->command, cmd->feature, cmd->nsect, cmd->lbal, cmd->lbam, cmd->lbah, cmd->hob_feature, cmd->hob_nsect, cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, - cmd->device, qc->tag, nbytes, dma_str[qc->dma_dir], + cmd->device, qc->tag, qc->cdb[0], nbytes, + dma_str[qc->dma_dir], res->command, res->feature, res->nsect, res->lbal, res->lbam, res->lbah, res->hob_feature, res->hob_nsect, -- cgit v1.2.3 From c972b60bf167a3d2c3da23df2af1eac93229e7cc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 29 Nov 2006 12:10:46 +0900 Subject: [PATCH] libata: add missing sht->slave_destroy Add missing sht->slave_destroy. Most drivers received this fix in didn't. Fix those four drives. Signed-off-by: Tejun Heo --- drivers/ata/pata_ixp4xx_cf.c | 1 + drivers/ata/pata_marvell.c | 1 + drivers/ata/pata_platform.c | 1 + drivers/ata/pata_winbond.c | 1 + 4 files changed, 4 insertions(+) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index d2268bfe6f55..14c6a2daf52e 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -117,6 +117,7 @@ static struct scsi_host_template ixp4xx_sht = { .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 25f7a79a8e25..3f53be4607a0 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -101,6 +101,7 @@ static struct scsi_host_template marvell_sht = { .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, .resume = ata_scsi_device_resume, diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 63d6687f0ba9..5ff74e4ce590 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -78,6 +78,7 @@ static struct scsi_host_template pata_platform_sht = { .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 48941d0757e9..b02ad1d3afed 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -133,6 +133,7 @@ static struct scsi_host_template winbond_sht = { .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; -- cgit v1.2.3 From 2eab80ac0c96fb98267afeb12a4899801564c75b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 29 Nov 2006 12:20:26 +0900 Subject: [PATCH] libata: kill unnecessary sht->max_sectors initializations sht->max_sectors is overrided unconditionally in ->slave_configure. There's no reason to set it to any value. Signed-off-by: Tejun Heo --- drivers/ata/ata_generic.c | 1 - drivers/ata/pata_ali.c | 3 --- drivers/ata/pata_amd.c | 1 - drivers/ata/pata_artop.c | 1 - drivers/ata/pata_atiixp.c | 1 - drivers/ata/pata_cmd64x.c | 1 - drivers/ata/pata_cs5520.c | 1 - drivers/ata/pata_cs5530.c | 1 - drivers/ata/pata_cs5535.c | 1 - drivers/ata/pata_cypress.c | 1 - drivers/ata/pata_efar.c | 1 - drivers/ata/pata_hpt366.c | 1 - drivers/ata/pata_hpt37x.c | 1 - drivers/ata/pata_hpt3x2n.c | 1 - drivers/ata/pata_hpt3x3.c | 1 - drivers/ata/pata_isapnp.c | 1 - drivers/ata/pata_it821x.c | 3 --- drivers/ata/pata_ixp4xx_cf.c | 1 - drivers/ata/pata_jmicron.c | 2 -- drivers/ata/pata_legacy.c | 1 - drivers/ata/pata_marvell.c | 1 - drivers/ata/pata_mpiix.c | 1 - drivers/ata/pata_netcell.c | 2 -- drivers/ata/pata_ns87410.c | 1 - drivers/ata/pata_oldpiix.c | 1 - drivers/ata/pata_opti.c | 1 - drivers/ata/pata_optidma.c | 1 - drivers/ata/pata_pcmcia.c | 1 - drivers/ata/pata_pdc2027x.c | 1 - drivers/ata/pata_pdc202xx_old.c | 1 - drivers/ata/pata_platform.c | 1 - drivers/ata/pata_qdi.c | 1 - drivers/ata/pata_radisys.c | 1 - drivers/ata/pata_rz1000.c | 1 - drivers/ata/pata_sc1200.c | 1 - drivers/ata/pata_serverworks.c | 1 - drivers/ata/pata_sil680.c | 1 - drivers/ata/pata_sis.c | 1 - drivers/ata/pata_sl82c105.c | 1 - drivers/ata/pata_triflex.c | 1 - drivers/ata/pata_via.c | 1 - drivers/ata/pata_winbond.c | 1 - drivers/ata/sata_nv.c | 1 - 43 files changed, 49 deletions(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index c7e8f033125d..908751d27e76 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -109,7 +109,6 @@ static struct scsi_host_template generic_sht = { .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, diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index ae6d573574cd..d25563794c8d 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -337,9 +337,6 @@ static struct scsi_host_template ali_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* Keep LBA28 counts so large I/O's don't turn LBA48 and PIO - with older controllers. Not locked so will grow on C5 or later */ - .max_sectors = 255, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index d9571206e580..a6b330089f22 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -326,7 +326,6 @@ static struct scsi_host_template amd_sht = { .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, diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 2cd30761ca1f..37bc1323bda7 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -307,7 +307,6 @@ static struct scsi_host_template artop_sht = { .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, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 7d9e391b0d18..6f6672c55131 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -209,7 +209,6 @@ static struct scsi_host_template atiixp_sht = { .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, diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 3376f3f4bad9..15841a563694 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -268,7 +268,6 @@ static struct scsi_host_template cmd64x_sht = { .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, diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index f839c0304b3a..9f165a8e032d 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -159,7 +159,6 @@ static struct scsi_host_template cs5520_sht = { .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, diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 265012b16bbb..1c628014dae6 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -173,7 +173,6 @@ static struct scsi_host_template cs5530_sht = { .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, diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 38c00f628761..73b9b5453a3c 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -177,7 +177,6 @@ static struct scsi_host_template cs5535_sht = { .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, diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 6352bc7df603..e2a95699bae7 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = { .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, diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 56589834483d..edf8a63f50af 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -226,7 +226,6 @@ static struct scsi_host_template efar_sht = { .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, diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 25d3cd7e74f1..2663599a7c02 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -330,7 +330,6 @@ static struct scsi_host_template hpt36x_sht = { .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, diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 1eeb16f0fb02..47082df7199e 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -768,7 +768,6 @@ static struct scsi_host_template hpt37x_sht = { .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, diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 47d7664e9eee..f6817b4093a4 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -334,7 +334,6 @@ static struct scsi_host_template hpt3x2n_sht = { .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, diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index e9fb029f28b7..5f1d385eb592 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -111,7 +111,6 @@ static struct scsi_host_template hpt3x3_sht = { .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, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 40ca2b82b7fc..a97d55ae95c9 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -27,7 +27,6 @@ static struct scsi_host_template isapnp_sht = { .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, diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index d57ac741cc08..0b56ff3d1cfe 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -666,9 +666,6 @@ static struct scsi_host_template it821x_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* 255 sectors to begin with. This is locked in smart mode but not - in pass through */ - .max_sectors = 255, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 14c6a2daf52e..cb8924109f59 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -110,7 +110,6 @@ static struct scsi_host_template ixp4xx_sht = { .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, diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index c9f0a543b27b..2d661cb4df3c 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -128,8 +128,6 @@ static struct scsi_host_template jmicron_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* Special handling needed if you have sector or LBA48 limits */ - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index b39078b2a47b..c7d1738e4e69 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -128,7 +128,6 @@ static struct scsi_host_template legacy_sht = { .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, diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 3f53be4607a0..1c810ea00253 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -94,7 +94,6 @@ static struct scsi_host_template marvell_sht = { .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, diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 752a7418ed51..4ccca938675e 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -159,7 +159,6 @@ static struct scsi_host_template mpiix_sht = { .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, diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 956616789ba1..cf7fe037471c 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -54,8 +54,6 @@ static struct scsi_host_template netcell_sht = { .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, - /* Special handling needed if you have sector or LBA48 limits */ - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 428e6b511a2f..c3032eb9010d 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -149,7 +149,6 @@ static struct scsi_host_template ns87410_sht = { .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, diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 1283fb71bd5d..10ac3cc10181 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -224,7 +224,6 @@ static struct scsi_host_template oldpiix_sht = { .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, diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 66f561db2ab1..c2988b0aa8ea 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -171,7 +171,6 @@ static struct scsi_host_template opti_sht = { .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, diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index d898e42f99e8..80d111c569dc 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -352,7 +352,6 @@ static struct scsi_host_template optidma_sht = { .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, diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 999922de476e..4ca6fa5dcb42 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -62,7 +62,6 @@ static struct scsi_host_template pcmcia_sht = { .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, diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index ef854299989c..76dd1c935dbd 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -134,7 +134,6 @@ static struct scsi_host_template pdc2027x_sht = { .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, diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 81a134cca3cd..ad691b9e7743 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -262,7 +262,6 @@ static struct scsi_host_template pdc202xx_sht = { .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, diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 5ff74e4ce590..443b1d85c6c4 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -71,7 +71,6 @@ static struct scsi_host_template pata_platform_sht = { .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, diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 314938dea1fc..36f621abc390 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -157,7 +157,6 @@ static struct scsi_host_template qdi_sht = { .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, diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 5fe7ffce5284..065541d034ad 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -220,7 +220,6 @@ static struct scsi_host_template radisys_sht = { .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, diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 21567aba82d2..3677c642c9f9 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -83,7 +83,6 @@ static struct scsi_host_template rz1000_sht = { .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, diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 0c5393a73970..a3b35bc50394 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -186,7 +186,6 @@ static struct scsi_host_template sc1200_sht = { .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, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 0fa803e6399c..f02b6a3b0f10 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = { .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, diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 5d3b42ec8e47..32cf0bfa8921 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -218,7 +218,6 @@ static struct scsi_host_template sil680_sht = { .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, diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 695e571540cc..916cedb3d755 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -538,7 +538,6 @@ static struct scsi_host_template sis_sht = { .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, diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index dc1cfc6d805b..e94f515ef54b 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -230,7 +230,6 @@ static struct scsi_host_template sl82c105_sht = { .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, diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index ece9cb7c2f4d..a142971f1307 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -185,7 +185,6 @@ static struct scsi_host_template triflex_sht = { .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, diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 489bd5796e73..ee93dd0169be 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -288,7 +288,6 @@ static struct scsi_host_template via_sht = { .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, diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index b02ad1d3afed..3ea345cde52e 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -126,7 +126,6 @@ static struct scsi_host_template winbond_sht = { .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, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 27d2225c9083..0d316eb3c214 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -321,7 +321,6 @@ static struct scsi_host_template nv_adma_sht = { .can_queue = NV_ADMA_MAX_CPBS, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN, - .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, -- cgit v1.2.3 From 582982e6991d6718ddadf8751072b50a850dde48 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Nov 2006 12:05:11 +0900 Subject: [PATCH] libata: remove unused HSM_ST_UNKNOWN HSM_ST_UNKNOWN is not used anywhere. Its value is zero and supposed to serve sanity check purpose but HSM_ST_IDLE is used for that purpose. This unused state causes confusion. After a port is initialized but before the first command is executed, the idle hsm state is UNKNOWN. However, once a command has completed, the idle hsm state is IDLE. This defeats sanity check in ata_pio_task() for the first command. This patch removes HSM_ST_UNKNOWN and consequently make HSM_ST_IDLE the default state. Signed-off-by: Tejun Heo --- include/linux/libata.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 9080789913f7..6013211ac7de 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -318,7 +318,6 @@ enum { }; enum hsm_task_states { - HSM_ST_UNKNOWN, /* state unknown */ HSM_ST_IDLE, /* no command on going */ HSM_ST, /* (waiting the device to) transfer data */ HSM_ST_LAST, /* (waiting the device to) complete command */ -- cgit v1.2.3 From 8070217d301d0ceab7d0c255d7b9d796256d37e7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Nov 2006 16:22:27 +0900 Subject: [PATCH] libata: set IRQF_SHARED for legacy PCI IDE IRQs There are machines out there which share legacy PCI IDE IRQs w/ other devices. libata SFF interrupt/HSM code is ready for shared IRQ and has been setting IRQF_SHARED for devices in native PCI mode. Device in legacy mode is still a PCI device and thus supposedly uses active-low level triggered IRQ. Machines with such setup should be quite rare and w/o this flag libata is likely to fail loading and render the system unuseable. Also, IDE driver has been setting IRQF_SHARED for devices in legacy mode for a looooong time. Signed-off-by: Tejun Heo --- drivers/ata/libata-sff.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 37471d3c1c28..a57de4a5aa45 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -906,6 +906,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, return NULL; probe_ent->n_ports = 2; + probe_ent->irq_flags = IRQF_SHARED; if (port_mask & ATA_PORT_PRIMARY) { probe_ent->irq = ATA_PRIMARY_IRQ; -- cgit v1.2.3 From 3d3cca37559e3ab2b574eda11ed5207ccdb8980a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 16 Nov 2006 10:50:50 +0900 Subject: [PATCH] libata: implement ATA_FLAG_SETXFER_POLLING and use it in pata_via, take #2 This patch implements ATA_FLAG_SETXFER_POLLING and use in pata_via. If this flag is set, transfer mode setting performed by polling not by interrupt. This should help those controllers which raise interrupt before the command is actually complete on SETXFER. Rationale for this approach. * uses existing facility and relatively simple * no busy sleep in the interrupt handler * updating drivers is easy While at it, kill now unused flag ATA_FLAG_SRST in pata_via. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 8 ++++++++ drivers/ata/pata_via.c | 12 ++++++------ include/linux/libata.h | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3fd7c7932707..b35fdcb104ec 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4821,6 +4821,14 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) } } + /* Some controllers show flaky interrupt behavior after + * setting xfer mode. Use polling instead. + */ + if (unlikely(qc->tf.command == ATA_CMD_SET_FEATURES && + qc->tf.feature == SETFEATURES_XFER) && + (ap->flags & ATA_FLAG_SETXFER_POLLING)) + qc->tf.flags |= ATA_TFLAG_POLLING; + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index ee93dd0169be..a9077b617b8d 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -418,7 +418,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Early VIA without UDMA support */ static struct ata_port_info via_mwdma_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops @@ -426,7 +426,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Ditto with IRQ masking required */ static struct ata_port_info via_mwdma_info_borked = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops_noirq, @@ -434,7 +434,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 33 devices (and borked 66) */ static struct ata_port_info via_udma33_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7, @@ -443,7 +443,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 66 devices */ static struct ata_port_info via_udma66_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x1f, @@ -452,7 +452,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 100 devices */ static struct ata_port_info via_udma100_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x3f, @@ -461,7 +461,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* UDMA133 with bad AST (All current 133) */ static struct ata_port_info via_udma133_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7f, /* FIXME: should check north bridge */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 6013211ac7de..8b57b6a806cc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -178,6 +178,7 @@ enum { ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by * polling IDENTIFY */ + ATA_FLAG_SETXFER_POLLING= (1 << 15), /* use polling for SETXFER */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be -- cgit v1.2.3 From 6a36261e63770ab61422550b774fe949ccca5fa9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Nov 2006 11:15:47 +0900 Subject: [PATCH] libata: fix READ CAPACITY simulation * READ CAPACITY (16) implementation fixed. Result was shifted by two bytes. Carlos Pardo spotted this problem and submitted preliminary patch. Capacity => 2TB is handled correctly now. (verifid w/ fake capacity) * Use dev->n_sectors instead of re-reading directly from ID data. * Define and use ATA_SCSI_RBUF_SET() which considers rbuf length. This should be done for all simulation functions. Userland can issue any simulated command with arbitrary buffer length. Signed-off-by: Tejun Heo Cc: Carlos Pardo --- drivers/ata/libata-scsi.c | 81 +++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 56d7e1ea9d72..7ff1adfc729c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1697,6 +1697,22 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, args->done(cmd); } +/** + * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer + * @idx: byte index into SCSI response buffer + * @val: value to set + * + * To be used by SCSI command simulator functions. This macros + * expects two local variables, u8 *rbuf and unsigned int buflen, + * are in scope. + * + * LOCKING: + * None. + */ +#define ATA_SCSI_RBUF_SET(idx, val) do { \ + if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \ + } while (0) + /** * ata_scsiop_inq_std - Simulate INQUIRY command * @args: device IDENTIFY data / SCSI command of interest. @@ -2156,67 +2172,42 @@ saving_not_supp: * Simulate READ CAPACITY commands. * * LOCKING: - * spin_lock_irqsave(host lock) + * None. */ - unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { - u64 n_sectors; - u32 tmp; + u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */ VPRINTK("ENTER\n"); - if (ata_id_has_lba(args->id)) { - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); - } else { - /* CHS default translation */ - n_sectors = args->id[1] * args->id[3] * args->id[6]; - - if (ata_id_current_chs_valid(args->id)) - /* CHS current translation */ - n_sectors = ata_id_u32(args->id, 57); - } - - n_sectors--; /* ATA TotalUserSectors - 1 */ - if (args->cmd->cmnd[0] == READ_CAPACITY) { - if( n_sectors >= 0xffffffffULL ) - tmp = 0xffffffff ; /* Return max count on overflow */ - else - tmp = n_sectors ; + if (last_lba >= 0xffffffffULL) + last_lba = 0xffffffff; /* sector count, 32-bit */ - rbuf[0] = tmp >> (8 * 3); - rbuf[1] = tmp >> (8 * 2); - rbuf[2] = tmp >> (8 * 1); - rbuf[3] = tmp; + ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3)); + ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2)); + ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1)); + ATA_SCSI_RBUF_SET(3, last_lba); /* sector size */ - tmp = ATA_SECT_SIZE; - rbuf[6] = tmp >> 8; - rbuf[7] = tmp; - + ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); + ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE); } else { /* sector count, 64-bit */ - tmp = n_sectors >> (8 * 4); - rbuf[2] = tmp >> (8 * 3); - rbuf[3] = tmp >> (8 * 2); - rbuf[4] = tmp >> (8 * 1); - rbuf[5] = tmp; - tmp = n_sectors; - rbuf[6] = tmp >> (8 * 3); - rbuf[7] = tmp >> (8 * 2); - rbuf[8] = tmp >> (8 * 1); - rbuf[9] = tmp; + ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); + ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6)); + ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5)); + ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4)); + ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3)); + ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2)); + ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1)); + ATA_SCSI_RBUF_SET(7, last_lba); /* sector size */ - tmp = ATA_SECT_SIZE; - rbuf[12] = tmp >> 8; - rbuf[13] = tmp; + ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); + ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE); } return 0; -- cgit v1.2.3 From a569a30d301e4dbc0ad67a211292edece2da1146 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Nov 2006 10:40:51 +0900 Subject: [PATCH] libata: don't request sense if the port is frozen If EH command is issued to a frozen port, it fails with AC_ERR_SYSTEM. libata used to request sense even when the port is frozen needlessly adding AC_ERR_SYSTEM to err_mask. Don't do it. Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5aa7f0907e83..2aad7b79d6dd 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1136,19 +1136,21 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, break; case ATA_DEV_ATAPI: - tmp = atapi_eh_request_sense(qc->dev, - qc->scsicmd->sense_buffer); - if (!tmp) { - /* ATA_QCFLAG_SENSE_VALID is used to tell - * atapi_qc_complete() that sense data is - * already valid. - * - * TODO: interpret sense data and set - * appropriate err_mask. - */ - qc->flags |= ATA_QCFLAG_SENSE_VALID; - } else - qc->err_mask |= tmp; + if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) { + tmp = atapi_eh_request_sense(qc->dev, + qc->scsicmd->sense_buffer); + if (!tmp) { + /* ATA_QCFLAG_SENSE_VALID is used to + * tell atapi_qc_complete() that sense + * data is already valid. + * + * TODO: interpret sense data and set + * appropriate err_mask. + */ + qc->flags |= ATA_QCFLAG_SENSE_VALID; + } else + qc->err_mask |= tmp; + } } if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) -- cgit v1.2.3 From f84e7e41e1b88547218a3c3b1eb528005e9afdb4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 22 Nov 2006 11:21:31 +0900 Subject: [PATCH] libata: make sure sdev doesn't go away while rescanning ata_scsi_dev_rescan() doesn't synchronize against SCSI device detach and the target sdev might go away in the middle. Fix it. Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7ff1adfc729c..d250858d201c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3181,15 +3181,27 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, void ata_scsi_dev_rescan(void *data) { struct ata_port *ap = data; - struct ata_device *dev; + unsigned long flags; unsigned int i; + spin_lock_irqsave(ap->lock, flags); + for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + struct ata_device *dev = &ap->device[i]; + struct scsi_device *sdev = dev->sdev; - if (ata_dev_enabled(dev) && dev->sdev) - scsi_rescan_device(&(dev->sdev->sdev_gendev)); + if (!ata_dev_enabled(dev) || !sdev) + continue; + if (scsi_device_get(sdev)) + continue; + + spin_unlock_irqrestore(ap->lock, flags); + scsi_rescan_device(&(sdev->sdev_gendev)); + scsi_device_put(sdev); + spin_lock_irqsave(ap->lock, flags); } + + spin_unlock_irqrestore(ap->lock, flags); } /** -- cgit v1.2.3 From ea54763f8a7c51b9f8fcb14431812ae63fcbaf96 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Nov 2006 12:06:21 +0900 Subject: [PATCH] libata: move BMDMA host status recording from EH to interrupt handler For certain errors, interrupt handler alter BMDMA host status before entering EH (clears active and intr). Thus altered BMDMA host status value is recorded by BMDMA EH and reported to user. Move BMDMA host status recording from EH to interrupt handler. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 6 ++++++ drivers/ata/libata-sff.c | 3 --- drivers/ata/sata_sil.c | 5 +++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b35fdcb104ec..7f53ea725bce 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4937,6 +4937,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { + struct ata_eh_info *ehi = &ap->eh_info; u8 status, host_stat = 0; VPRINTK("ata%u: protocol %d task_state %d\n", @@ -4997,6 +4998,11 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ap->ops->irq_clear(ap); ata_hsm_move(ap, qc, status, 0); + + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + return 1; /* irq handled */ idle_irq: diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index a57de4a5aa45..95ff186f0ccd 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -743,7 +743,6 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; struct ata_queued_cmd *qc; unsigned long flags; int thaw = 0; @@ -763,8 +762,6 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, host_stat = ap->ops->bmdma_status(ap); - ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); - /* BMDMA controllers indicate host bus error by * setting DMA_ERR bit and timing out. As it wasn't * really a timeout event, adjust error mask and diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index f844a1faba18..7808d0369d91 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -356,6 +356,7 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static void sil_host_intr(struct ata_port *ap, u32 bmdma2) { + struct ata_eh_info *ehi = &ap->eh_info; struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); u8 status; @@ -428,6 +429,10 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) /* kick HSM in the ass */ ata_hsm_move(ap, qc, status, 0); + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2); + return; err_hsm: -- cgit v1.2.3 From 0f0a3ad3741fd93461fcfb85dc577103c58d9be8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Nov 2006 12:24:22 +0900 Subject: [PATCH] libata: make sure IRQ is cleared after ata_bmdma_freeze() Now that BMDMA status is recorded in irq handler. ata_bmdma_freeze() is free to manipulate host status. Under certain circumstances, some controllers (ICH7 in enhanced mode w/ IRQ shared) raise IRQ when CTL register is written to and ATA_NIEN doesn't mask it. This patch makes ata_bmdma_freeze() clear all pending IRQs after freezing a port. This change makes explicit clearing in ata_device_add() unnecessary and thus kills it. The removed code was SFF-specific and was in the wrong place. Note that ->freeze() handler is always called under ap->lock held and irq disabled. Even if CTL manipulation causes stuck IRQ, it's cleared immediately. This should be safe (enough) even in SMP environment. More correct solution is to mask the IRQ from IRQ controller but that would be an overkill. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 5 ++--- drivers/ata/libata-sff.c | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f53ea725bce..47c70392ec4d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5681,9 +5681,8 @@ int ata_device_add(const struct ata_probe_ent *ent) ap->ioaddr.bmdma_addr, irq_line); - ata_chk_status(ap); - host->ops->irq_clear(ap); - ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */ + /* freeze port before requesting IRQ */ + ata_eh_freeze_port(ap); } /* obtain irq, that may be shared between channels */ diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 95ff186f0ccd..10ee22ae5c15 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -700,6 +700,14 @@ void ata_bmdma_freeze(struct ata_port *ap) writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); + + /* Under certain circumstances, some controllers raise IRQ on + * ATA_NIEN manipulation. Also, many controllers fail to mask + * previously pending IRQ on ATA_NIEN assertion. Clear it. + */ + ata_chk_status(ap); + + ap->ops->irq_clear(ap); } /** -- cgit v1.2.3 From 2432697ba0ce312d60be5009ffe1fa054a761bb9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:47:09 +0900 Subject: [PATCH] libata: implement ata_exec_internal_sg() Sg'ify ata_exec_internal() and call it ata_exec_internal_sg(). Wrapper function around ata_exec_internal_sg() is implemented to provide ata_exec_internal() interface. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 49 ++++++++++++++++++++++++++++++++++++++++------- drivers/ata/libata.h | 4 ++++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 47c70392ec4d..0a5103b707c6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1042,13 +1042,13 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) } /** - * ata_exec_internal - execute libata internal command + * ata_exec_internal_sg - execute libata internal command * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command * @dma_dir: Data tranfer direction of the command - * @buf: Data buffer of the command - * @buflen: Length of data buffer + * @sg: sg list for the data buffer of the command + * @n_elem: Number of sg entries * * Executes libata internal command with timeout. @tf contains * command on entry and result on return. Timeout and error @@ -1062,9 +1062,10 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) * RETURNS: * Zero on success, AC_ERR_* mask on failure */ -unsigned ata_exec_internal(struct ata_device *dev, - struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen) +unsigned ata_exec_internal_sg(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, struct scatterlist *sg, + unsigned int n_elem) { struct ata_port *ap = dev->ap; u8 command = tf->command; @@ -1120,7 +1121,12 @@ unsigned ata_exec_internal(struct ata_device *dev, qc->flags |= ATA_QCFLAG_RESULT_TF; qc->dma_dir = dma_dir; if (dma_dir != DMA_NONE) { - ata_sg_init_one(qc, buf, buflen); + unsigned int i, buflen = 0; + + for (i = 0; i < n_elem; i++) + buflen += sg[i].length; + + ata_sg_init(qc, sg, n_elem); qc->nsect = buflen / ATA_SECT_SIZE; } @@ -1203,6 +1209,35 @@ unsigned ata_exec_internal(struct ata_device *dev, return err_mask; } +/** + * ata_exec_internal_sg - execute libata internal command + * @dev: Device to which the command is sent + * @tf: Taskfile registers for the command and the result + * @cdb: CDB for packet command + * @dma_dir: Data tranfer direction of the command + * @buf: Data buffer of the command + * @buflen: Length of data buffer + * + * Wrapper around ata_exec_internal_sg() which takes simple + * buffer instead of sg list. + * + * LOCKING: + * None. Should be called with kernel context, might sleep. + * + * RETURNS: + * Zero on success, AC_ERR_* mask on failure + */ +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, void *buf, unsigned int buflen) +{ + struct scatterlist sg; + + sg_init_one(&sg, buf, buflen); + + return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, 1); +} + /** * ata_do_simple_cmd - execute simple internal command * @dev: Device to which the command is sent diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 2d532da8c398..ca6f36c13115 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -58,6 +58,10 @@ extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen); +extern unsigned ata_exec_internal_sg(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, struct scatterlist *sg, + unsigned int n_elem); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); -- cgit v1.2.3 From bd056d7eeb55d696556ee4f5ee2acb67b2d16df4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:47:10 +0900 Subject: [PATCH] libata: separate out rw ATA taskfile building into ata_build_rw_tf() Separate out rw ATA taskfile building from ata_scsi_rw_xlat() into ata_build_rw_tf(). This will be used to improve media error handling. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 133 ++++++++++++++++++++++++++++++++++++++++++++-- drivers/ata/libata-scsi.c | 120 +++++------------------------------------ drivers/ata/libata.h | 4 +- 3 files changed, 145 insertions(+), 112 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0a5103b707c6..4ac53ef0e4b0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -199,7 +199,8 @@ static const u8 ata_rw_cmds[] = { /** * ata_rwcmd_protocol - set taskfile r/w commands and protocol - * @qc: command to examine and configure + * @tf: command to examine and configure + * @dev: device tf belongs to * * Examine the device configuration and tf->flags to calculate * the proper read/write commands and protocol to use. @@ -207,10 +208,8 @@ static const u8 ata_rw_cmds[] = { * LOCKING: * caller. */ -int ata_rwcmd_protocol(struct ata_queued_cmd *qc) +static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) { - struct ata_taskfile *tf = &qc->tf; - struct ata_device *dev = qc->dev; u8 cmd; int index, fua, lba48, write; @@ -222,7 +221,7 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc) if (dev->flags & ATA_DFLAG_PIO) { tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; - } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) { + } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) { /* Unable to use DMA due to host limitation */ tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; @@ -282,6 +281,130 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) return block; } +/** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile + * @dev: ATA device @tf belongs to + * @block: Block address + * @n_block: Number of blocks + * @tf_flags: RW/FUA etc... + * @tag: tag + * + * LOCKING: + * None. + * + * Build ATA taskfile @tf for read/write request described by + * @block, @n_block, @tf_flags and @tag on @dev. + * + * RETURNS: + * + * 0 on success, -ERANGE if the request is too large for @dev, + * -EINVAL if the request is invalid. + */ +int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, + u64 block, u32 n_block, unsigned int tf_flags, + unsigned int tag) +{ + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->flags |= tf_flags; + + if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | + ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { + /* yay, NCQ */ + if (!lba_48_ok(block, n_block)) + return -ERANGE; + + tf->protocol = ATA_PROT_NCQ; + tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + if (tf->flags & ATA_TFLAG_WRITE) + tf->command = ATA_CMD_FPDMA_WRITE; + else + tf->command = ATA_CMD_FPDMA_READ; + + tf->nsect = tag << 3; + tf->hob_feature = (n_block >> 8) & 0xff; + tf->feature = n_block & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device = 1 << 6; + if (tf->flags & ATA_TFLAG_FUA) + tf->device |= 1 << 7; + } else if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; + + if (lba_28_ok(block, n_block)) { + /* use LBA28 */ + tf->device |= (block >> 24) & 0xf; + } else if (lba_48_ok(block, n_block)) { + if (!(dev->flags & ATA_DFLAG_LBA48)) + return -ERANGE; + + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else + /* request too large even for LBA48 */ + return -ERANGE; + + if (unlikely(ata_rwcmd_protocol(tf, dev) < 0)) + return -EINVAL; + + tf->nsect = n_block & 0xff; + + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* The request -may- be too large for CHS addressing. */ + if (!lba_28_ok(block, n_block)) + return -ERANGE; + + if (unlikely(ata_rwcmd_protocol(tf, dev) < 0)) + return -EINVAL; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + return -ERANGE; + + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; + } + + return 0; +} + /** * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask * @pio_mask: pio_mask diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d250858d201c..8eaace94d963 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1265,17 +1265,14 @@ nothing_to_do: static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { - struct ata_taskfile *tf = &qc->tf; - struct ata_device *dev = qc->dev; + unsigned int tf_flags = 0; u64 block; u32 n_block; - - qc->flags |= ATA_QCFLAG_IO; - tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + int rc; if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || scsicmd[0] == WRITE_16) - tf->flags |= ATA_TFLAG_WRITE; + tf_flags |= ATA_TFLAG_WRITE; /* Calculate the SCSI LBA, transfer length and FUA. */ switch (scsicmd[0]) { @@ -1283,7 +1280,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm case WRITE_10: scsi_10_lba_len(scsicmd, &block, &n_block); if (unlikely(scsicmd[1] & (1 << 3))) - tf->flags |= ATA_TFLAG_FUA; + tf_flags |= ATA_TFLAG_FUA; break; case READ_6: case WRITE_6: @@ -1299,7 +1296,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm case WRITE_16: scsi_16_lba_len(scsicmd, &block, &n_block); if (unlikely(scsicmd[1] & (1 << 3))) - tf->flags |= ATA_TFLAG_FUA; + tf_flags |= ATA_TFLAG_FUA; break; default: DPRINTK("no-byte command\n"); @@ -1317,106 +1314,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm */ goto nothing_to_do; - if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | - ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { - /* yay, NCQ */ - if (!lba_48_ok(block, n_block)) - goto out_of_range; - - tf->protocol = ATA_PROT_NCQ; - tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; - - if (tf->flags & ATA_TFLAG_WRITE) - tf->command = ATA_CMD_FPDMA_WRITE; - else - tf->command = ATA_CMD_FPDMA_READ; - - qc->nsect = n_block; - - tf->nsect = qc->tag << 3; - tf->hob_feature = (n_block >> 8) & 0xff; - tf->feature = n_block & 0xff; - - tf->hob_lbah = (block >> 40) & 0xff; - tf->hob_lbam = (block >> 32) & 0xff; - tf->hob_lbal = (block >> 24) & 0xff; - tf->lbah = (block >> 16) & 0xff; - tf->lbam = (block >> 8) & 0xff; - tf->lbal = block & 0xff; - - tf->device = 1 << 6; - if (tf->flags & ATA_TFLAG_FUA) - tf->device |= 1 << 7; - } else if (dev->flags & ATA_DFLAG_LBA) { - tf->flags |= ATA_TFLAG_LBA; - - if (lba_28_ok(block, n_block)) { - /* use LBA28 */ - tf->device |= (block >> 24) & 0xf; - } else if (lba_48_ok(block, n_block)) { - if (!(dev->flags & ATA_DFLAG_LBA48)) - goto out_of_range; - - /* use LBA48 */ - tf->flags |= ATA_TFLAG_LBA48; - - tf->hob_nsect = (n_block >> 8) & 0xff; - - tf->hob_lbah = (block >> 40) & 0xff; - tf->hob_lbam = (block >> 32) & 0xff; - tf->hob_lbal = (block >> 24) & 0xff; - } else - /* request too large even for LBA48 */ - goto out_of_range; - - if (unlikely(ata_rwcmd_protocol(qc) < 0)) - goto invalid_fld; - - qc->nsect = n_block; - tf->nsect = n_block & 0xff; - - tf->lbah = (block >> 16) & 0xff; - tf->lbam = (block >> 8) & 0xff; - tf->lbal = block & 0xff; - - tf->device |= ATA_LBA; - } else { - /* CHS */ - u32 sect, head, cyl, track; - - /* The request -may- be too large for CHS addressing. */ - if (!lba_28_ok(block, n_block)) - goto out_of_range; - - if (unlikely(ata_rwcmd_protocol(qc) < 0)) - goto invalid_fld; - - /* Convert LBA to CHS */ - track = (u32)block / dev->sectors; - cyl = track / dev->heads; - head = track % dev->heads; - sect = (u32)block % dev->sectors + 1; - - DPRINTK("block %u track %u cyl %u head %u sect %u\n", - (u32)block, track, cyl, head, sect); - - /* Check whether the converted CHS can fit. - Cylinder: 0-65535 - Head: 0-15 - Sector: 1-255*/ - if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) - goto out_of_range; - - qc->nsect = n_block; - tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ - tf->lbal = sect; - tf->lbam = cyl; - tf->lbah = cyl >> 8; - tf->device |= head; - } + qc->flags |= ATA_QCFLAG_IO; + qc->nsect = n_block; - return 0; + rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, + qc->tag); + if (likely(rc == 0)) + return 0; + if (rc == -ERANGE) + goto out_of_range; + /* treat all other errors as -EINVAL, fall through */ invalid_fld: ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ca6f36c13115..60576b1237e4 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -51,7 +51,9 @@ extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); -extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); +extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, + u64 block, u32 n_block, unsigned int tf_flags, + unsigned int tag); extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); -- cgit v1.2.3 From 70e6ad0c6d1e6cb9ee3c036a85ca2561eb1fd766 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Nov 2006 22:47:10 +0900 Subject: [PATCH] libata: prepare ata_sg_clean() for invocation from EH Make ata_sg_clean() global and don't allow NCQ for internal commands. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 6 +++--- drivers/ata/libata.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4ac53ef0e4b0..883276388207 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -309,7 +309,8 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, tf->flags |= tf_flags; if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | - ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { + ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ && + likely(tag != ATA_TAG_INTERNAL)) { /* yay, NCQ */ if (!lba_48_ok(block, n_block)) return -ERANGE; @@ -3533,8 +3534,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_sg_clean(struct ata_queued_cmd *qc) +void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg = qc->__sg; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 60576b1237e4..1ff3f59504c9 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -73,6 +73,7 @@ extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); +extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); extern void __ata_qc_complete(struct ata_queued_cmd *qc); -- cgit v1.2.3 From 8e16f941226f15622fbbc416a1f3d8705001a191 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Nov 2006 15:42:36 +0900 Subject: [PATCH] ahci: do not powerdown during initialization ahci_init_controller() calls ahci_deinit_port() to make sure the controller is stopped before initializing the controller. In turn, ahci_deinit_port() invokes ahci_power_down() to power down the port. If the controller supports slumber mode, the link is put into it. Unfortunately, some devices don't implement link powersaving mode properly and show erratic behavior after link is put into slumber mode. For example, HL-DT-ST DVD-RAM GSA-H30N completely locks up on slumber transition and can only be recovered with the *REAL* hard reset - power removal and reapply. Note that this makes the first probing reset different from all others. If the above dvd-ram is hotplugged after ahci is initialized, no problem occurs because ahci is already fully initialized with phy powered up. So, this might also be the reason for other weird AHCI initial probing abnormalities. This patch moves power up/down out of port init/deinit and call them only when needed. Power down is now called only when suspending. As system suspend usually involves powering down 12v for storage devices, this shouldn't cause problem even if the attached device doesn't support slumber mode. However, in partial power management and suspend failure cases, devices might lock up after suspend attempt. I thought about removing transition to slumber mode altogether but ahci spec mandates it before HBA D3 state transition. Blacklisting such devices might be the solution. Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index af3565d1fefe..f36da488a2c1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -612,9 +612,6 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap) static void ahci_init_port(void __iomem *port_mmio, u32 cap, dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) { - /* power up */ - ahci_power_up(port_mmio, cap); - /* enable FIS reception */ ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma); @@ -640,9 +637,6 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) return rc; } - /* put device into slumber mode */ - ahci_power_down(port_mmio, cap); - return 0; } @@ -1321,7 +1315,9 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) int rc; rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); - if (rc) { + if (rc == 0) + ahci_power_down(port_mmio, hpriv->cap); + else { ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); @@ -1337,6 +1333,7 @@ static int ahci_port_resume(struct ata_port *ap) void __iomem *mmio = ap->host->mmio_base; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + ahci_power_up(port_mmio, hpriv->cap); ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); return 0; @@ -1443,6 +1440,9 @@ static int ahci_port_start(struct ata_port *ap) ap->private_data = pp; + /* power up port */ + ahci_power_up(port_mmio, hpriv->cap); + /* initialize port */ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); -- cgit v1.2.3 From 3ac551a6a63dcbc707348772a27bd7090b081524 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 3 Dec 2006 07:57:21 -0500 Subject: [libata] pata_cs5535: fix build Noticed by Tejun and others. Signed-off-by: Jeff Garzik --- drivers/ata/pata_cs5535.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 73b9b5453a3c..e3efec4ffc79 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -269,7 +269,7 @@ static struct pci_driver cs5535_pci_driver = { .name = DRV_NAME, .id_table = cs5535, .probe = cs5535_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, }; -- cgit v1.2.3 From 800b399669ad495ad4361d134df87401ae36f44f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 3 Dec 2006 21:34:13 +0900 Subject: [PATCH] libata: always use polling IDENTIFY libata switched to IRQ-driven IDENTIFY when IRQ-driven PIO was introduced. This has caused a lot of problems including device misdetection and phantom device. ATA_FLAG_DETECT_POLLING was added recently to selectively use polling IDENTIFY on problemetic drivers but many controllers and devices are affected by this problem and trying to adding ATA_FLAG_DETECT_POLLING for each such case is diffcult and not very rewarding. This patch makes libata always use polling IDENTIFY. This is consistent with libata's original behavior and drivers/ide's behavior. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 5 ++--- drivers/ata/libata-core.c | 8 ++------ drivers/ata/libata-eh.c | 3 --- drivers/ata/libata.h | 2 -- include/linux/libata.h | 4 +--- 5 files changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 788a269206e6..a2d84f7cf2bc 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -105,9 +105,8 @@ enum { PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ - PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS | ATA_FLAG_DETECT_POLLING, - PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | - ATA_FLAG_DETECT_POLLING, + PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, + PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, /* combined mode. if set, PATA is channel 0. * if clear, PATA is channel 1. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 883276388207..f8ec3896b793 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1473,16 +1473,12 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, } tf.protocol = ATA_PROT_PIO; - - /* presence detection using polling IDENTIFY? */ - if (flags & ATA_READID_DETECT) - tf.flags |= ATA_TFLAG_POLLING; + tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { - if ((flags & ATA_READID_DETECT) && - (err_mask & AC_ERR_NODEV_HINT)) { + if (err_mask & AC_ERR_NODEV_HINT) { DPRINTK("ata%u.%d: NODEV after polling detection\n", ap->id, dev->devno); return -ENOENT; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2aad7b79d6dd..76a85dfb7307 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1692,9 +1692,6 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - if (ap->flags & ATA_FLAG_DETECT_POLLING) - readid_flags |= ATA_READID_DETECT; - rc = ata_dev_read_id(dev, &dev->class, readid_flags, dev->id); if (rc == 0) { diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 1ff3f59504c9..107b2b565229 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -42,8 +42,6 @@ struct ata_scsi_args { enum { /* flags for ata_dev_read_id() */ ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ - ATA_READID_DETECT = (1 << 1), /* perform presence detection - * using polling IDENTIFY */ }; extern struct workqueue_struct *ata_aux_wq; diff --git a/include/linux/libata.h b/include/linux/libata.h index 8b57b6a806cc..202283b5df96 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -176,9 +176,7 @@ enum { ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), - ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by - * polling IDENTIFY */ - ATA_FLAG_SETXFER_POLLING= (1 << 15), /* use polling for SETXFER */ + ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be -- cgit v1.2.3 From 599b7202c5bf2c7345ea34007379ba241c94a491 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Fri, 1 Dec 2006 10:55:58 +0100 Subject: [PATCH] sata_promise: PHYMODE4 fixup This patch adds code to fix up the PHYMODE4 "align timing" register value on second-generation Promise SATA chips. Failure to correct this value on non-x86 machines makes drive detection prone to failure due to timeouts. (I've observed about 50% detection failure rates on SPARC64.) The HW boots with a bad value in this register, but on x86 machines the Promise BIOS corrects it to the value recommended by the manual, so most people have been unaffected by this issue. After developing the patch I checked Promise's SATAII driver, and discovered that it also corrects PHYMODE4 just like this patch does. This patch depends on the sata_promise SATAII updates patch I sent recently. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik --- drivers/ata/sata_promise.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 8daf5d67dfe2..a2778cf016bc 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -280,6 +280,7 @@ static struct pci_driver pdc_ata_pci_driver = { static int pdc_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; + struct pdc_host_priv *hp = ap->host->private_data; struct pdc_port_priv *pp; int rc; @@ -301,6 +302,16 @@ static int pdc_port_start(struct ata_port *ap) ap->private_data = pp; + /* fix up PHYMODE4 align timing */ + if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) { + void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr; + unsigned int tmp; + + tmp = readl(mmio + 0x014); + tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */ + writel(tmp, mmio + 0x014); + } + return 0; err_out_kfree: -- cgit v1.2.3 From 2c5ff671ca853a1f73ae688bbf5b4f68a476b55d Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 4 Dec 2006 16:33:20 +0000 Subject: [PATCH] trivial piix: swap bogus dot for comma space Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index a2d84f7cf2bc..c7de0bb1591f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -40,7 +40,7 @@ * Documentation * Publically available from Intel web site. Errata documentation * is also publically available. As an aide to anyone hacking on this - * driver the list of errata that are relevant is below.going back to + * driver the list of errata that are relevant is below, going back to * PIIX4. Older device documentation is now a bit tricky to find. * * The chipsets all follow very much the same design. The orginal Triton -- cgit v1.2.3 From 75f609d2a923b8f1db870e0c63ff41c84c145589 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 4 Dec 2006 16:38:25 +0000 Subject: [PATCH] pata_via: VIA 8251 bridged systems are now out and about Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index a9077b617b8d..cc09d47fb927 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -23,6 +23,7 @@ * VIA VT8233c - UDMA100 * VIA VT8235 - UDMA133 * VIA VT8237 - UDMA133 + * VIA VT8251 - UDMA133 * * Most registers remain compatible across chips. Others start reserved * and acquire sensible semantics if set to 1 (eg cable detect). A few @@ -94,6 +95,7 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { + { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES}, { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, -- cgit v1.2.3 From 8e42a5a220a3369c70d88474e887a6de6a4ae209 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 4 Dec 2006 16:36:05 +0000 Subject: [PATCH] pata_ali: small fixes Switch to pci_get_bus_and_slot because some x86 systems seem to be handing us a device with dev->bus = NULL. Also don't apply the isa fixup to revision C6 and later of the chip. Really we need to work out wtf is handing us pdev->bus = NULL, but firstly and more importantly we need the drivers working. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_ali.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index d25563794c8d..c5d61d1911a5 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.7.1" +#define DRV_VERSION "0.7.2" /* * Cable special cases @@ -528,7 +528,7 @@ static void ali_init_chipset(struct pci_dev *pdev) pci_read_config_byte(pdev, 0x4B, &tmp); pci_write_config_byte(pdev, 0x4B, tmp | 0x08); } - north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); + north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { @@ -537,7 +537,7 @@ static void ali_init_chipset(struct pci_dev *pdev) pci_read_config_byte(isa_bridge, 0x79, &tmp); if (rev == 0xC2) pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); - else if (rev > 0xC2) + else if (rev > 0xC2 && rev < 0xC5) pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); } if (rev >= 0x20) { -- cgit v1.2.3