diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/Config.in linux.21-ac4/drivers/ide/Config.in --- linux.vanilla/drivers/ide/Config.in 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/Config.in 2003-06-03 23:15:18.000000000 +0100 @@ -27,8 +27,6 @@ comment 'IDE chipset support/bugfixes' if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then - dep_bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86 - dep_bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640 dep_bool ' ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP if [ "$CONFIG_PCI" = "y" ]; then bool ' PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI @@ -47,7 +47,9 @@ dep_tristate ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_tristate ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 - dep_tristate ' AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_tristate ' AMD and nVidia IDE support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX + dep_tristate ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86 + dep_mbool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640 dep_tristate ' CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI dep_tristate ' Compaq Triflex IDE support' CONFIG_BLK_DEV_TRIFLEX $CONFIG_BLK_DEV_IDEDMA_PCI @@ -63,7 +63,7 @@ dep_tristate ' NS87415 chipset support' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI dep_tristate ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL dep_tristate ' PROMISE PDC202{46|62|65|67} support' CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI + dep_mbool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI dep_tristate ' PROMISE PDC202{68|69|70|71|75|76|77} support' CONFIG_BLK_DEV_PDC202XX_NEW $CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_BLK_DEV_PDC202XX_OLD" = "y" -o "$CONFIG_BLK_DEV_PDC202XX_OLD" = "m" -o "$CONFIG_BLK_DEV_PDC202XX_NEW" = "y" -o "$CONFIG_BLK_DEV_PDC202XX_NEW" = "m" ]; then bool ' Special FastTrak Feature' CONFIG_PDC202XX_FORCE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide.c linux.21-ac4/drivers/ide/ide.c --- linux.vanilla/drivers/ide/ide.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide.c 2003-05-30 22:42:04.000000000 +0100 @@ -1414,6 +1414,8 @@ #endif } +EXPORT_SYMBOL_GPL(ide_add_generic_settings); + /* * Delay for *at least* 50ms. As we don't know how much time is left * until the next tick occurs, we wait an extra tick to be safe. @@ -2110,8 +2112,8 @@ #ifdef CONFIG_BLK_DEV_CMD640 case -14: /* "cmd640_vlb" */ { - extern int cmd640_vlb; /* flag for cmd640.c */ - cmd640_vlb = 1; + extern void init_cmd640_vlb (void); + init_cmd640_vlb(); goto done; } #endif /* CONFIG_BLK_DEV_CMD640 */ @@ -2210,6 +2212,37 @@ } /* + * Legacy interface registration + */ +#define NUM_DRIVER 32 + +/* + * Yes this is moronically simple, but why not - it works! + */ + +static __initdata ide_driver_call ide_scan[NUM_DRIVER]; + +void __init ide_register_driver(ide_driver_call scan) +{ + static int ide_scans = 0; + if(ide_scans == NUM_DRIVER) + panic("Too many IDE drivers"); + ide_scan[ide_scans++]=scan; +} + +EXPORT_SYMBOL(ide_register_driver); + +static void __init ide_scan_drivers(void) +{ + int i = 0; + while(ide_scan[i]) + { + (ide_scan[i])(); + i++; + } +} + +/* * probe_for_hwifs() finds/initializes "known" IDE interfaces */ static void __init probe_for_hwifs (void) @@ -2220,25 +2253,17 @@ ide_scan_pcibus(ide_scan_direction); } #endif /* CONFIG_BLK_DEV_IDEPCI */ + ide_scan_drivers(); + /* + * Unconverted drivers + */ #ifdef CONFIG_ETRAX_IDE { extern void init_e100_ide(void); init_e100_ide(); } #endif /* CONFIG_ETRAX_IDE */ -#ifdef CONFIG_BLK_DEV_CMD640 - { - extern void ide_probe_for_cmd640x(void); - ide_probe_for_cmd640x(); - } -#endif /* CONFIG_BLK_DEV_CMD640 */ -#ifdef CONFIG_BLK_DEV_PDC4030 - { - extern int ide_probe_for_pdc4030(void); - (void) ide_probe_for_pdc4030(); - } -#endif /* CONFIG_BLK_DEV_PDC4030 */ #ifdef CONFIG_BLK_DEV_IDE_PMAC { extern void pmac_ide_probe(void); @@ -2293,12 +2318,6 @@ buddha_init(); } #endif /* CONFIG_BLK_DEV_BUDDHA */ -#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) - { - extern void pnpide_init(int enable); - pnpide_init(1); - } -#endif /* CONFIG_BLK_DEV_ISAPNP */ } void __init ide_init_builtin_subdrivers (void) @@ -2355,6 +2374,10 @@ void __init ide_init_builtin_drivers (void) { /* + * Attach null driver + */ + idedefault_init(); + /* * Probe for special PCI and other "known" interface chipsets */ probe_for_hwifs (); @@ -2604,9 +2627,6 @@ up(&ide_setting_sem); return 1; } -#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE) - pnpide_init(0); -#endif /* CONFIG_BLK_DEV_ISAPNP */ #ifdef CONFIG_PROC_FS ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc); ide_remove_proc_entries(drive->proc, generic_subdriver_entries); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-default.c linux.21-ac4/drivers/ide/ide-default.c --- linux.vanilla/drivers/ide/ide-default.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide-default.c 2003-05-30 19:44:32.000000000 +0100 @@ -85,13 +85,10 @@ return ret; } -MODULE_DESCRIPTION("IDE Default Driver"); - int idedefault_init (void) { ide_register_module(&idedefault_module); return 0; } -module_init(idedefault_init); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-dma.c linux.21-ac4/drivers/ide/ide-dma.c --- linux.vanilla/drivers/ide/ide-dma.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide-dma.c 2003-05-29 01:38:47.000000000 +0100 @@ -528,9 +528,10 @@ * the driver to resolve the problem, if a DMA transfer is still * in progress we continue to wait (arguably we need to add a * secondary 'I dont care what the drive thinks' timeout here) - * Finally if we have an interrupt but for some reason got the - * timeout first we complete the I/O. This can occur if an - * interrupt is lost or due to bugs. + * Finally if we have an interrupt we let it complete the I/O. + * But only one time - we clear expiry and if it's still not + * completed after WAIT_CMD, we error and retry in PIO. + * This can occur if an interrupt is lost or due to hang or bugs. */ static int dma_timer_expiry (ide_drive_t *drive) @@ -544,22 +545,24 @@ if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */ return WAIT_CMD; - HWGROUP(drive)->expiry = NULL; /* one free ride for now */ + /* + * Clear the expiry handler in case we decide to wait more, + * next time timer expires it is an error + */ + HWGROUP(drive)->expiry = NULL; /* 1 dmaing, 2 error, 4 intr */ - if (dma_stat & 2) { /* ERROR */ - (void) hwif->ide_dma_end(drive); - return DRIVER(drive)->error(drive, - "dma_timer_expiry", hwif->INB(IDE_STATUS_REG)); - } + if (dma_stat & 2) /* ERROR */ + return -1; + if (dma_stat & 1) /* DMAing */ return WAIT_CMD; if (dma_stat & 4) /* Got an Interrupt */ - HWGROUP(drive)->handler(drive); + return WAIT_CMD; - return 0; + return 0; /* Unknown status -- reset the bus */ } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-geometry.c linux.21-ac4/drivers/ide/ide-geometry.c --- linux.vanilla/drivers/ide/ide-geometry.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide-geometry.c 2003-05-30 19:58:14.000000000 +0100 @@ -215,3 +215,4 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); return ret; } + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-io.c linux.21-ac4/drivers/ide/ide-io.c --- linux.vanilla/drivers/ide/ide-io.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide-io.c 2003-05-30 19:56:36.000000000 +0100 @@ -896,15 +896,18 @@ ide_do_request(q->queuedata, IDE_NO_IRQ); } +EXPORT_SYMBOL(do_ide_request); + /* * un-busy the hwgroup etc, and clear any pending DMA status. we want to * retry the current request in pio mode instead of risking tossing it * all away */ -void ide_dma_timeout_retry(ide_drive_t *drive) +static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { ide_hwif_t *hwif = HWIF(drive); struct request *rq; + ide_startstop_t ret = ide_stopped; /* * end current dma transaction @@ -914,8 +917,16 @@ /* * complain a little, later we might remove some of this verbosity */ - printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); - (void) hwif->ide_dma_timeout(drive); + + if (error < 0) { + printk(KERN_ERR "%s: error waiting for DMA\n", drive->name); + (void)HWIF(drive)->ide_dma_end(drive); + ret = DRIVER(drive)->error(drive, "dma timeout retry", + hwif->INB(IDE_STATUS_REG)); + } else { + printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); + (void) hwif->ide_dma_timeout(drive); + } /* * disable dma for now, but remember that we did so because of @@ -938,9 +949,9 @@ rq->current_nr_sectors = rq->bh->b_size >> 9; rq->hard_cur_sectors = rq->current_nr_sectors; rq->buffer = rq->bh->b_data; -} -EXPORT_SYMBOL(ide_dma_timeout_retry); + return ret; +} /** * ide_timer_expiry - handle lack of an IDE interrupt @@ -962,10 +973,9 @@ ide_handler_t *handler; ide_expiry_t *expiry; unsigned long flags; - unsigned long wait; + unsigned long wait = -1; spin_lock_irqsave(&io_request_lock, flags); - del_timer(&hwgroup->timer); if ((handler = hwgroup->handler) == NULL) { /* @@ -992,7 +1002,7 @@ } if ((expiry = hwgroup->expiry) != NULL) { /* continue */ - if ((wait = expiry(drive)) != 0) { + if ((wait = expiry(drive)) > 0) { /* reset timer */ hwgroup->timer.expires = jiffies + wait; add_timer(&hwgroup->timer); @@ -1028,16 +1038,15 @@ startstop = handler(drive); } else { if (drive->waiting_for_dma) { - startstop = ide_stopped; - ide_dma_timeout_retry(drive); + startstop = ide_dma_timeout_retry(drive, wait); } else { startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); } } set_recovery_timer(hwif); drive->service_time = jiffies - drive->service_start; - enable_irq(hwif->irq); spin_lock_irq(&io_request_lock); + enable_irq(hwif->irq); if (startstop == ide_stopped) hwgroup->busy = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-pnp.c linux.21-ac4/drivers/ide/ide-pnp.c --- linux.vanilla/drivers/ide/ide-pnp.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide-pnp.c 2003-05-30 20:54:38.000000000 +0100 @@ -16,6 +16,7 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include @@ -98,7 +99,7 @@ * Probe for ISA PnP IDE interfaces. */ -void __init pnpide_init(int enable) +static void pnpide_init(int enable) { struct pci_dev *dev = NULL; struct pnp_dev_t *dev_type; @@ -155,3 +156,26 @@ } } } + +static void __init pnpide_begin(void) +{ + pnpide_init(1); +} + +static int pnpide_init_module(void) +{ + ide_register_driver(pnpide_begin); + return 0; +} + +static void pnpide_unload(void) +{ + pnpide_init(0); +} + +module_init(pnpide_init_module); +module_exit(pnpide_unload); + +MODULE_AUTHOR("Andrey Panin"); +MODULE_DESCRIPTION("Enabler for ISAPNP IDE devices"); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/ide-proc.c linux.21-ac4/drivers/ide/ide-proc.c --- linux.vanilla/drivers/ide/ide-proc.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/ide-proc.c 2003-06-03 18:18:09.000000000 +0100 @@ -982,16 +982,11 @@ void proc_ide_destroy(void) { #ifdef CONFIG_BLK_DEV_IDEPCI - ide_pci_host_proc_t *p = ide_pci_host_proc_list; - char name[32]; + ide_pci_host_proc_t *p; - while ((p->name != NULL) && (p->set) && (p->get_info != NULL)) { - name[0] = '\0'; - sprintf(name, "ide/%s", p->name); + for (p = ide_pci_host_proc_list; p; p = p->next) { if (p->set == 2) remove_proc_entry(p->name, p->parent); - if (p->next == NULL) break; - p = p->next; } #endif /* CONFIG_BLK_DEV_IDEPCI */ remove_proc_entry("ide/drivers", proc_ide_root); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/legacy/pdc4030.c linux.21-ac4/drivers/ide/legacy/pdc4030.c --- linux.vanilla/drivers/ide/legacy/pdc4030.c 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/legacy/pdc4030.c 2003-05-30 20:22:40.000000000 +0100 @@ -147,8 +147,6 @@ return pdc4030_cmd(drive, PROMISE_IDENTIFY); } -int enable_promise_support; - /* * setup_pdc4030() * Completes the setup of a Promise DC4030 controller card, once found. @@ -308,11 +306,6 @@ unsigned int index; ide_hwif_t *hwif; -#ifndef MODULE - if (enable_promise_support == 0) - return; -#endif - for (index = 0; index < MAX_HWIFS; index++) { hwif = &ide_hwifs[index]; if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) { @@ -362,7 +355,7 @@ void __init init_pdc4030(void) { - enable_promise_support = 1; + ide_register_driver(ide_probe_for_pdc4030); } #else @@ -373,9 +366,6 @@ int __init pdc4030_mod_init(void) { - if (enable_promise_support == 0) - enable_promise_support = 1; - if (!ide_probe_for_pdc4030()) return -ENODEV; return 0; @@ -387,9 +377,6 @@ unsigned int index; ide_hwif_t *hwif; - if (enable_promise_support == 0) - return; - for (index = 0; index < MAX_HWIFS; index++) { hwif = &ide_hwifs[index]; if (hwif->chipset == ide_pdc4030) { @@ -400,7 +387,6 @@ release_pdc4030(hwif, NULL); } } - enable_promise_support = 0; } module_exit(pdc4030_mod_exit); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/Makefile linux.21-ac4/drivers/ide/Makefile --- linux.vanilla/drivers/ide/Makefile 2003-06-14 00:11:30.000000000 +0100 +++ linux.21-ac4/drivers/ide/Makefile 2003-05-30 23:14:43.000000000 +0100 @@ -8,7 +8,6 @@ # In the future, some of these should be built conditionally. # -O_TARGET := idedriver.o export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o ide-io.o ide-disk.o @@ -29,24 +28,25 @@ # Core IDE code - must come before legacy -obj-$(CONFIG_BLK_DEV_IDE) += ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o ide-default.o -obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o -obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o -obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o -obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o +ide-core-objs := ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o ide-default.o ide-proc.o +ide-detect-objs := ide-probe.o ide-geometry.o + ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) -obj-$(CONFIG_BLK_DEV_IDE) += setup-pci.o +ide-core-objs += setup-pci.o endif ifeq ($(CONFIG_BLK_DEV_IDEDMA_PCI),y) -obj-$(CONFIG_BLK_DEV_IDE) += ide-dma.o +ide-core-objs += ide-dma.o endif -obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o +# Initialisation order: +# Core sets up +# Legacy drivers may register a callback +# Drivers are pre initialised +# Probe inits the drivers and driver callbacks +# Raid scans the devices -ifeq ($(CONFIG_BLK_DEV_IDE),y) -obj-$(CONFIG_PROC_FS) += ide-proc.o -endif +obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o ifeq ($(CONFIG_BLK_DEV_IDE),y) obj-y += legacy/idedriver-legacy.o @@ -58,10 +58,28 @@ endif endif +obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o + +obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o +obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o +obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o +obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o + +obj-$(CONFIG_BLK_DEV_IDE) += ide-detect.o ifeq ($(CONFIG_BLK_DEV_IDE),y) # RAID must be last of all obj-y += raid/idedriver-raid.o endif +list-multi := ide-core.o ide-detect.o +O_TARGET := idedriver.o + include $(TOPDIR)/Rules.make + +ide-core.o: $(ide-core-objs) + $(LD) -r -o $@ $(ide-core-objs) + +ide-detect.o: $(ide-detect-objs) + $(LD) -r -o $@ $(ide-detect-objs) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/cmd640.c linux.21-ac4/drivers/ide/pci/cmd640.c --- linux.vanilla/drivers/ide/pci/cmd640.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/cmd640.c 2003-05-30 23:16:59.000000000 +0100 @@ -102,6 +102,7 @@ #define CMD640_PREFETCH_MASKS 1 #include +#include #include #include #include @@ -120,7 +121,8 @@ /* * This flag is set in ide.c by the parameter: ide0=cmd640_vlb */ -int cmd640_vlb = 0; + +static int cmd640_vlb = 0; /* * CMD640 specific registers definition. @@ -716,7 +718,7 @@ /* * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c */ -int __init ide_probe_for_cmd640x (void) +static void __init ide_probe_for_cmd640x (void) { #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED int second_port_toggled = 0; @@ -731,13 +733,13 @@ } else { cmd640_vlb = 0; /* Find out what kind of PCI probing is supported otherwise - Justin Gibbs will sulk.. */ + we break some Adaptec cards... */ if (pci_conf1() && probe_for_cmd640_pci1()) bus_type = "PCI (type1)"; else if (pci_conf2() && probe_for_cmd640_pci2()) bus_type = "PCI (type2)"; else - return 0; + return; } /* * Undocumented magic (there is no 0x5b reg in specs) @@ -745,7 +747,7 @@ put_cmd640_reg(0x5b, 0xbd); if (get_cmd640_reg(0x5b) != 0xbd) { printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n"); - return 0; + return; } put_cmd640_reg(0x5b, 0); @@ -760,7 +762,7 @@ cmd640_chip_version = cfr & CFR_DEVREV; if (cmd640_chip_version == 0) { printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version); - return 0; + return; } /* @@ -874,6 +876,28 @@ #ifdef CMD640_DUMP_REGS CMD640_DUMP_REGS; #endif - return 1; + return; +} + +static int __init cmd640_init(void) +{ + ide_register_driver(ide_probe_for_cmd640x); + return 0; +} + +/* + * Called by the IDE core when compiled in and cmd640=vlb is + * selected. + */ +void init_cmd640_vlb(void) +{ + cmd640_vlb = 1; } +module_init(cmd640_init); + +MODULE_AUTHOR("See Source"); +MODULE_DESCRIPTION("IDE support for CMD640 controller"); +MODULE_PARM(cmd640_vlb, "i"); +MODULE_PARM_DESC(cmd640_vlb, "Set to enable scanning for VLB controllers"); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/generic.c linux.21-ac4/drivers/ide/pci/generic.c --- linux.vanilla/drivers/ide/pci/generic.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/generic.c 2003-06-02 17:46:35.000000000 +0100 @@ -140,6 +140,7 @@ { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, { 0, }, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/generic.h linux.21-ac4/drivers/ide/pci/generic.h --- linux.vanilla/drivers/ide/pci/generic.h 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/generic.h 2003-06-27 17:13:09.000000000 +0100 @@ -127,6 +127,19 @@ .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, .extra = 0, + },{ /* 9 */ + .vendor = PCI_VENDOR_ID_TOSHIBA, + .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO, + .name = "Piccolo", + .init_chipset = init_chipset_generic, + .init_iops = NULL, + .init_hwif = init_hwif_generic, + .init_dma = init_dma_generic, + .channels = 2, + .autodma = NOAUTODMA, + .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, + .bootable = ON_BOARD, + .extra = 0, },{ .vendor = 0, .device = 0, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/hpt366.c linux.21-ac4/drivers/ide/pci/hpt366.c --- linux.vanilla/drivers/ide/pci/hpt366.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/hpt366.c 2003-06-22 18:18:49.000000000 +0100 @@ -484,9 +484,12 @@ { u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive)); - if (!(speed)) + if (!speed) return 0; + if (pci_get_drvdata(HWIF(drive)->pci_dev) == NULL) + return 0; + (void) hpt3xx_tune_chipset(drive, speed); return ide_dma_enable(drive); } @@ -919,6 +922,8 @@ * Currently we always set up the PLL for the 372N */ + pci_set_drvdata(dev, NULL); + if(is_372n) { printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n"); @@ -957,6 +962,7 @@ pci_set_drvdata(dev, (void *) thirty_three_base_hpt370); printk("HPT37X: using 33MHz PCI clock\n"); } else if (pll == F_LOW_PCI_40) { + /* Unsupported */ } else if (pll == F_LOW_PCI_50) { if (hpt_minimum_revision(dev,8)) pci_set_drvdata(dev, NULL); @@ -971,7 +977,6 @@ if (hpt_minimum_revision(dev,8)) { printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n"); - pci_set_drvdata(dev, NULL); } else if (hpt_minimum_revision(dev,5)) pci_set_drvdata(dev, (void *) sixty_six_base_hpt372); @@ -996,6 +1001,11 @@ if (pci_get_drvdata(dev)) goto init_hpt37X_done; + if (hpt_minimum_revision(dev,8)) + { + printk(KERN_ERR "HPT374: Only 33MHz PCI timings are supported.\n"); + return -EOPNOTSUPP; + } /* * adjust PLL based upon PCI clock, enable it, and wait for * stabilization. @@ -1021,9 +1031,7 @@ pci_write_config_dword(dev, 0x5c, pll & ~0x100); pci_write_config_byte(dev, 0x5b, 0x21); - if (hpt_minimum_revision(dev,8)) - return -EOPNOTSUPP; - else if (hpt_minimum_revision(dev,5)) + if (hpt_minimum_revision(dev,5)) pci_set_drvdata(dev, (void *) fifty_base_hpt372); else if (hpt_minimum_revision(dev,4)) pci_set_drvdata(dev, (void *) fifty_base_hpt370a); @@ -1334,7 +1342,7 @@ struct pci_dev *findev = NULL; u8 pin1 = 0, pin2 = 0; unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", + static char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"}; if (PCI_FUNC(dev->devfn) & 1) @@ -1349,7 +1357,8 @@ if(d->device == PCI_DEVICE_ID_TTI_HPT372N) class_rev = 5; - strcpy(d->name, chipset_names[class_rev]); + if(class_rev < 6) + d->name = chipset_names[class_rev]; switch(class_rev) { case 5: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/pdc202xx_new.h linux.21-ac4/drivers/ide/pci/pdc202xx_new.h --- linux.vanilla/drivers/ide/pci/pdc202xx_new.h 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/pdc202xx_new.h 2003-06-27 17:13:09.000000000 +0100 @@ -255,7 +255,7 @@ .vendor = PCI_VENDOR_ID_PROMISE, .device = PCI_DEVICE_ID_PROMISE_20275, .name = "PDC20275", - .init_setup = init_setup_pdcnew, + .init_setup = init_setup_pdc20276, .init_chipset = init_chipset_pdcnew, .init_iops = NULL, .init_hwif = init_hwif_pdc202new, @@ -287,7 +287,7 @@ .vendor = PCI_VENDOR_ID_PROMISE, .device = PCI_DEVICE_ID_PROMISE_20277, .name = "PDC20277", - .init_setup = init_setup_pdcnew, + .init_setup = init_setup_pdc20276, .init_chipset = init_chipset_pdcnew, .init_iops = NULL, .init_hwif = init_hwif_pdc202new, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/pdc202xx_old.c linux.21-ac4/drivers/ide/pci/pdc202xx_old.c --- linux.vanilla/drivers/ide/pci/pdc202xx_old.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/pdc202xx_old.c 2003-06-02 15:23:26.000000000 +0100 @@ -168,9 +168,6 @@ pdc202xx_pio_verbose(reg64h), pdc202xx_pio_verbose(reg68h), pdc202xx_pio_verbose(reg6ch)); -#if 0 - p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n"); -#endif return (char *)p; } @@ -635,42 +632,7 @@ pdc202xx_reset_host(hwif); pdc202xx_reset_host(mate); -#if 0 - /* - * FIXME: Have to kick all the drives again :-/ - * What a pain in the ACE! - */ - if (hwif->present) { - u16 hunit = 0; - hwif->initializing = 1; - for (hunit = 0; hunit < MAX_DRIVES; ++hunit) { - ide_drive_t *hdrive = &hwif->drives[hunit]; - if (hdrive->present) { - if (hwif->ide_dma_check) - hwif->ide_dma_check(hdrive); - else - hwif->tuneproc(hdrive, 5); - } - } - hwif->initializing = 0; - } - if (mate->present) { - u16 munit = 0; - mate->initializing = 1; - for (munit = 0; munit < MAX_DRIVES; ++munit) { - ide_drive_t *mdrive = &mate->drives[munit]; - if (mdrive->present) { - if (mate->ide_dma_check) - mate->ide_dma_check(mdrive); - else - mate->tuneproc(mdrive, 5); - } - } - mate->initializing = 0; - } -#else hwif->tuneproc(drive, 5); -#endif } /* @@ -726,20 +688,6 @@ * reset leaves the timing registers intact, * but resets the drives. */ -#if 0 - if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) || - (dev->device == PCI_DEVICE_ID_PROMISE_20265) || - (dev->device == PCI_DEVICE_ID_PROMISE_20263) || - (dev->device == PCI_DEVICE_ID_PROMISE_20262)) { - unsigned long high_16 = pci_resource_start(dev, 4); - byte udma_speed_flag = inb(high_16 + 0x001f); - outb(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - outb(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ - } - -#endif return dev->irq; } @@ -859,18 +807,6 @@ } } -#if 0 - if (dev->device == PCI_DEVICE_ID_PROMISE_20262) - if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || - (tmp & e->mask) != e->val)) - - if (d->enablebits[0].reg != d->enablebits[1].reg) { - d->enablebits[0].reg = d->enablebits[1].reg; - d->enablebits[0].mask = d->enablebits[1].mask; - d->enablebits[0].val = d->enablebits[1].val; - } -#endif - ide_setup_pci_device(dev, d); } @@ -884,22 +820,6 @@ "attached to I2O RAID controller.\n"); return; } - -#if 0 - { - u8 pri = 0, sec = 0; - - if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || - (tmp & e->mask) != e->val)) - - if (d->enablebits[0].reg != d->enablebits[1].reg) { - d->enablebits[0].reg = d->enablebits[1].reg; - d->enablebits[0].mask = d->enablebits[1].mask; - d->enablebits[0].val = d->enablebits[1].val; - } - } -#endif - ide_setup_pci_device(dev, d); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/piix.c linux.21-ac4/drivers/ide/pci/piix.c --- linux.vanilla/drivers/ide/pci/piix.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/piix.c 2003-06-22 20:24:21.000000000 +0100 @@ -811,7 +811,9 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, +#if 0 /* SATA is covered by ata_piix scsi driver */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, +#endif { 0, }, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/siimage.c linux.21-ac4/drivers/ide/pci/siimage.c --- linux.vanilla/drivers/ide/pci/siimage.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/siimage.c 2003-06-27 17:49:44.000000000 +0100 @@ -1,10 +1,24 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.02 Jan 30, 2003 + * linux/drivers/ide/pci/siimage.c Version 1.06 June 11, 2003 * * Copyright (C) 2001-2002 Andre Hedrick * Copyright (C) 2003 Red Hat * * May be copied or modified under the terms of the GNU General Public License + * + * Documentation available under NDA only + * + * + * FAQ Items: + * If you are using Marvell SATA-IDE adapters with Maxtor drives + * ensure the system is set up for ATA100/UDMA5 not UDMA6. + * + * If you are using WD drives with SATA bridges you must set the + * drive to "Single". "Master" will hang + * + * If you have strange problems with nVidia chipset systems please + * see the SI support documentation and update your system BIOS + * if neccessary */ #include @@ -30,12 +44,102 @@ static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS]; static int n_siimage_devs; -static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index) +/** + * pdev_is_sata - check if device is SATA + * @pdev: PCI device to check + * + * Returns true if this is a SATA controller + */ + +static int pdev_is_sata(struct pci_dev *pdev) +{ + switch(pdev->device) + { + case PCI_DEVICE_ID_SII_3112: + case PCI_DEVICE_ID_SII_1210SA: + return 1; + case PCI_DEVICE_ID_SII_680: + return 0; + } + BUG(); +} + +/** + * is_sata - check if hwif is SATA + * @hwif: interface to check + * + * Returns true if this is a SATA controller + */ + +static inline int is_sata(ide_hwif_t *hwif) +{ + return pdev_is_sata(hwif->pci_dev); +} + +/** + * siimage_selreg - return register base + * @hwif: interface + * @r: config offset + * + * Turn a config register offset into the right address in either + * PCI space or MMIO space to access the control register in question + * Thankfully this is a configuration operation so isnt performance + * criticial. + */ + +static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) +{ + unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; + if(hwif->mmio) + base += (hwif->channel << 6); + else + base += (hwif->channel << 4); + return base; +} + +/** + * siimage_seldev - return register base + * @hwif: interface + * @r: config offset + * + * Turn a config register offset into the right address in either + * PCI space or MMIO space to access the control register in question + * including accounting for the unit shift. + */ + +static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; + if(hwif->mmio) + base += (hwif->channel << 6); + else + base += (hwif->channel << 4); + base |= drive->select.b.unit << drive->select.b.unit; + return base; +} + +/** + * print_siimage_get_info - print minimal proc information + * @buf: buffer to write into (kernel space) + * @dev: PCI device we are describing + * @index: Controller number + * + * Print the basic information for the state of the CMD680/SI3112 + * channel. We don't actually dump a lot of information out for + * this controller although we could expand it if we needed. + */ + +static char *print_siimage_get_info (char *buf, struct pci_dev *dev, int index) { char *p = buf; u8 mmio = (pci_get_drvdata(dev) != NULL) ? 1 : 0; - unsigned long bmdma = (mmio) ? ((unsigned long) pci_get_drvdata(dev)) : - (pci_resource_start(dev, 4)); + unsigned long bmdma = pci_resource_start(dev, 4); + + if(mmio) + bmdma = pci_resource_start(dev, 5); p += sprintf(p, "\nController: %d\n", index); p += sprintf(p, "SiI%x Chipset.\n", dev->device); @@ -43,18 +147,20 @@ p += sprintf(p, "MMIO Base 0x%lx\n", bmdma); p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma); p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8); - - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, "--------------- drive0 --------- drive1 " - "-------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "PIO Mode: %s %s" - " %s %s\n", - "?", "?", "?", "?"); return (char *)p; } +/** + * siimage_get_info - proc callback + * @buffer: kernel buffer to complete + * @addr: written with base of data to return + * offset: seek offset + * count: bytes to fill in + * + * Called when the user reads data from the virtual file for this + * controller from /proc + */ + static int siimage_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; @@ -89,44 +195,56 @@ { ide_hwif_t *hwif = HWIF(drive); u8 mode = 0, scsc = 0; + unsigned long base = (unsigned long) hwif->hwif_data; if (hwif->mmio) - scsc = hwif->INB(HWIFADDR(0x4A)); + scsc = hwif->INB(base + 0x4A); else pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_SII_3112: - return 4; - case PCI_DEVICE_ID_SII_680: - if ((scsc & 0x30) == 0x10) /* 133 */ - mode = 4; - else if ((scsc & 0x30) == 0x20) /* 2xPCI */ - mode = 4; - else if ((scsc & 0x30) == 0x00) /* 100 */ - mode = 3; - else /* Disabled ? */ - BUG(); - break; - default: return 0; + if(is_sata(hwif)) + { + if(strstr(drive->id->model, "Maxtor")) + return 3; + return 4; } + + if ((scsc & 0x30) == 0x10) /* 133 */ + mode = 4; + else if ((scsc & 0x30) == 0x20) /* 2xPCI */ + mode = 4; + else if ((scsc & 0x30) == 0x00) /* 100 */ + mode = 3; + else /* Disabled ? */ + BUG(); + if (!eighty_ninty_three(drive)) mode = min(mode, (u8)1); return mode; } +/** + * siimage_taskfile_timing - turn timing data to a mode + * @hwif: interface to query + * + * Read the timing data for the interface and return the + * mode that is being used. + */ + static byte siimage_taskfile_timing (ide_hwif_t *hwif) { u16 timing = 0x328a; + unsigned long addr = siimage_selreg(hwif, 2); if (hwif->mmio) - timing = hwif->INW(SELADDR(2)); + timing = hwif->INW(addr); else - pci_read_config_word(hwif->pci_dev, SELREG(2), &timing); + pci_read_config_word(hwif->pci_dev, addr, &timing); switch (timing) { case 0x10c1: return 4; case 0x10c3: return 3; + case 0x1104: case 0x1281: return 2; case 0x2283: return 1; case 0x328a: @@ -140,37 +258,82 @@ * @mode_wanted: the target operating mode * * Load the timing settings for this device mode into the - * controller + * controller. If we are in PIO mode 3 or 4 turn on IORDY + * monitoring (bit 9). The TF timing is bits 31:16 */ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted) { ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u16 speedt = 0; - u8 unit = drive->select.b.unit; - - if (hwif->mmio) - speedt = hwif->INW(SELADDR(0x04|(unit<mmio) - hwif->OUTW(speedt, SELADDR(0x04|(unit<OUTW(speedt, addr); + hwif->OUTW(speedp, tfaddr); + /* Now set up IORDY */ + if(mode_wanted == 3 || mode_wanted == 4) + hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); + else + hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); + } else - pci_write_config_word(dev, SELADDR(0x04|(unit<pci_dev, addr, speedp); + pci_write_config_word(hwif->pci_dev, tfaddr, speedt); + pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp); + speedp &= ~0x200; + /* Set IORDY for mode 3 or 4 */ + if(mode_wanted == 3 || mode_wanted == 4) + speedp |= 0x200; + pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp); + } } +/** + * config_siimage_chipset_for_pio - set drive timings + * @drive: drive to tune + * @speed we want + * + * Compute the best pio mode we can for a given device. Also honour + * the timings for the driver when dealing with mixed devices. Some + * of this is ugly but its all wrapped up here + * + * The SI680 can also do VDMA - we need to start using that + * + * FIXME: we use the BIOS channel timings to avoid driving the task + * files too fast at the disk. We need to compute the master/slave + * drive PIO mode properly so that we can up the speed on a hotplug + * system. + */ + static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed) { u8 channel_timings = siimage_taskfile_timing(HWIF(drive)); @@ -191,6 +354,16 @@ config_siimage_chipset_for_pio(drive, set_speed); } +/** + * siimage_tune_chipset - set controller timings + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Tune the SII chipset for the desired mode. If we can't achieve + * the desired mode then tune for a lower one, but ultimately + * make the thing work. + */ + static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) { u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; @@ -200,30 +373,32 @@ ide_hwif_t *hwif = HWIF(drive); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; - u8 speed = ide_rate_filter(siimage_ratemask(drive), xferspeed); + u8 speed = ide_rate_filter(siimage_ratemask(drive), xferspeed); + unsigned long base = (unsigned long)hwif->hwif_data; u8 scsc = 0, addr_mask = ((hwif->channel) ? ((hwif->mmio) ? 0xF4 : 0x84) : ((hwif->mmio) ? 0xB4 : 0x80)); + + unsigned long ma = siimage_seldev(drive, 0x08); + unsigned long ua = siimage_seldev(drive, 0x0C); if (hwif->mmio) { - scsc = hwif->INB(HWIFADDR(0x4A)); - mode = hwif->INB(HWIFADDR(addr_mask)); - multi = hwif->INW(SELADDR(0x08|(unit<INW(SELADDR(0x0C|(unit<INB(base + 0x4A); + mode = hwif->INB(base + addr_mask); + multi = hwif->INW(ma); + ultra = hwif->INW(ua); } else { pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); - pci_read_config_word(hwif->pci_dev, - SELREG(0x08|(unit<pci_dev, - SELREG(0x0C|(unit<pci_dev, ma, &multi); + pci_read_config_word(hwif->pci_dev, ua, &ultra); } mode &= ~((unit) ? 0x30 : 0x03); ultra &= ~0x3F; scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; - scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc; + scsc = is_sata(hwif) ? 1 : scsc; switch(speed) { case XFER_PIO_4: @@ -259,20 +434,26 @@ } if (hwif->mmio) { - hwif->OUTB(mode, HWIFADDR(addr_mask)); - hwif->OUTW(multi, SELADDR(0x08|(unit<OUTW(ultra, SELADDR(0x0C|(unit<OUTB(mode, base + addr_mask); + hwif->OUTW(multi, ma); + hwif->OUTW(ultra, ua); } else { pci_write_config_byte(hwif->pci_dev, addr_mask, mode); - pci_write_config_word(hwif->pci_dev, - SELREG(0x08|(unit<pci_dev, - SELREG(0x0C|(unit<pci_dev, ma, multi); + pci_write_config_word(hwif->pci_dev, ua, ultra); } - return (ide_config_drive_speed(drive, speed)); } +/** + * config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by the IDE layer when it wants the timings set up. + * For the CMD680 we also need to set up the PIO timings and + * enable DMA. + */ + static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, siimage_ratemask(drive)); @@ -291,6 +472,16 @@ return ide_dma_enable(drive); } +/** + * siimage_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. If the drive isn't suitable for DMA or we hit + * other problems then we will drop down to PIO and set up + * PIO appropriately + */ + static int siimage_config_drive_for_dma (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -340,18 +531,28 @@ { ide_hwif_t *hwif = HWIF(drive); u8 dma_altstat = 0; + unsigned long addr = siimage_selreg(hwif, 1); /* return 1 if INTR asserted */ if ((hwif->INB(hwif->dma_status) & 4) == 4) return 1; /* return 1 if Device INTR asserted */ - pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat); + pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat); if (dma_altstat & 8) return 0; //return 1; return 0; } +/** + * siimage_mmio_ide_dma_count - DMA bytes done + * @drive + * + * If we are doing VDMA the CMD680 requires a little bit + * of more careful handling and we have to read the counts + * off ourselves. For non VDMA life is normal. + */ + static int siimage_mmio_ide_dma_count (ide_drive_t *drive) { #ifdef SIIMAGE_VIRTUAL_DMAPIO @@ -359,9 +560,10 @@ ide_hwif_t *hwif = HWIF(drive); u32 count = (rq->nr_sectors * SECTOR_SIZE); u32 rcount = 0; + unsigned long addr = siimage_selreg(hwif, 0x1C); - hwif->OUTL(count, SELADDR(0x1C)); - rcount = hwif->INL(SELADDR(0x1C)); + hwif->OUTL(count, addr); + rcount = hwif->INL(addr); printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n", drive->name, count, rcount, rq->nr_sectors); @@ -370,13 +572,22 @@ return __ide_dma_count(drive); } -/* returns 1 if dma irq issued, 0 otherwise */ +/** + * siimage_mmio_ide_dma_test_irq - check we caused an IRQ + * @drive: drive we are testing + * + * Check if we caused an IDE DMA interrupt. We may also have caused + * SATA status interrupts, if so we clean them up and continue. + */ + static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + unsigned long base = (unsigned long)hwif->hwif_data; + unsigned long addr = siimage_selreg(hwif, 0x1); if (SATA_ERROR_REG) { - u32 ext_stat = hwif->INL(HWIFADDR(0x10)); + u32 ext_stat = hwif->INL(base + 0x10); u8 watchdog = 0; if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { u32 sata_error = hwif->INL(SATA_ERROR_REG); @@ -403,7 +614,7 @@ return 1; /* return 1 if Device INTR asserted */ - if ((hwif->INB(SELADDR(1)) & 8) == 8) + if ((hwif->INB(addr) & 8) == 8) return 0; //return 1; return 0; @@ -412,9 +623,6 @@ static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive) { int temp = __ide_dma_verbose(drive); -#if 0 - drive->using_dma = 0; -#endif return temp; } @@ -432,11 +640,12 @@ { ide_hwif_t *hwif = HWIF(drive); u32 stat_config = 0; + unsigned long addr = siimage_selreg(hwif, 0); if (hwif->mmio) { - stat_config = hwif->INL(SELADDR(0)); + stat_config = hwif->INL(addr); } else - pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config); + pci_read_config_dword(hwif->pci_dev, addr, &stat_config); switch (state) { case BUSSTATE_ON: @@ -458,6 +667,14 @@ return 0; } +/** + * siimage_reset_poll - wait for sata reset + * @drive: drive we are resetting + * + * Poll the SATA phy and see whether it has come back from the dead + * yet. + */ + static int siimage_reset_poll (ide_drive_t *drive) { if (SATA_STATUS_REG) { @@ -488,7 +705,8 @@ if (drive->media != ide_disk) return; - if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) { + if (is_sata(HWIF(drive))) + { drive->special.b.set_geometry = 0; drive->special.b.recalibrate = 0; } @@ -506,19 +724,21 @@ { ide_hwif_t *hwif = HWIF(drive); u8 reset = 0; + unsigned long addr = siimage_selreg(hwif, 0); if (hwif->mmio) { - reset = hwif->INB(SELADDR(0)); - hwif->OUTB((reset|0x03), SELADDR(0)); + reset = hwif->INB(addr); + hwif->OUTB((reset|0x03), addr); + /* FIXME:posting */ udelay(25); - hwif->OUTB(reset, SELADDR(0)); - (void) hwif->INB(SELADDR(0)); + hwif->OUTB(reset, addr); + (void) hwif->INB(addr); } else { - pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset); - pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03); + pci_read_config_byte(hwif->pci_dev, addr, &reset); + pci_write_config_byte(hwif->pci_dev, addr, reset|0x03); udelay(25); - pci_write_config_byte(hwif->pci_dev, SELREG(0), reset); - pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset); + pci_write_config_byte(hwif->pci_dev, addr, reset); + pci_read_config_byte(hwif->pci_dev, addr, &reset); } if (SATA_STATUS_REG) { @@ -546,11 +766,11 @@ static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name) { - if (dev->device == PCI_DEVICE_ID_SII_3112) + if(pdev_is_sata(dev)) goto sata_skip; printk(KERN_INFO "%s: BASE CLOCK ", name); - clocking &= ~0x03; + clocking &= 0x03; switch(clocking) { case 0x03: printk("DISABLED !\n"); break; case 0x02: printk("== 2X PCI \n"); break; @@ -570,10 +790,20 @@ #endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */ } +/** + * setup_mmio_siimage - switch an SI controller into MMIO + * @dev: PCI device we are configuring + * @name: device name + * + * Attempt to put the device into mmio mode. There are some slight + * complications here with certain systems where the mmio bar isnt + * mapped so we have to be sure we can fall back to I/O. + */ + static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) { unsigned long bar5 = pci_resource_start(dev, 5); - unsigned long len5 = pci_resource_len(dev, 5); + unsigned long barsize = pci_resource_len(dev, 5); u8 tmpbyte = 0; unsigned long addr; void *ioaddr; @@ -584,34 +814,37 @@ * spaces. */ - if(check_mem_region(bar5, len5)!=0) + if(!request_mem_region(bar5, barsize, name)) { printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n"); return 0; } - ioaddr = ioremap_nocache(bar5, len5); + ioaddr = ioremap(bar5, barsize); if (ioaddr == NULL) + { + release_mem_region(bar5, barsize); return 0; + } pci_set_master(dev); pci_set_drvdata(dev, ioaddr); addr = (unsigned long) ioaddr; - if (dev->device == PCI_DEVICE_ID_SII_3112) { - writel(0, DEVADDR(0x148)); - writel(0, DEVADDR(0x1C8)); + if (pdev_is_sata(dev)) { + writel(0, addr + 0x148); + writel(0, addr + 0x1C8); } - writeb(0, DEVADDR(0xB4)); - writeb(0, DEVADDR(0xF4)); - tmpbyte = readb(DEVADDR(0x4A)); + writeb(0, addr + 0xB4); + writeb(0, addr + 0xF4); + tmpbyte = readb(addr + 0x4A); switch(tmpbyte & 0x30) { case 0x00: /* In 100 MHz clocking, try and switch to 133 */ - writeb(tmpbyte|0x10, DEVADDR(0x4A)); + writeb(tmpbyte|0x10, addr + 0x4A); break; case 0x10: /* On 133Mhz clocking */ @@ -622,34 +855,43 @@ case 0x30: /* Clocking is disabled */ /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, DEVADDR(0x4A)); + writeb(tmpbyte & ~0x20, addr + 0x4A); break; } - writeb(0x72, DEVADDR(0xA1)); - writew(0x328A, DEVADDR(0xA2)); - writel(0x62DD62DD, DEVADDR(0xA4)); - writel(0x43924392, DEVADDR(0xA8)); - writel(0x40094009, DEVADDR(0xAC)); - writeb(0x72, DEVADDR(0xE1)); - writew(0x328A, DEVADDR(0xE2)); - writel(0x62DD62DD, DEVADDR(0xE4)); - writel(0x43924392, DEVADDR(0xE8)); - writel(0x40094009, DEVADDR(0xEC)); - - if (dev->device == PCI_DEVICE_ID_SII_3112) { - writel(0xFFFF0000, DEVADDR(0x108)); - writel(0xFFFF0000, DEVADDR(0x188)); - writel(0x00680000, DEVADDR(0x148)); - writel(0x00680000, DEVADDR(0x1C8)); + writeb( 0x72, addr + 0xA1); + writew( 0x328A, addr + 0xA2); + writel(0x62DD62DD, addr + 0xA4); + writel(0x43924392, addr + 0xA8); + writel(0x40094009, addr + 0xAC); + writeb( 0x72, addr + 0xE1); + writew( 0x328A, addr + 0xE2); + writel(0x62DD62DD, addr + 0xE4); + writel(0x43924392, addr + 0xE8); + writel(0x40094009, addr + 0xEC); + + if (pdev_is_sata(dev)) { + writel(0xFFFF0000, addr + 0x108); + writel(0xFFFF0000, addr + 0x188); + writel(0x00680000, addr + 0x148); + writel(0x00680000, addr + 0x1C8); } - tmpbyte = readb(DEVADDR(0x4A)); + tmpbyte = readb(addr + 0x4A); - proc_reports_siimage(dev, (tmpbyte>>=4), name); + proc_reports_siimage(dev, (tmpbyte>>4), name); return 1; } +/** + * init_chipset_siimage - set up an SI device + * @dev: PCI device + * @name: device name + * + * Perform the initial PCI set up for this device. Attempt to switch + * to 133MHz clocking if the system isn't already set up to do it. + */ + static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name) { u32 class_rev = 0; @@ -686,115 +928,134 @@ break; } - pci_read_config_byte(dev, 0x8A, &tmpbyte); - pci_write_config_byte(dev, 0xA1, 0x72); - pci_write_config_word(dev, 0xA2, 0x328A); + pci_read_config_byte(dev, 0x8A, &tmpbyte); + + pci_write_config_byte(dev, 0xA1, 0x72); + pci_write_config_word(dev, 0xA2, 0x328A); pci_write_config_dword(dev, 0xA4, 0x62DD62DD); pci_write_config_dword(dev, 0xA8, 0x43924392); pci_write_config_dword(dev, 0xAC, 0x40094009); - pci_write_config_byte(dev, 0xB1, 0x72); - pci_write_config_word(dev, 0xB2, 0x328A); + pci_write_config_byte(dev, 0xB1, 0x72); + pci_write_config_word(dev, 0xB2, 0x328A); pci_write_config_dword(dev, 0xB4, 0x62DD62DD); pci_write_config_dword(dev, 0xB8, 0x43924392); pci_write_config_dword(dev, 0xBC, 0x40094009); - pci_read_config_byte(dev, 0x8A, &tmpbyte); - proc_reports_siimage(dev, (tmpbyte>>=4), name); + proc_reports_siimage(dev, (tmpbyte>>4), name); return 0; } +/** + * init_mmio_iops_siimage - set up the iops for MMIO + * @hwif: interface to set up + * + * The basic setup here is fairly simple, we can use standard MMIO + * operations. However we do have to set the taskfile register offsets + * by hand as there isnt a standard defined layout for them this + * time. + * + * The hardware supports buffered taskfiles and also some rather nice + * extended PRD tables. Unfortunately right now we don't. + */ + static void __init init_mmio_iops_siimage (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; - unsigned long addr = (unsigned long) pci_get_drvdata(hwif->pci_dev); + void *addr = pci_get_drvdata(dev); u8 ch = hwif->channel; -// u16 i = 0; - hw_regs_t hw; + hw_regs_t hw; + unsigned long base; + + /* + * Fill in the basic HWIF bits + */ default_hwif_mmiops(hwif); + hwif->hwif_data = addr; + + /* + * Now set up the hw. We have to do this ourselves as + * the MMIO layout isnt the same as the the standard port + * based I/O + */ + memset(&hw, 0, sizeof(hw_regs_t)); + hw.priv = addr; -#if 1 -#ifdef SIIMAGE_BUFFERED_TASKFILE - hw.io_ports[IDE_DATA_OFFSET] = DEVADDR((ch) ? 0xD0 : 0x90); - hw.io_ports[IDE_ERROR_OFFSET] = DEVADDR((ch) ? 0xD1 : 0x91); - hw.io_ports[IDE_NSECTOR_OFFSET] = DEVADDR((ch) ? 0xD2 : 0x92); - hw.io_ports[IDE_SECTOR_OFFSET] = DEVADDR((ch) ? 0xD3 : 0x93); - hw.io_ports[IDE_LCYL_OFFSET] = DEVADDR((ch) ? 0xD4 : 0x94); - hw.io_ports[IDE_HCYL_OFFSET] = DEVADDR((ch) ? 0xD5 : 0x95); - hw.io_ports[IDE_SELECT_OFFSET] = DEVADDR((ch) ? 0xD6 : 0x96); - hw.io_ports[IDE_STATUS_OFFSET] = DEVADDR((ch) ? 0xD7 : 0x97); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A); -#else /* ! SIIMAGE_BUFFERED_TASKFILE */ - hw.io_ports[IDE_DATA_OFFSET] = DEVADDR((ch) ? 0xC0 : 0x80); - hw.io_ports[IDE_ERROR_OFFSET] = DEVADDR((ch) ? 0xC1 : 0x81); - hw.io_ports[IDE_NSECTOR_OFFSET] = DEVADDR((ch) ? 0xC2 : 0x82); - hw.io_ports[IDE_SECTOR_OFFSET] = DEVADDR((ch) ? 0xC3 : 0x83); - hw.io_ports[IDE_LCYL_OFFSET] = DEVADDR((ch) ? 0xC4 : 0x84); - hw.io_ports[IDE_HCYL_OFFSET] = DEVADDR((ch) ? 0xC5 : 0x85); - hw.io_ports[IDE_SELECT_OFFSET] = DEVADDR((ch) ? 0xC6 : 0x86); - hw.io_ports[IDE_STATUS_OFFSET] = DEVADDR((ch) ? 0xC7 : 0x87); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A); -#endif /* SIIMAGE_BUFFERED_TASKFILE */ -#else -#ifdef SIIMAGE_BUFFERED_TASKFILE - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A); -#else /* ! SIIMAGE_BUFFERED_TASKFILE */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i); - hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A); -#endif /* SIIMAGE_BUFFERED_TASKFILE */ -#endif + base = (unsigned long)addr; + if(ch) + base += 0xC0; + else + base += 0x80; -#if 0 - printk(KERN_DEBUG "%s: ", hwif->name); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i)); - printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i)); -#endif + /* + * The buffered task file doesn't have status/control + * so we can't currently use it sanely since we want to + * use LBA48 mode. + */ +// base += 0x10; +// hwif->addressing = 1; + + hw.io_ports[IDE_DATA_OFFSET] = base; + hw.io_ports[IDE_ERROR_OFFSET] = base + 1; + hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2; + hw.io_ports[IDE_SECTOR_OFFSET] = base + 3; + hw.io_ports[IDE_LCYL_OFFSET] = base + 4; + hw.io_ports[IDE_HCYL_OFFSET] = base + 5; + hw.io_ports[IDE_SELECT_OFFSET] = base + 6; + hw.io_ports[IDE_STATUS_OFFSET] = base + 7; + hw.io_ports[IDE_CONTROL_OFFSET] = base + 10; hw.io_ports[IDE_IRQ_OFFSET] = 0; - if (dev->device == PCI_DEVICE_ID_SII_3112) { - hw.sata_scr[SATA_STATUS_OFFSET] = DEVADDR((ch) ? 0x184 : 0x104); - hw.sata_scr[SATA_ERROR_OFFSET] = DEVADDR((ch) ? 0x188 : 0x108); - hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100); - hw.sata_misc[SATA_MISC_OFFSET] = DEVADDR((ch) ? 0x1C0 : 0x140); - hw.sata_misc[SATA_PHY_OFFSET] = DEVADDR((ch) ? 0x1C4 : 0x144); - hw.sata_misc[SATA_IEN_OFFSET] = DEVADDR((ch) ? 0x1C8 : 0x148); + if (pdev_is_sata(dev)) { + base = (unsigned long) addr; + if(ch) + base += 0x80; + hw.sata_scr[SATA_STATUS_OFFSET] = base + 0x104; + hw.sata_scr[SATA_ERROR_OFFSET] = base + 0x108; + hw.sata_scr[SATA_CONTROL_OFFSET]= base + 0x100; + hw.sata_misc[SATA_MISC_OFFSET] = base + 0x140; + hw.sata_misc[SATA_PHY_OFFSET] = base + 0x144; + hw.sata_misc[SATA_IEN_OFFSET] = base + 0x148; } - hw.priv = (void *) addr; -// hw.priv = pci_get_drvdata(hwif->pci_dev); hw.irq = hwif->pci_dev->irq; memcpy(&hwif->hw, &hw, sizeof(hw)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); - if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) { + if (is_sata(hwif)) { memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr)); memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc)); } -#ifdef SIIMAGE_BUFFERED_TASKFILE - hwif->addressing = 1; -#endif /* SIIMAGE_BUFFERED_TASKFILE */ hwif->irq = hw.irq; - hwif->hwif_data = pci_get_drvdata(hwif->pci_dev); + + base = (unsigned long) addr; #ifdef SIIMAGE_LARGE_DMA - hwif->dma_base = DEVADDR((ch) ? 0x18 : 0x10); - hwif->dma_base2 = DEVADDR((ch) ? 0x08 : 0x00); - hwif->dma_prdtable = (hwif->dma_base2 + 4); +/* Watch the brackets - even Ken and Dennis get some language design wrong */ + hwif->dma_base = base + (ch ? 0x18 : 0x10); + hwif->dma_base2 = base + (ch ? 0x08 : 0x00); + hwif->dma_prdtable = hwif->dma_base2 + 4; #else /* ! SIIMAGE_LARGE_DMA */ - hwif->dma_base = DEVADDR((ch) ? 0x08 : 0x00); - hwif->dma_base2 = DEVADDR((ch) ? 0x18 : 0x10); + hwif->dma_base = base + (ch ? 0x08 : 0x00); + hwif->dma_base2 = base + (ch ? 0x18 : 0x10); #endif /* SIIMAGE_LARGE_DMA */ hwif->mmio = 2; } +/** + * init_iops_siimage - set up iops + * @hwif: interface to set up + * + * Do the basic setup for the SIIMAGE hardware interface + * and then do the MMIO setup if we can. This is the first + * look in we get for setting up the hwif so that we + * can get the iops right before using them. + */ + static void __init init_iops_siimage (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; @@ -802,27 +1063,47 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; + + hwif->hwif_data = 0; hwif->rqsize = 128; - if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev))) - hwif->rqsize = 16; + if (is_sata(hwif)) + hwif->rqsize = 15; if (pci_get_drvdata(dev) == NULL) return; init_mmio_iops_siimage(hwif); } +/** + * ata66_siimage - check for 80 pin cable + * @hwif: interface to check + * + * Check for the presence of an ATA66 capable cable on the + * interface. + */ + static unsigned int __init ata66_siimage (ide_hwif_t *hwif) { + unsigned long addr = siimage_selreg(hwif, 0); if (pci_get_drvdata(hwif->pci_dev) == NULL) { u8 ata66 = 0; - pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66); + pci_read_config_byte(hwif->pci_dev, addr, &ata66); return (ata66 & 0x01) ? 1 : 0; } - return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0; + return (hwif->INB(addr) & 0x01) ? 1 : 0; } +/** + * init_hwif_siimage - set up hwif structs + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The SIIMAGE + * requires several custom handlers so we override the default + * ide DMA handlers appropriately + */ + static void __init init_hwif_siimage (ide_hwif_t *hwif) { hwif->autodma = 0; @@ -833,7 +1114,7 @@ hwif->reset_poll = &siimage_reset_poll; hwif->pre_reset = &siimage_pre_reset; - if(hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) + if(is_sata(hwif)) hwif->busproc = &siimage_busproc; if (!hwif->dma_base) { @@ -846,7 +1127,7 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112) + if (!is_sata(hwif)) hwif->atapi_dma = 1; hwif->ide_dma_check = &siimage_config_drive_for_dma; @@ -860,12 +1141,26 @@ } else { hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq; } - if (!noautodma) - hwif->autodma = 1; + + /* + * The BIOS often doesn't set up DMA on this controller + * so we always do it. + */ + + hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; } +/** + * init_dma_siimage - set up IDE DMA + * @hwif: interface + * @dmabase: DMA base address to use + * + * For the SI chips this requires no special set up so we can just + * let the IDE DMA core do the usual work. + */ + static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase) { ide_setup_dma(hwif, dmabase, 8); @@ -874,6 +1169,15 @@ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *); +/** + * siimage_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an SI680 or SI3112 controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) { ide_pci_device_t *d = &siimage_chipsets[id->driver_data]; @@ -887,6 +1191,7 @@ static struct pci_device_id siimage_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, { 0, }, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/siimage.h linux.21-ac4/drivers/ide/pci/siimage.h --- linux.vanilla/drivers/ide/pci/siimage.h 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/siimage.h 2003-06-27 17:13:09.000000000 +0100 @@ -13,12 +13,6 @@ #undef SIIMAGE_BUFFERED_TASKFILE #undef SIIMAGE_LARGE_DMA -#if 0 -typedef struct ide_io_ops_s siimage_iops { - -} -#endif - #define SII_DEBUG 0 #if SII_DEBUG @@ -27,12 +21,6 @@ #define siiprintk(x...) #endif -#define ADJREG(B,R) ((B)|(R)|((hwif->channel)<<(4+(2*(!!hwif->mmio))))) -#define SELREG(R) ADJREG((0xA0),(R)) -#define SELADDR(R) ((((unsigned long)hwif->hwif_data)*(!!hwif->mmio))|SELREG((R))) -#define HWIFADDR(R) ((((unsigned long)hwif->hwif_data)*(!!hwif->mmio))|(R)) -#define DEVADDR(R) (((unsigned long) pci_get_drvdata(dev))|(R)) - #if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -85,6 +73,19 @@ .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, .extra = 0, + },{ /* 2 */ + .vendor = PCI_VENDOR_ID_CMD, + .device = PCI_DEVICE_ID_SII_1210SA, + .name = "Adaptec AAR-1210SA", + .init_chipset = init_chipset_siimage, + .init_iops = init_iops_siimage, + .init_hwif = init_hwif_siimage, + .init_dma = init_dma_siimage, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, + .bootable = ON_BOARD, + .extra = 0, },{ .vendor = 0, .device = 0, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/pci/sis5513.c linux.21-ac4/drivers/ide/pci/sis5513.c --- linux.vanilla/drivers/ide/pci/sis5513.c 2003-06-14 00:11:31.000000000 +0100 +++ linux.21-ac4/drivers/ide/pci/sis5513.c 2003-06-22 13:51:39.000000000 +0100 @@ -1,8 +1,9 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.14ac Sept 11, 2002 + * linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer + * Copyright (C) 2003 Vojtech Pavlik * May be copied or modified under the terms of the GNU General Public License * * @@ -14,31 +15,33 @@ * for checking code correctness, providing patches. * * - * Original tests and design on the SiS620/5513 chipset. - * ATA100 tests and design on the SiS735/5513 chipset. + * Original tests and design on the SiS620 chipset. + * ATA100 tests and design on the SiS735 chipset. * ATA16/33 support from specs * ATA133 support for SiS961/962 by L.C. Chang + * ATA133 961/962/963 fixes by Vojtech Pavlik * * Documentation: - * SiS chipset documentation available under NDA to companies not - * individuals only. + * SiS chipset documentation available under NDA to companies only + * (not to individuals). */ /* - * Notes/Special cases: - * - SiS5513 derivatives usually have the same PCI IDE register layout when - * supporting the same UDMA modes. - * - There are exceptions : - * . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support - * ATA_100 - * . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously - * south and northbridge were integrated, making IDE (a southbridge function) - * capabilities easily deduced from the northbridge PCI id. With ATA_133, - * chipsets started to be split in the usual north/south bridges chips - * -> the driver needs to detect the correct southbridge when faced to newest - * northbridges. - * . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the - * configuration space is moved from 0x40 to 0x70. + * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original + * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511 + * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip. + * + * Later SiS chipsets integrated the 5513 functionality into the NorthBridge, + * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We + * can figure out that we have a more modern and more capable 5513 by looking + * for the respective NorthBridge IDs. + * + * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513 + * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI + * ID, while the now ATA-133 capable 5513 still has the same PCI ID. + * Fortunately the 5513 can be 'unmasked' by fiddling with some config space + * bits, changing its device id to the true one - 5517 for 961 and 5518 for + * 962/963. */ #include @@ -57,94 +60,23 @@ #include #include -#include #include +#include "ide-timing.h" #include "ide_modes.h" #include "sis5513.h" -/* When DEBUG is defined it outputs initial PCI config register - values and changes made to them by the driver */ -// #define DEBUG -/* When BROKEN_LEVEL is defined it limits the DMA mode - at boot time to its value */ -// #define BROKEN_LEVEL XFER_SW_DMA_0 - -/* Miscellaneous flags */ -#define SIS5513_LATENCY 0x01 - /* registers layout and init values are chipset family dependant */ -/* 1/ define families */ -#define ATA_00 0x00 + #define ATA_16 0x01 #define ATA_33 0x02 #define ATA_66 0x03 -#define ATA_100a 0x04 // SiS730 is ATA100 with ATA66 layout +#define ATA_100a 0x04 // SiS730/SiS550 is ATA100 with ATA66 layout #define ATA_100 0x05 #define ATA_133a 0x06 // SiS961b with 133 support -#define ATA_133 0x07 // SiS962 -/* 2/ variable holding the controller chipset family value */ -static u8 chipset_family; - - -/* - * Debug code: following IDE config registers' changes - */ -#ifdef DEBUG -/* Copy of IDE Config registers fewer will be used - * Some odd chipsets hang if unused registers are accessed - * -> We only access them in #DEBUG code (then we'll see if SiS did - * it right from day one) */ -static u8 ide_regs_copy[0xff]; - -/* Read config registers, print differences from previous read */ -static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) { - int i; - u8 reg_val; - u8 changed=0; - - printk("SIS5513: %s, changed registers:\n", info); - for(i=0; i<=0xff; i++) { - pci_read_config_byte(dev, i, ®_val); - if (reg_val != ide_regs_copy[i]) { - printk("%02x: %02x -> %02x\n", - i, ide_regs_copy[i], reg_val); - ide_regs_copy[i]=reg_val; - changed=1; - } - } - - if (!changed) { - printk("none\n"); - } -} - -/* Load config registers, no printing */ -static void sis5513_load_registers(struct pci_dev* dev) { - int i; - - for(i=0; i<=0xff; i++) { - pci_read_config_byte(dev, i, &(ide_regs_copy[i])); - } -} - -/* Print config space registers a la "lspci -vxxx" */ -static void sis5513_print_registers(struct pci_dev* dev, char* marker) { - int i,j; - - sis5513_load_registers(dev); - printk("SIS5513 %s\n", marker); - - for(i=0; i<=0xf; i++) { - printk("SIS5513 dump: %d" "0:", i); - for(j=0; j<=0xf; j++) { - printk(" %02x", ide_regs_copy[(i<<16)+j]); - } - printk("\n"); - } -} -#endif +#define ATA_133 0x07 // SiS962/963 +static u8 chipset_family; /* * Devices supported @@ -155,41 +87,38 @@ u8 chipset_family; u8 flags; } SiSHostChipInfo[] = { - { "SiS752", PCI_DEVICE_ID_SI_752, ATA_133, 0 }, - { "SiS751", PCI_DEVICE_ID_SI_751, ATA_133, 0 }, - { "SiS750", PCI_DEVICE_ID_SI_750, ATA_133, 0 }, - { "SiS748", PCI_DEVICE_ID_SI_748, ATA_133, 0 }, - { "SiS746", PCI_DEVICE_ID_SI_746, ATA_133, 0 }, - { "SiS745", PCI_DEVICE_ID_SI_745, ATA_133, 0 }, - { "SiS740", PCI_DEVICE_ID_SI_740, ATA_100, 0 }, - { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100, SIS5513_LATENCY }, - { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a, SIS5513_LATENCY }, - { "SiS652", PCI_DEVICE_ID_SI_652, ATA_133, 0 }, - { "SiS651", PCI_DEVICE_ID_SI_651, ATA_133, 0 }, - { "SiS650", PCI_DEVICE_ID_SI_650, ATA_133, 0 }, - { "SiS648", PCI_DEVICE_ID_SI_648, ATA_133, 0 }, - { "SiS646", PCI_DEVICE_ID_SI_646, ATA_133, 0 }, - { "SiS645", PCI_DEVICE_ID_SI_645, ATA_133, 0 }, - { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100, SIS5513_LATENCY }, - { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66, SIS5513_LATENCY }, - { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66, SIS5513_LATENCY }, - { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66, SIS5513_LATENCY }, - { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a, 0}, - { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66, 0}, - { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66, 0}, - { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33, 0}, - { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33, 0}, - { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33, 0}, - { "SiS5591", PCI_DEVICE_ID_SI_5591, ATA_33, 0}, - { "SiS5513", PCI_DEVICE_ID_SI_5513, ATA_16, 0}, - { "SiS5511", PCI_DEVICE_ID_SI_5511, ATA_16, 0}, + { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 }, + { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 }, + { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 }, + { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 }, + { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 }, + + { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a }, + { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a }, + + { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 }, + { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 }, + { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 }, + { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 }, + { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 }, + + { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 }, + { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 }, + { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 }, + { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 }, + { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 }, + { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 }, + + { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 }, + { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 }, + { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 }, }; /* Cycle time bits and values vary across chip dma capabilities These three arrays hold the register layout and the values to set. Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ -/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ +/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ static u8 cycle_time_offset[] = {0,0,5,4,4,0,0}; static u8 cycle_time_range[] = {0,0,2,3,3,4,4}; static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { @@ -248,8 +177,6 @@ {40,12,4,12,5,34,12,5}, }; -static struct pci_dev *host_dev = NULL; - /* * Printing configuration */ @@ -257,8 +184,8 @@ static char* chipset_capability[] = { "ATA", "ATA 16", "ATA 33", "ATA 66", - "ATA 100", "ATA 100", - "ATA 133", "ATA 133" + "ATA 100 (1st gen)", "ATA 100 (2nd gen)", + "ATA 133 (1st gen)", "ATA 133 (2nd gen)" }; #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) @@ -331,8 +258,9 @@ // Configuration space remapped to 0x70 drive_pci = 0x70; } - pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos, ®dw0); - pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos+4, ®dw1); + pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos, ®dw0); + pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos+8, ®dw1); + p += sprintf(p, "Drive %d:\n", pos); } @@ -357,8 +285,7 @@ case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break; case ATA_100: case ATA_133a: p += sprintf(p, cycle_time[reg01 & 0x0F]); break; - case ATA_133: - default: p += sprintf(p, "133+ ?"); break; + default: p += sprintf(p, "?"); break; } p += sprintf(p, " \t UDMA Cycle Time "); switch(chipset_family) { @@ -367,42 +294,39 @@ case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break; case ATA_100: case ATA_133a: p += sprintf(p, cycle_time[reg11 & 0x0F]); break; - case ATA_133: - default: p += sprintf(p, "133+ ?"); break; + default: p += sprintf(p, "?"); break; } p += sprintf(p, "\n"); } + + if (chipset_family < ATA_133) { /* else case TODO */ + /* Data Active */ - p += sprintf(p, " Data Active Time "); - switch(chipset_family) { - case ATA_00: - case ATA_16: /* confirmed */ - case ATA_33: - case ATA_66: - case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break; - case ATA_100: - case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break; - case ATA_133: - default: p += sprintf(p, "133+ ?"); break; - } - p += sprintf(p, " \t Data Active Time "); - switch(chipset_family) { - case ATA_00: - case ATA_16: - case ATA_33: - case ATA_66: - case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break; - case ATA_100: - case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break; - case ATA_133: - default: p += sprintf(p, "133+ ?"); break; - } - p += sprintf(p, "\n"); + p += sprintf(p, " Data Active Time "); + switch(chipset_family) { + case ATA_16: /* confirmed */ + case ATA_33: + case ATA_66: + case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break; + case ATA_100: + case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break; + default: p += sprintf(p, "?"); break; + } + p += sprintf(p, " \t Data Active Time "); + switch(chipset_family) { + case ATA_16: + case ATA_33: + case ATA_66: + case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break; + case ATA_100: + case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break; + default: p += sprintf(p, "?"); break; + } + p += sprintf(p, "\n"); /* Data Recovery */ /* warning: may need (reg&0x07) for pre ATA66 chips */ - if (chipset_family < ATA_133) { p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]); } @@ -430,7 +354,6 @@ p += sprintf(p, "\nSiS 5513 "); switch(chipset_family) { - case ATA_00: p += sprintf(p, "Unknown???"); break; case ATA_16: p += sprintf(p, "DMA 16"); break; case ATA_33: p += sprintf(p, "Ultra 33"); break; case ATA_66: p += sprintf(p, "Ultra 66"); break; @@ -497,39 +420,16 @@ len = (p - buffer) - offset; *addr = buffer + offset; - + return len > count ? count : len; } #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ static u8 sis5513_ratemask (ide_drive_t *drive) { -#if 0 u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 }; u8 mode = rates[chipset_family]; -#else - u8 mode; - switch(chipset_family) { - case ATA_133: - case ATA_133a: - mode = 4; - break; - case ATA_100: - case ATA_100a: - mode = 3; - break; - case ATA_66: - mode = 2; - break; - case ATA_33: - return 1; - case ATA_16: - case ATA_00: - default: - return 0; - } -#endif if (!eighty_ninty_three(drive)) mode = min(mode, (u8)1); return mode; @@ -547,20 +447,12 @@ u8 reg4bh = 0; u8 rw_prefetch = (0x11 << drive->dn); -#ifdef DEBUG - printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn); - sis5513_load_verify_registers(dev, "config_drive_art_rwp start"); -#endif - if (drive->media != ide_disk) return; pci_read_config_byte(dev, 0x4b, ®4bh); if ((reg4bh & rw_prefetch) != rw_prefetch) pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp end"); -#endif } @@ -575,10 +467,6 @@ u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; u16 xfer_pio = drive->id->eide_pio_modes; -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); -#endif - config_drive_art_rwp(drive); pio = ide_get_best_pio_mode(drive, 255, pio, NULL); @@ -598,12 +486,6 @@ timing = (xfer_pio >= pio) ? xfer_pio : pio; -#ifdef DEBUG - printk("SIS5513: config_drive_art_rwp_pio, " - "drive %d, pio %d, timing %d\n", - drive->dn, pio, timing); -#endif - /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ drive_pci = 0x40; /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */ @@ -649,41 +531,24 @@ pci_read_config_dword(dev, drive_pci, &test3); test3 &= 0xc0c00fff; if (test3 & 0x08) { - test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24; + test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; } else { - test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24; + test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; } pci_write_config_dword(dev, drive_pci, test3); } - -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); -#endif } static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) { -#if 0 + if (pio == 255) + pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, (XFER_PIO_0 + pio)); -#else - u8 speed; - - switch(pio) { - case 4: speed = XFER_PIO_4; break; - case 3: speed = XFER_PIO_3; break; - case 2: speed = XFER_PIO_2; break; - case 1: speed = XFER_PIO_1; break; - default: speed = XFER_PIO_0; break; - } - - config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, speed); -#endif + return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4)); } static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) @@ -694,24 +559,8 @@ u8 drive_pci, reg, speed; u32 regdw; -#ifdef DEBUG - sis5513_load_verify_registers(dev, "sis5513_tune_chipset start"); -#endif - -#ifdef BROKEN_LEVEL -#ifdef DEBUG - printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL); -#endif - if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL; -#endif - speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed); -#ifdef DEBUG - printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n", - drive->dn, xferspeed); -#endif - /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { @@ -750,14 +599,14 @@ regdw &= 0xfffff00f; /* check if ATA133 enable */ if (regdw & 0x08) { - regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8; + regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; } else { /* if ATA133 disable, we should not set speed above UDMA5 */ if (speed > XFER_UDMA_5) speed = XFER_UDMA_5; - regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8; + regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; } pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); } else { @@ -767,7 +616,7 @@ reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) << cycle_time_offset[chipset_family]); /* set reg cycle time bits */ - reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0] + reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0] << cycle_time_offset[chipset_family]; pci_write_config_byte(dev, drive_pci+1, reg); } @@ -786,9 +635,7 @@ case XFER_PIO_0: default: return((int) config_chipset_for_pio(drive, 0)); } -#ifdef DEBUG - sis5513_load_verify_registers(dev, "sis5513_tune_chipset end"); -#endif + return ((int) ide_config_drive_speed(drive, speed)); } @@ -867,71 +714,121 @@ return sis5513_config_drive_xfer_rate(drive); } +/* + Future simpler config_xfer_rate : + When ide_find_best_mode is made bad-drive aware + - remove config_drive_xfer_rate and config_chipset_for_dma, + - replace config_xfer_rate with the following + +static int sis5513_config_xfer_rate (ide_drive_t *drive) +{ + u16 w80 = HWIF(drive)->udma_four; + u16 speed; + + config_drive_art_rwp(drive); + config_art_rwp_pio(drive, 5); + + speed = ide_find_best_mode(drive, + XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | + (chipset_family >= ATA_33 ? XFER_UDMA : 0) | + (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | + (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | + (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); + + sis5513_tune_chipset(drive, speed); + + if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) + return HWIF(drive)->ide_dma_on(drive); + return HWIF(drive)->ide_dma_off_quietly(drive); +} +*/ + /* Chip detection and general config */ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name) { struct pci_dev *host; int i = 0; - /* Find the chip */ - for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) { - host = pci_find_device (PCI_VENDOR_ID_SI, - SiSHostChipInfo[i].host_id, - NULL); + chipset_family = 0; + + for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { + + host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); + if (!host) continue; - host_dev = host; chipset_family = SiSHostChipInfo[i].chipset_family; + + /* Special case for SiS630 : 630S/ET is ATA_100a */ + if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { + u8 hostrev; + pci_read_config_byte(host, PCI_REVISION_ID, &hostrev); + if (hostrev >= 0x30) + chipset_family = ATA_100a; + } - /* check 100/133 chipset family */ - if (chipset_family == ATA_133) { - u32 reg54h; - u16 reg02h; - pci_read_config_dword(dev, 0x54, ®54h); - pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff)); - pci_read_config_word(dev, 0x02, ®02h); - pci_write_config_dword(dev, 0x54, reg54h); - /* devid 5518 here means SiS962 or later - which supports ATA133 */ - if (reg02h != 0x5518) { - u8 reg49h; - unsigned long sbrev; - /* SiS961 family */ - - /* - * FIXME !!! GAK!!!!!!!!!! PCI DIRECT POKING - */ - outl(0x80001008, 0x0cf8); - sbrev = inl(0x0cfc); + printk(KERN_INFO "SIS5513: %s %s controller\n", + SiSHostChipInfo[i].name, chipset_capability[chipset_family]); + } - pci_read_config_byte(dev, 0x49, ®49h); - if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80)) - chipset_family = ATA_133a; - else - chipset_family = ATA_100; + if (!chipset_family) { /* Belongs to pci-quirks */ + + u32 idemisc; + u16 trueid; + + /* Disable ID masking and register remapping */ + pci_read_config_dword(dev, 0x54, &idemisc); + pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_dword(dev, 0x54, idemisc); + + if (trueid == 0x5518) { + printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); + chipset_family = ATA_133; } - } - printk(SiSHostChipInfo[i].name); - printk(" %s controller", chipset_capability[chipset_family]); - printk("\n"); + } -#ifdef DEBUG - sis5513_print_registers(dev, "pci_init_sis5513 start"); -#endif + if (!chipset_family) { /* Belongs to pci-quirks */ - if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) { - u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); - } + struct pci_dev *lpc_bridge; + u16 trueid; + u8 prefctl; + u8 idecfg; + u8 sbrev; + + pci_read_config_byte(dev, 0x4a, &idecfg); + pci_write_config_byte(dev, 0x4a, idecfg | 0x10); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_byte(dev, 0x4a, idecfg); + + if (trueid == 0x5517) { /* SiS 961/961B */ + + lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */ + pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev); + pci_read_config_byte(dev, 0x49, &prefctl); + + if (sbrev == 0x10 && (prefctl & 0x80)) { + printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n"); + chipset_family = ATA_133a; + } else { + printk(KERN_INFO "SIS5513: SiS 961 MuTIOL IDE UDMA100 controller\n"); + chipset_family = ATA_100; + } + } } + if (!chipset_family) + return -1; + /* Make general config ops here 1/ tell IDE channels to operate in Compatibility mode only 2/ tell old chips to allow per drive IDE timings */ - if (host_dev) { + + { u8 reg; u16 regw; + switch(chipset_family) { case ATA_133: /* SiS962 operation mode */ @@ -944,6 +841,8 @@ break; case ATA_133a: case ATA_100: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); /* Set compatibility bit */ pci_read_config_byte(dev, 0x49, ®); if (!(reg & 0x01)) { @@ -952,6 +851,9 @@ break; case ATA_100a: case ATA_66: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + /* On ATA_66 chips the bit was elsewhere */ pci_read_config_byte(dev, 0x52, ®); if (!(reg & 0x04)) { @@ -972,8 +874,6 @@ pci_write_config_byte(dev, 0x52, reg|0x08); } break; - case ATA_00: - default: break; } #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) @@ -984,9 +884,7 @@ } #endif } -#ifdef DEBUG - sis5513_load_verify_registers(dev, "pci_init_sis5513 end"); -#endif + return 0; } @@ -1029,7 +927,7 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (!host_dev) + if (!chipset_family) return; if (!(hwif->udma_four)) @@ -1087,7 +985,7 @@ module_init(sis5513_ide_init); module_exit(sis5513_ide_exit); -MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick"); +MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik"); MODULE_DESCRIPTION("PCI driver module for SIS IDE"); MODULE_LICENSE("GPL"); @@ -1095,13 +993,10 @@ /* * TODO: - * - Get ridden of SisHostChipInfo[] completness dependancy. - * - Study drivers/ide/ide-timing.h. - * - Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them - * or remove ATA_00 define + * - CLEANUP + * - Use drivers/ide/ide-timing.h ! * - More checks in the config registers (force values instead of * relying on the BIOS setting them correctly). * - Further optimisations ? * . for example ATA66+ regs 0x48 & 0x4A */ - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ide/raid/hptraid.c linux.21-ac4/drivers/ide/raid/hptraid.c --- linux.vanilla/drivers/ide/raid/hptraid.c 2003-06-14 00:11:32.000000000 +0100 +++ linux.21-ac4/drivers/ide/raid/hptraid.c 2003-06-22 14:13:46.000000000 +0100 @@ -17,7 +17,30 @@ Copyright (C) 1994-96 Marc ZYNGIER Based on work done by Søren Schmidt for FreeBSD - + Changelog: + 15.06.2003 wweissmann@gmx.at + * correct values of raid-1 superbock + * re-add check for availability of all disks + * fix offset bug in raid-1 (introduced in raid 0+1 implementation) + + 14.06.2003 wweissmann@gmx.at + * superblock has wrong "disks" value on raid-1 + * fixup for raid-1 disknumbering + * do _NOT_ align size to 255*63 boundary + I WILL NOT USE FDISK TO DETERMINE THE VOLUME SIZE. + I WILL NOT USE FDISK TO DETERMINE THE VOLUME SIZE. + I WILL NOT USE FDISK TO DETERMINE THE VOLUME SIZE. + I WILL NOT ... + + 13.06.2003 wweissmann@gmx.at + * raid 0+1 support + * check if all disks of an array are available + * bump version number + + 29.05.2003 wweissmann@gmx.at + * release no more devices than available on unload + * remove static variables in raid-1 read path + */ #include @@ -34,6 +57,8 @@ #include #include "ataraid.h" +#include "hptraid.h" + static int hptraid_open(struct inode * inode, struct file * filp); static int hptraid_release(struct inode * inode, struct file * filp); @@ -41,26 +66,30 @@ static int hptraidspan_make_request (request_queue_t *q, int rw, struct buffer_head * bh); static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh); static int hptraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh); +static int hptraid01_make_request (request_queue_t *q, int rw, struct buffer_head * bh); struct hptdisk { - kdev_t device; + kdev_t device; /* disk-ID/raid 0+1 volume-ID */ unsigned long sectors; struct block_device *bdev; unsigned long last_pos; }; struct hptraid { - unsigned int stride; - unsigned int disks; - unsigned long sectors; + unsigned int stride; /* stripesize */ + unsigned int disks; /* number of disks in array */ + unsigned long sectors; /* disksize in sectors */ u_int32_t magic_0; + u_int32_t magic_1; struct geom geom; + int previous; /* most recently accessed disk in mirror */ struct hptdisk disk[8]; - unsigned long cutoff[8]; + unsigned long cutoff[8]; /* raid 0 cutoff */ unsigned int cutoff_disks[8]; + struct hptraid * raid01; /* sub arrays for raid 0+1 */ }; struct hptraid_dev { @@ -109,9 +138,30 @@ make_request: hptraid1_make_request }; + +static struct raid_device_operations hptraid01_ops = { + open: hptraid_open, + release: hptraid_release, + ioctl: hptraid_ioctl, + make_request: hptraid01_make_request +}; + +static __init struct { + struct raid_device_operations *op; + u_int8_t type; + char label[8]; +} oplist[] = { + {&hptraid0_ops, HPT_T_RAID_0, "RAID 0"}, + {&hptraid1_ops, HPT_T_RAID_1, "RAID 1"}, + {&hptraidspan_ops, HPT_T_SPAN, "SPAN"}, + {&hptraid01_ops, HPT_T_RAID_01_RAID_0, "RAID 0+1"}, + {0, 0} +}; + static struct hptraid raid[14]; -static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int hptraid_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { unsigned int minor; unsigned char val; @@ -185,7 +235,10 @@ device = (bh->b_rdev >> SHIFT)&MAJOR_MASK; thisraid = &raid[device]; - /* Partitions need adding of the start sector of the partition to the requested sector */ + /* + * Partitions need adding of the start sector of the partition to the + * requested sector + */ rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; @@ -216,58 +269,58 @@ return 1; } -static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +static int hptraid0_compute_request (struct hptraid *thisraid, + request_queue_t *q, + int rw, struct buffer_head * bh) { - unsigned long rsect; unsigned long rsect_left,rsect_accum = 0; unsigned long block; unsigned int disk=0,real_disk=0; int i; - int device; - struct hptraid *thisraid; - - rsect = bh->b_rsector; - /* Ok. We need to modify this sector number to a new disk + new sector number. + /* Ok. We need to modify this sector number to a new disk + new sector + * number. * If there are disks of different sizes, this gets tricky. * Example with 3 disks (1Gb, 4Gb and 5 GB): * The first 3 Gb of the "RAID" are evenly spread over the 3 disks. - * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3 - * and the last 1Gb is disk 3 only. + * Then things get interesting. The next 2Gb (RAID view) are spread + * across disk 2 and 3 and the last 1Gb is disk 3 only. * - * the way this is solved is like this: We have a list of "cutoff" points where everytime - * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff - * point, we have to divide by one less. + * the way this is solved is like this: We have a list of "cutoff" + * points where everytime a disk falls out of the "higher" count, we + * mark the max sector. So once we pass a cutoff point, we have to + * divide by one less. */ - device = (bh->b_rdev >> SHIFT)&MAJOR_MASK; - thisraid = &raid[device]; if (thisraid->stride==0) thisraid->stride=1; - /* Partitions need adding of the start sector of the partition to the requested sector */ - - rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; - - /* Woops we need to split the request to avoid crossing a stride barrier */ - if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) { + /* + * Woops we need to split the request to avoid crossing a stride + * barrier + */ + if ((bh->b_rsector/thisraid->stride) != + ((bh->b_rsector+(bh->b_size/512)-1)/thisraid->stride)) { return -1; } - rsect_left = rsect; + rsect_left = bh->b_rsector;; for (i=0;i<8;i++) { if (thisraid->cutoff_disks[i]==0) break; - if (rsect > thisraid->cutoff[i]) { + if (bh->b_rsector > thisraid->cutoff[i]) { /* we're in the wrong area so far */ rsect_left -= thisraid->cutoff[i]; - rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i]; + rsect_accum += thisraid->cutoff[i] / + thisraid->cutoff_disks[i]; } else { block = rsect_left / thisraid->stride; disk = block % thisraid->cutoff_disks[i]; - block = (block / thisraid->cutoff_disks[i]) * thisraid->stride; - rsect = rsect_accum + (rsect_left % thisraid->stride) + block; + block = (block / thisraid->cutoff_disks[i]) * + thisraid->stride; + bh->b_rsector = rsect_accum + + (rsect_left % thisraid->stride) + block; break; } } @@ -286,7 +339,7 @@ /* All but the first disk have a 10 sector offset */ if (i>0) - rsect+=10; + bh->b_rsector+=10; /* @@ -295,7 +348,6 @@ */ bh->b_rdev = thisraid->disk[disk].device; - bh->b_rsector = rsect; /* * Let the main block layer submit the IO and resolve recursion: @@ -303,12 +355,39 @@ return 1; } +static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +{ + unsigned long rsect; + int device; + + /* + * save the sector, it must be restored before a request-split + * is performed + */ + rsect = bh->b_rsector; + + /* + * Partitions need adding of the start sector of the partition to the + * requested sector + */ + + bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; + + device = (bh->b_rdev >> SHIFT)&MAJOR_MASK; + if( hptraid0_compute_request(raid+device, q, rw, bh) != 1 ) { + /* request must be split => restore sector */ + bh->b_rsector = rsect; + return -1; + } + + return 1; +} + static int hptraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh) { int device; int dist; int bestsofar,bestdist,i; - static int previous; /* Reads are simple in principle. Pick a disk and go. Initially I cheat by just picking the one which the last known @@ -331,11 +410,15 @@ dist = -dist; if (dist>4095) dist=4095; - - if (bestdist==dist) { /* it's a tie; try to do some read balancing */ - if ((previous>bestsofar)&&(previous<=i)) + + /* it's a tie; try to do some read balancing */ + if (bestdist==dist) { + if ( (raid[device].previous>bestsofar) && + (raid[device].previous<=i) ) bestsofar = i; - previous = (previous + 1) % raid[device].disks; + raid[device].previous = + (raid[device].previous + 1) % + raid[device].disks; } else if (bestdist>dist) { bestdist = dist; bestsofar = i; @@ -343,7 +426,6 @@ } - bh->b_rsector += bestsofar?10:0; bh->b_rdev = raid[device].disk[bestsofar].device; raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9); @@ -377,24 +459,49 @@ if (!bh1) BUG(); - /* dupe the bufferhead and update the parts that need to be different */ + /* + * dupe the bufferhead and update the parts that need to be + * different + */ memcpy(bh1, bh, sizeof(*bh)); bh1->b_end_io = ataraid_end_request; bh1->b_private = private; - bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect+(i==0?0:10); /* partition offset */ + bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */ bh1->b_rdev = raid[device].disk[i].device; /* update the last known head position for the drive */ raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9); + if( raid[device].raid01 ) { + if( hptraid0_compute_request( + raid[device].raid01 + + (bh1->b_rdev-1), + q, rw, bh1) != 1 ) { + /* + * If a split is requested then it is requested + * in the first iteration. This is true because + * of the cutoff is not used in raid 0+1. + */ + if(unlikely(i)) { + BUG(); + } + else { + kfree(private); + return -1; + } + } + } generic_make_request(rw,bh1); } return 0; } static int hptraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - /* Read and Write are totally different cases; split them totally here */ + /* + * Read and Write are totally different cases; split them totally + * here + */ if (rw==READA) rw = READ; @@ -404,7 +511,43 @@ return hptraid1_write_request(q,rw,bh); } -#include "hptraid.h" +static int hptraid01_read_request (request_queue_t *q, int rw, struct buffer_head * bh) +{ + int rsector=bh->b_rsector; + int rdev=bh->b_rdev; + + /* select mirror volume */ + hptraid1_read_request(q, rw, bh); + + /* stripe volume is selected by "bh->b_rdev" */ + if( hptraid0_compute_request( + raid[(bh->b_rdev >> SHIFT)&MAJOR_MASK]. + raid01 + (bh->b_rdev-1) , + q, rw, bh) != 1 ) { + + /* request must be split => restore sector and device */ + bh->b_rsector = rsector; + bh->b_rdev = rdev; + return -1; + + } + + return 1; +} + +static int hptraid01_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { + /* + * Read and Write are totally different cases; split them totally + * here + */ + if (rw==READA) + rw = READ; + + if (rw==READ) + return hptraid01_read_request(q,rw,bh); + else + return hptraid1_write_request(q,rw,bh); +} static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize) { @@ -456,77 +599,140 @@ return lba; } -static void __init probedisk(struct hptraid_dev *disk, int device, u_int8_t type) +static void writeentry(struct hptraid * raid, struct hptraid_dev * disk, + int index, struct highpoint_raid_conf * prom) { + + int j=0; + struct gendisk *gd; + struct block_device *bdev; + + bdev = bdget(MKDEV(disk->major,disk->minor)); + if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) { + raid->disk[index].bdev = bdev; + /* + * This is supposed to prevent others from stealing our + * underlying disks now blank the /proc/partitions table for + * the wrong partition table, so that scripts don't + * accidentally mount it and crash the kernel + */ + /* XXX: the 0 is an utter hack --hch */ + gd=get_gendisk(MKDEV(disk->major, 0)); + if (gd!=NULL) { + if (gd->major==disk->major) + for (j=1+(disk->minor<minor_shift); + j<((disk->minor+1)<minor_shift); + j++) gd->part[j].nr_sects=0; + } + } + raid->disk[index].device = MKDEV(disk->major,disk->minor); + raid->disk[index].sectors = maxsectors(disk->major,disk->minor); + raid->stride = (1<raid0_shift); + raid->disks = prom->raid_disks; + raid->sectors = prom->total_secs; + raid->sectors += raid->sectors&1?1:0; + raid->magic_0=prom->magic_0; + raid->magic_1=prom->magic_1; + +} + +static int probedisk(struct hptraid_dev *disk, int device, u_int8_t type) { - int i; + int i, j; struct highpoint_raid_conf *prom; static unsigned char block[4096]; - struct block_device *bdev; if (disk->device != -1) /* disk is occupied? */ - return; + return 0; if (maxsectors(disk->major,disk->minor)==0) - return; + return 0; if (read_disk_sb(disk->major,disk->minor,(unsigned char*)&block,sizeof(block))) - return; + return 0; prom = (struct highpoint_raid_conf*)&block[512]; if (prom->magic!= 0x5a7816f0) - return; + return 0; switch (prom->type) { case HPT_T_SPAN: case HPT_T_RAID_0: case HPT_T_RAID_1: + case HPT_T_RAID_01_RAID_0: if(prom->type != type) - return; + return 0; break; default: - printk(KERN_INFO "hptraid: only SPAN, RAID0 and RAID1 is currently supported \n"); - return; + printk(KERN_INFO "hptraid: unknown raid level-id %i\n", + prom->type); + return 0; } /* disk from another array? */ - if(raid[device].disks && prom->magic_0 != raid[device].magic_0) - return; + if (raid[device].disks) { /* only check if raid is not empty */ + if (type == HPT_T_RAID_01_RAID_0 ) { + if( prom->magic_1 != raid[device].magic_1) { + return 0; + } + } + else if (prom->magic_0 != raid[device].magic_0) { + return 0; + } + } i = prom->disk_number; if (i<0) - return; + return 0; if (i>8) - return; + return 0; - bdev = bdget(MKDEV(disk->major,disk->minor)); - if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) { - int j=0; - struct gendisk *gd; - raid[device].disk[i].bdev = bdev; - /* This is supposed to prevent others from stealing our underlying disks */ - /* now blank the /proc/partitions table for the wrong partition table, - so that scripts don't accidentally mount it and crash the kernel */ - /* XXX: the 0 is an utter hack --hch */ - gd=get_gendisk(MKDEV(disk->major, 0)); - if (gd!=NULL) { - if (gd->major==disk->major) - for (j=1+(disk->minor<minor_shift); - j<((disk->minor+1)<minor_shift); - j++) gd->part[j].nr_sects=0; + if ( type == HPT_T_RAID_01_RAID_0 ) { + + /* allocate helper raid devices for level 0+1 */ + if (raid[device].raid01 == NULL ) { + + raid[device].raid01= + kmalloc(2 * sizeof(struct hptraid),GFP_KERNEL); + if ( raid[device].raid01 == NULL ) { + printk(KERN_ERR "hptraid: out of memory\n"); + raid[device].disks=-1; + return -ENOMEM; + } + memset(raid[device].raid01, 0, + 2 * sizeof(struct hptraid)); } - } - raid[device].disk[i].device = MKDEV(disk->major,disk->minor); - raid[device].disk[i].sectors = maxsectors(disk->major,disk->minor); - raid[device].stride = (1<raid0_shift); - raid[device].disks = prom->raid_disks; - raid[device].sectors = prom->total_secs-(prom->total_secs%(255*63)); - raid[device].sectors += raid[device].sectors&1?1:0; - raid[device].magic_0=prom->magic_0; + + /* find free sub-stucture */ + for (j=0; j<2; j++) { + if ( raid[device].raid01[j].disks == 0 || + raid[device].raid01[j].magic_0 == prom->magic_0 ) + { + writeentry(raid[device].raid01+j, disk, + i, prom); + break; + } + } + + /* no free slot */ + if(j == 2) + return 0; + + raid[device].stride=raid[device].raid01[j].stride; + raid[device].disks=j+1; + raid[device].sectors=raid[device].raid01[j].sectors; + raid[device].disk[j].sectors=raid[device].raid01[j].sectors; + raid[device].magic_1=prom->magic_1; + } + else { + writeentry(raid+device, disk, i, prom); + } + disk->device=device; + return 1; } -static void __init fill_cutoff(int device) +static void fill_cutoff(struct hptraid * device) { int i,j; unsigned long smallest; @@ -537,111 +743,154 @@ for (i=0;i<8;i++) { smallest = ~0; for (j=0;j<8;j++) - if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar)) - smallest = raid[device].disk[j].sectors; + if ((device->disk[j].sectors < smallest) && (device->disk[j].sectors>bar)) + smallest = device->disk[j].sectors; count = 0; for (j=0;j<8;j++) - if (raid[device].disk[j].sectors >= smallest) + if (device->disk[j].sectors >= smallest) count++; smallest = smallest * count; bar = smallest; - raid[device].cutoff[i] = smallest; - raid[device].cutoff_disks[i] = count; + device->cutoff[i] = smallest; + device->cutoff_disks[i] = count; } } +static int count_disks(struct hptraid * raid) { + int i, count=0; + for (i=0;i<8;i++) { + if (raid->disk[i].device!=0) { + printk(KERN_INFO "Drive %i is %li Mb \n", + i,raid->disk[i].sectors/2048); + count++; + } + } + return count; +} + +static void raid1_fixup(struct hptraid * raid) { + int i, count=0; + for (i=0;i<8;i++) { + /* disknumbers and total disks values are bogus */ + if (raid->disk[i].device!=0) { + raid->disk[count]=raid->disk[i]; + if(i > count) { + memset(raid->disk+i, 0, sizeof(struct hptdisk)); + } + count++; + } + } + raid->disks=count; +} -static __init int hptraid_init_one(int device, u_int8_t type) +static int hptraid_init_one(int device, u_int8_t type, const char * label) { int i,count; - memset(raid+device, 0, sizeof(struct hptraid)); - for(i=0; i < 14; i++) { - probedisk(devlist+i, device, type); + for (i=0; i < 14; i++) { + if( probedisk(devlist+i, device, type) < 0 ) + return -EINVAL; + } + + /* Initialize raid levels */ + switch (type) { + case HPT_T_RAID_0: + fill_cutoff(raid+device); + break; + + case HPT_T_RAID_1: + raid1_fixup(raid+device); + break; + + case HPT_T_RAID_01_RAID_0: + for(i=0; i < 2 && raid[device].raid01 && + raid[device].raid01[i].disks; i++) { + fill_cutoff(raid[device].raid01+i); + /* initialize raid 0+1 volumes */ + raid[device].disk[i].device=i+1; + } + break; } - if(type == HPT_T_RAID_0) - fill_cutoff(device); - /* Initialize the gendisk structure */ ataraid_register_disk(device,raid[device].sectors); - count=0; + /* Verify that we have all disks */ + + count=count_disks(raid+device); - for (i=0;i<8;i++) { - if (raid[device].disk[i].device!=0) { - printk(KERN_INFO "Drive %i is %li Mb \n", - i,raid[device].disk[i].sectors/2048); - count++; - } + if (count != raid[device].disks) { + printk(KERN_INFO "%s consists of %i drives but found %i drives\n", + label, raid[device].disks, count); + return -ENODEV; } - if (count) { - printk(KERN_INFO "Raid array consists of %i drives. \n",count); + else if (count) { + printk(KERN_INFO "%s consists of %i drives.\n", + label, count); + if (type == HPT_T_RAID_01_RAID_0 ) { + for(i=0;immio) && (hwif->dma_base)) + if (hwif->mmio && hwif->dma_base) return hwif->dma_base; - - if (hwif->mate && hwif->mate->dma_base) { + else if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); } else { dma_base = (hwif->mmio) ? diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ide-scsi.c linux.21-ac4/drivers/scsi/ide-scsi.c --- linux.vanilla/drivers/scsi/ide-scsi.c 2003-06-14 00:11:35.000000000 +0100 +++ linux.21-ac4/drivers/scsi/ide-scsi.c 2003-06-27 13:39:01.000000000 +0100 @@ -1105,15 +1105,34 @@ int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags) { + return SCSI_RESET_SNOOZE; + +#ifdef WORK_IN_PROGRESS ide_drive_t *drive = idescsi_drives[cmd->target]; - /* We cannot reset the interface holding the lock. We can - drop the lock here however */ + /* At this point the state machine is running, that + requires we are especially careful. Ideally we want + to abort commands on timeout only if they hit the + cable but thats harder */ + + DRIVER(drive)->abort(drive, "scsi reset"); + if(HWGROUP(drive)->handler) + BUG(); + + /* Ok the state machine is halted but make sure it + doesn't restart too early */ - spin_unlock(&io_request_lock); - (void) ide_do_reset(drive); - spin_lock(&io_request_lock); + HWGROUP(drive)->busy = 1; + spin_unlock_irq(&io_request_lock); + + /* Apply the mallet of re-education firmly to the drive */ + ide_do_reset(drive); + + /* At this point the reset state machine is running and + its termination will kick off the next command */ + spin_lock_irq(&io_request_lock); return SCSI_RESET_SUCCESS; +#endif } int idescsi_bios (Disk *disk, kdev_t dev, int *parm) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ide.h linux.21-ac4/include/linux/ide.h --- linux.vanilla/include/linux/ide.h 2003-06-14 00:11:42.000000000 +0100 +++ linux.21-ac4/include/linux/ide.h 2003-06-27 17:13:09.000000000 +0100 @@ -1744,6 +1744,12 @@ extern void ide_toggle_bounce(ide_drive_t *drive, int on); extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate); +/* ide driver registration */ +typedef void (*ide_driver_call)(void); +extern void __init ide_register_driver(ide_driver_call); + +/* ide locks for 2.4 */ + #define ide_lock (io_request_lock) #define DRIVE_LOCK(drive) ((drive)->queue.queue_lock) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pci_ids.h linux.21-ac3/include/linux/pci_ids.h --- linux.vanilla/include/linux/pci_ids.h 2003-06-14 00:11:42.000000000 +0100 +++ linux.21-ac3/include/linux/pci_ids.h 2003-06-22 13:51:39.000000000 +0100 @@ -493,6 +493,7 @@ #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_633 0x0633 #define PCI_DEVICE_ID_SI_635 0x0635 #define PCI_DEVICE_ID_SI_640 0x0640 #define PCI_DEVICE_ID_SI_645 0x0645 @@ -501,7 +502,9 @@ #define PCI_DEVICE_ID_SI_650 0x0650 #define PCI_DEVICE_ID_SI_651 0x0651 #define PCI_DEVICE_ID_SI_652 0x0652 +#define PCI_DEVICE_ID_SI_655 0x0655 #define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_733 0x0733 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_735 0x0735 @@ -519,7 +522,10 @@ #define PCI_DEVICE_ID_SI_5513 0x5513 #define PCI_DEVICE_ID_SI_5518 0x5518 #define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_5581 0x5581 +#define PCI_DEVICE_ID_SI_5582 0x5582 #define PCI_DEVICE_ID_SI_5591 0x5591 +#define PCI_DEVICE_ID_SI_5596 0x5596 #define PCI_DEVICE_ID_SI_5597 0x5597 #define PCI_DEVICE_ID_SI_5598 0x5598 #define PCI_DEVICE_ID_SI_5600 0x5600 @@ -760,6 +766,8 @@ #define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001 #define PCI_VENDOR_ID_CMD 0x1095 +#define PCI_DEVICE_ID_SII_1210SA 0x0240 + #define PCI_DEVICE_ID_CMD_640 0x0640 #define PCI_DEVICE_ID_CMD_643 0x0643 #define PCI_DEVICE_ID_CMD_646 0x0646 @@ -923,7 +931,9 @@ #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 +#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc +#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 @@ -1025,13 +1035,14 @@ #define PCI_DEVICE_ID_VIA_8622 0x3102 #define PCI_DEVICE_ID_VIA_8233C_0 0x3109 #define PCI_DEVICE_ID_VIA_8361 0x3112 -#define PCI_DEVICE_ID_VIA_8375 0x3116 +#define PCI_DEVICE_ID_VIA_8375 0x3116 #define PCI_DEVICE_ID_VIA_8233A 0x3147 -#define PCI_DEVICE_ID_VIA_P4X333 0x3168 -#define PCI_DEVICE_ID_VIA_8235 0x3177 -#define PCI_DEVICE_ID_VIA_8377_0 0x3189 +#define PCI_DEVICE_ID_VIA_P4M266 0x3148 +#define PCI_DEVICE_ID_VIA_8237_SATA 0x3149 +#define PCI_DEVICE_ID_VIA_P4X333 0x3168 +#define PCI_DEVICE_ID_VIA_8235 0x3177 #define PCI_DEVICE_ID_VIA_8377_0 0x3189 -#define PCI_DEVICE_ID_VIA_8237 0x3227 +#define PCI_DEVICE_ID_VIA_8237 0x3227 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_DEVICE_ID_VIA_8231 0x8231 #define PCI_DEVICE_ID_VIA_8231_4 0x8235 @@ -1185,6 +1196,7 @@ #define PCI_DEVICE_ID_SBE_WANXL400 0x0104 #define PCI_VENDOR_ID_TOSHIBA 0x1179 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102 #define PCI_DEVICE_ID_TOSHIBA_601 0x0601 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a #define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f @@ -1765,6 +1777,7 @@ #define PCI_DEVICE_ID_INTEL_82801DB_7 0x24c7 #define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca #define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb +#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc #define PCI_DEVICE_ID_INTEL_82801DB_13 0x24cd #define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0 #define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1