diff options
| author | Martin Dalecki <dalecki@evision-ventures.com> | 2002-05-17 09:49:53 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-05-17 09:49:53 -0700 |
| commit | acff0d9364ccfc427ddfc20d13c53afd7ac3d0fb (patch) | |
| tree | c52163956bbfcaeb4335c522208267f6a3db82a9 /drivers/ide | |
| parent | d7e09f7eac82dcb45fabfe8c1055e6da418c7d6a (diff) | |
[PATCH] 2.5.15 IDE 64
Let's just get over with this before queue handling will be targeted again...
- Implement suggestions by Russell King for improved portability and separation
between PCI and non PCI host code.
- pdc202xxx updates from Thierry Vignaud.
- Tiny PIO fix from Tomita.
Diffstat (limited to 'drivers/ide')
| -rw-r--r-- | drivers/ide/Makefile | 5 | ||||
| -rw-r--r-- | drivers/ide/ide-taskfile.c | 2 | ||||
| -rw-r--r-- | drivers/ide/ide.c | 2 | ||||
| -rw-r--r-- | drivers/ide/pcidma.c (renamed from drivers/ide/ide-dma.c) | 613 | ||||
| -rw-r--r-- | drivers/ide/pcihost.h | 4 | ||||
| -rw-r--r-- | drivers/ide/pdc202xx.c | 502 | ||||
| -rw-r--r-- | drivers/ide/quirks.c | 231 |
7 files changed, 472 insertions, 887 deletions
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index b004ba92bc4e..8655590ea98d 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -10,7 +10,7 @@ O_TARGET := idedriver.o -export-objs := ide-taskfile.o ide.o ide-features.o ide-probe.o ide-dma.o ataraid.o +export-objs := ide-taskfile.o ide.o ide-features.o ide-probe.o quirks.o pcidma.o ataraid.o obj-y := obj-m := @@ -43,7 +43,8 @@ ide-obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o ide-obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o -ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += ide-dma.o +ide-obj-$(CONFIG_BLK_DEV_IDEDMA) += quirks.o +ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += pcidma.o ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ) += tcq.o ide-obj-$(CONFIG_PCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index cd620d6074af..4be7d8b00f85 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -562,7 +562,7 @@ static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *r if (!ide_end_request(drive, rq, 1)) return ide_stopped; - if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { + if ((rq->nr_sectors == 1) != (stat & DRQ_STAT)) { pBuf = ide_map_rq(rq, &flags); DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 61223d678026..1279afbe463d 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1145,7 +1145,7 @@ static unsigned long longest_sleep(struct ata_channel *channel) } /* - * Select the next device which will be serviced. This selects onlt between + * Select the next device which will be serviced. This selects only between * devices on the same channel, since everything else will be scheduled on the * queue level. */ diff --git a/drivers/ide/ide-dma.c b/drivers/ide/pcidma.c index 59542ba0d252..b9a33e5c73f7 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/pcidma.c @@ -1,70 +1,17 @@ /**** vi:set ts=8 sts=8 sw=8:************************************************ * + * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de> + * + * Based on previous work by: + * * Copyright (c) 1999-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (c) 1995-1998 Mark Lord * * May be copied or modified under the terms of the GNU General Public License - * - * Special Thanks to Mark for his Six years of work. - * - * This module provides support for the bus-master IDE DMA functions - * of various PCI chipsets, including the Intel PIIX (i82371FB for - * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and - * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset) - * ("PIIX" stands for "PCI ISA IDE Xcellerator"). - * - * Pretty much the same code works for other IDE PCI bus-mastering chipsets. - * - * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies). - * - * By default, DMA support is prepared for use, but is currently enabled only - * for drives which already have DMA enabled (UltraDMA or mode 2 multi/single), - * or which are recognized as "good" (see table below). Drives with only mode0 - * or mode1 (multi/single) DMA should also work with this chipset/driver - * (eg. MC2112A) but are not enabled by default. - * - * Use "hdparm -i" to view modes supported by a given drive. - * - * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling - * DMA support, but must be (re-)compiled against this kernel version or later. - * - * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting. - * If problems arise, ide.c will disable DMA operation after a few retries. - * This error recovery mechanism works and has been extremely well exercised. - * - * IDE drives, depending on their vintage, may support several different modes - * of DMA operation. The boot-time modes are indicated with a "*" in - * the "hdparm -i" listing, and can be changed with *knowledgeable* use of - * the "hdparm -X" feature. There is seldom a need to do this, as drives - * normally power-up with their "best" PIO/DMA modes enabled. - * - * Testing has been done with a rather extensive number of drives, - * with Quantum & Western Digital models generally outperforming the pack, - * and Fujitsu & Conner (and some Seagate which are really Conner) drives - * showing more lackluster throughput. - * - * Keep an eye on /var/adm/messages for "DMA disabled" messages. - * - * Some people have reported trouble with Intel Zappa motherboards. - * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0, - * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe - * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this). - * - * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for - * fixing the problem with the BIOS on some Acer motherboards. - * - * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing - * "TX" chipset compatibility and for providing patches for the "TX" chipset. - * - * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack - * at generic DMA -- his patches were referred to when preparing this code. - * - * Most importantly, thanks to Robert Bringman <rob@mars.trion.com> - * for supplying a Promise UDMA board & WD UDMA drive for this work! - * - * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports. - * - * ATA-66/100 and recovery functions, I forgot the rest...... + */ + +/* + * Those are the generic BM DMA support functions for PCI bus based systems. */ #include <linux/config.h> @@ -83,115 +30,10 @@ #include <asm/io.h> #include <asm/irq.h> -/* - * Long lost data from 2.0.34 that is now in 2.0.39 - * - * This was used in ./drivers/block/triton.c to do DMA Base address setup - * when PnP failed. Oh the things we forget. I believe this was part - * of SFF-8038i that has been withdrawn from public access... :-(( - */ #define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */ #define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */ #define DEFAULT_BMALIBA 0xd400 /* ALI's default value */ -#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS - -struct drive_list_entry { - char * id_model; - char * id_firmware; -}; - -struct drive_list_entry drive_whitelist[] = { - { "Micropolis 2112A", NULL }, - { "CONNER CTMA 4000", NULL }, - { "CONNER CTT8000-A", NULL }, - { "ST34342A", NULL }, - { NULL, NULL } -}; - -struct drive_list_entry drive_blacklist[] = { - - { "WDC AC11000H", NULL }, - { "WDC AC22100H", NULL }, - { "WDC AC32500H", NULL }, - { "WDC AC33100H", NULL }, - { "WDC AC31600H", NULL }, - { "WDC AC32100H", "24.09P07" }, - { "WDC AC23200L", "21.10N21" }, - { "Compaq CRD-8241B", NULL }, - { "CRD-8400B", NULL }, - { "CRD-8480B", NULL }, - { "CRD-8480C", NULL }, - { "CRD-8482B", NULL }, - { "CRD-84", NULL }, - { "SanDisk SDP3B", NULL }, - { "SanDisk SDP3B-64", NULL }, - { "SANYO CD-ROM CRD", NULL }, - { "HITACHI CDR-8", NULL }, - { "HITACHI CDR-8335", NULL }, - { "HITACHI CDR-8435", NULL }, - { "Toshiba CD-ROM XM-6202B", NULL }, - { "CD-532E-A", NULL }, - { "E-IDE CD-ROM CR-840", NULL }, - { "CD-ROM Drive/F5A", NULL }, - { "RICOH CD-R/RW MP7083A", NULL }, - { "WPI CDD-820", NULL }, - { "SAMSUNG CD-ROM SC-148C", NULL }, - { "SAMSUNG CD-ROM SC-148F", NULL }, - { "SAMSUNG CD-ROM SC", NULL }, - { "SanDisk SDP3B-64", NULL }, - { "SAMSUNG CD-ROM SN-124", NULL }, - { "PLEXTOR CD-R PX-W8432T", NULL }, - { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL }, - { "_NEC DV5800A", NULL }, - { NULL, NULL } - -}; - -static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) -{ - for ( ; drive_table->id_model ; drive_table++) - if ((!strcmp(drive_table->id_model, id->model)) && - ((drive_table->id_firmware && !strstr(drive_table->id_firmware, id->fw_rev)) || - (!drive_table->id_firmware))) - return 1; - return 0; -} - -#else - -/* - * good_dma_drives() lists the model names (from "hdparm -i") - * of drives which do not support mode2 DMA but which are - * known to work fine with this interface under Linux. - */ -const char *good_dma_drives[] = {"Micropolis 2112A", - "CONNER CTMA 4000", - "CONNER CTT8000-A", - "ST34342A", /* for Sun Ultra */ - NULL}; - -/* - * bad_dma_drives() lists the model names (from "hdparm -i") - * of drives which supposedly support (U)DMA but which are - * known to corrupt data with this interface under Linux. - * - * This is an empirical list. Its generated from bug reports. That means - * while it reflects actual problem distributions it doesn't answer whether - * the drive or the controller, or cabling, or software, or some combination - * thereof is the fault. If you don't happen to agree with the kernel's - * opinion of your drive - use hdparm to turn DMA on. - */ -const char *bad_dma_drives[] = {"WDC AC11000H", - "WDC AC22100H", - "WDC AC32100H", - "WDC AC32500H", - "WDC AC33100H", - "WDC AC31600H", - NULL}; - -#endif - /* * This is the handler for disk read/write DMA interrupts. */ @@ -267,53 +109,60 @@ static int build_sglist(struct ata_channel *ch, struct request *rq) ch->sg_dma_direction = PCI_DMA_TODEVICE; } + return pci_map_sg(ch->pci_dev, sg, nents, ch->sg_dma_direction); } /* - * For both Blacklisted and Whitelisted drives. - * This is setup to be called as an extern for future support - * to other special driver code. + * 1 dma-ing, 2 error, 4 intr */ -int check_drive_lists(struct ata_device *drive, int good_bad) +static int dma_timer_expiry(struct ata_device *drive, struct request *rq) { - struct hd_driveid *id = drive->id; + /* FIXME: What's that? */ + u8 dma_stat = inb(drive->channel->dma_base+2); -#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS - if (good_bad) { - return in_drive_list(id, drive_whitelist); - } else { - int blacklist = in_drive_list(id, drive_blacklist); - if (blacklist) - printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); - return(blacklist); - } -#else - const char **list; +#ifdef DEBUG + printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat); +#endif - if (good_bad) { - /* Consult the list of known "good" drives */ - list = good_dma_drives; - while (*list) { - if (!strcmp(*list++,id->model)) - return 1; - } - } else { - /* Consult the list of known "bad" drives */ - list = bad_dma_drives; - while (*list) { - if (!strcmp(*list++,id->model)) { - printk("%s: Disabling (U)DMA for %s\n", - drive->name, id->model); - return 1; - } - } - } +#if 0 + drive->expiry = NULL; /* one free ride for now */ #endif + + if (dma_stat & 2) { /* ERROR */ + u8 stat = GET_STAT(); + return ide_error(drive, rq, "dma_timer_expiry", stat); + } + if (dma_stat & 1) /* DMAing */ + return WAIT_CMD; return 0; } -static int config_drive_for_dma(struct ata_device *drive) +int ata_start_dma(struct ata_device *drive, struct request *rq) +{ + struct ata_channel *ch = drive->channel; + unsigned long dma_base = ch->dma_base; + unsigned int reading = 0; + + if (rq_data_dir(rq) == READ) + reading = 1 << 3; + + /* try PIO instead of DMA */ + if (!udma_new_table(ch, rq)) + return 1; + + outl(ch->dmatable_dma, dma_base + 4); /* PRD table */ + outb(reading, dma_base); /* specify r/w */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; + + return 0; +} + +/* + * Configure a device for DMA operation. + */ +int XXX_ide_dmaproc(struct ata_device *drive) { int config_allows_dma = 1; struct hd_driveid *id = drive->id; @@ -373,72 +222,6 @@ static int config_drive_for_dma(struct ata_device *drive) } /* - * 1 dma-ing, 2 error, 4 intr - */ -static int dma_timer_expiry(struct ata_device *drive, struct request *rq) -{ - /* FIXME: What's that? */ - u8 dma_stat = inb(drive->channel->dma_base+2); - -#ifdef DEBUG - printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat); -#endif - -#if 0 - drive->expiry = NULL; /* one free ride for now */ -#endif - - if (dma_stat & 2) { /* ERROR */ - u8 stat = GET_STAT(); - return ide_error(drive, rq, "dma_timer_expiry", stat); - } - if (dma_stat & 1) /* DMAing */ - return WAIT_CMD; - return 0; -} - -int ata_start_dma(struct ata_device *drive, struct request *rq) -{ - struct ata_channel *ch = drive->channel; - unsigned long dma_base = ch->dma_base; - unsigned int reading = 0; - - if (rq_data_dir(rq) == READ) - reading = 1 << 3; - - /* try PIO instead of DMA */ - if (!udma_new_table(ch, rq)) - return 1; - - outl(ch->dmatable_dma, dma_base + 4); /* PRD table */ - outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ - drive->waiting_for_dma = 1; - return 0; -} - -/* - * This initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * For ATAPI devices, we just prepare for DMA and return. The caller should - * then issue the packet command to the drive and call us again with - * udma_start afterwards. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case - * the caller should revert to PIO for the current request. - * May also be invoked from trm290.c - */ -int XXX_ide_dmaproc(struct ata_device *drive) -{ - return config_drive_for_dma(drive); -} - -/* * Needed for allowing full modular support of ide-driver */ void ide_release_dma(struct ata_channel *ch) @@ -463,62 +246,8 @@ void ide_release_dma(struct ata_channel *ch) ch->dma_base = 0; } -/* - * This can be called for a dynamically installed interface. Don't __init it - */ -void ata_init_dma(struct ata_channel *ch, unsigned long dma_base) -{ - if (!request_region(dma_base, 8, ch->name)) { - printk(KERN_ERR "ATA: ERROR: BM DMA portst already in use!\n"); - - return; - } - printk(KERN_INFO" %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + 7); - ch->dma_base = dma_base; - ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev, - PRD_ENTRIES * PRD_BYTES, - &ch->dmatable_dma); - if (ch->dmatable_cpu == NULL) - goto dma_alloc_failure; - - ch->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, - GFP_KERNEL); - if (ch->sg_table == NULL) { - pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES, - ch->dmatable_cpu, ch->dmatable_dma); - goto dma_alloc_failure; - } - - if (!ch->XXX_udma) - ch->XXX_udma = XXX_ide_dmaproc; - - if (ch->chipset != ide_trm290) { - u8 dma_stat = inb(dma_base+2); - printk(", BIOS settings: %s:%s, %s:%s", - ch->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", - ch->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); - } - printk("\n"); - return; - -dma_alloc_failure: - printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n"); -} - /**************************************************************************** - * UDMA function which should have architecture specific counterparts where - * neccessary. - * - * The intention is that at some point in time we will move this whole to - * architecture specific kernel sections. For now I would love the architecture - * maintainers to just #ifdef #endif this stuff directly here. I have for now - * tryed to update as much as I could in the architecture specific code. But - * of course I may have done mistakes, so please bear with me and update it - * here the proper way. - * - * Thank you a lot in advance! - * - * Sat May 4 20:29:46 CEST 2002 Marcin Dalecki. + * PCI specific UDMA channel method implementations. */ /* @@ -529,21 +258,13 @@ dma_alloc_failure: * recovery" in the ATAPI drivers. This was just plain wrong before, in esp. * not portable, and just got uncovered now. */ -void udma_enable(struct ata_device *drive, int on, int verbose) +static void udma_pci_enable(struct ata_device *drive, int on, int verbose) { struct ata_channel *ch = drive->channel; int set_high = 1; u8 unit; u64 addr; - - /* Method overloaded by host chip specific code. */ - if (ch->udma_enable) { - ch->udma_enable(drive, on, verbose); - - return; - } - /* Fall back to the default implementation. */ unit = (drive->select.b.unit & 0x01); addr = BLK_BOUNCE_HIGH; @@ -669,80 +390,17 @@ void udma_destroy_table(struct ata_channel *ch) pci_unmap_sg(ch->pci_dev, ch->sg_table, ch->sg_nents, ch->sg_dma_direction); } -void udma_print(struct ata_device *drive) -{ -#ifdef CONFIG_ARCH_ACORN - printk(", DMA"); -#else - struct hd_driveid *id = drive->id; - char *str = NULL; - - if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && - (id->dma_ultra & (id->dma_ultra >> 14) & 3)) { - if ((id->dma_ultra >> 15) & 1) - str = ", UDMA(mode 7)"; /* UDMA BIOS-enabled! */ - else - str = ", UDMA(133)"; /* UDMA BIOS-enabled! */ - } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && - (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { - if ((id->dma_ultra >> 13) & 1) { - str = ", UDMA(100)"; /* UDMA BIOS-enabled! */ - } else if ((id->dma_ultra >> 12) & 1) { - str = ", UDMA(66)"; /* UDMA BIOS-enabled! */ - } else { - str = ", UDMA(44)"; /* UDMA BIOS-enabled! */ - } - } else if ((id->field_valid & 4) && - (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { - if ((id->dma_ultra >> 10) & 1) { - str = ", UDMA(33)"; /* UDMA BIOS-enabled! */ - } else if ((id->dma_ultra >> 9) & 1) { - str = ", UDMA(25)"; /* UDMA BIOS-enabled! */ - } else { - str = ", UDMA(16)"; /* UDMA BIOS-enabled! */ - } - } else if (id->field_valid & 4) - str = ", (U)DMA"; /* Can be BIOS-enabled! */ - else - str = ", DMA"; - - printk(str); -#endif -} - -/* - * Drive back/white list handling for UDMA capability: - */ - -int udma_black_list(struct ata_device *drive) -{ - return check_drive_lists(drive, 0); -} - -int udma_white_list(struct ata_device *drive) -{ - return check_drive_lists(drive, 1); -} - -/* - * Generic entry points for functions provided possibly by the host chip set - * drivers. - */ - /* * Prepare the channel for a DMA startfer. Please note that only the broken * Pacific Digital host chip needs the reques to be passed there to decide * about addressing modes. */ -int udma_start(struct ata_device *drive, struct request *rq) +static int udma_pci_start(struct ata_device *drive, struct request *rq) { struct ata_channel *ch = drive->channel; unsigned long dma_base = ch->dma_base; - if (ch->udma_start) - return ch->udma_start(drive, rq); - /* Note that this is done *after* the cmd has * been issued to the drive, as per the BM-IDE spec. * The Promise Ultra33 doesn't work correctly when @@ -752,15 +410,12 @@ int udma_start(struct ata_device *drive, struct request *rq) return 0; } -int udma_stop(struct ata_device *drive) +static int udma_pci_stop(struct ata_device *drive) { struct ata_channel *ch = drive->channel; unsigned long dma_base = ch->dma_base; u8 dma_stat; - if (ch->udma_stop) - return ch->udma_stop(drive); - drive->waiting_for_dma = 0; outb(inb(dma_base)&~1, dma_base); /* stop DMA */ dma_stat = inb(dma_base+2); /* get DMA status */ @@ -770,97 +425,131 @@ int udma_stop(struct ata_device *drive) return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ } -/* - * This is the default read write function. - * - * It's exported only for host chips which use it for fallback or (too) late - * capability checking. - */ - -int ata_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq) +static int udma_pci_read(struct ata_device *drive, struct request *rq) { - if (ata_start_dma(drive, rq)) - return 1; - - if (drive->type != ATA_DISK) - return 0; - - reading <<= 3; - - ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ - if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) { - struct ata_taskfile *args = rq->special; - - OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG); - } else if (drive->addressing) { - OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); - } else { - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - } - - return udma_start(drive, rq); -} - -int udma_read(struct ata_device *drive, struct request *rq) -{ - struct ata_channel *ch = drive->channel; - - if (ch->udma_read) - return ch->udma_read(drive, rq); - return ata_do_udma(1, drive, rq); } -int udma_write(struct ata_device *drive, struct request *rq) +static int udma_pci_write(struct ata_device *drive, struct request *rq) { - struct ata_channel *ch = drive->channel; - - if (ch->udma_write) - return ch->udma_write(drive, rq); - return ata_do_udma(0, drive, rq); } /* * FIXME: This should be attached to a channel as we can see now! */ -int udma_irq_status(struct ata_device *drive) +static int udma_pci_irq_status(struct ata_device *drive) { struct ata_channel *ch = drive->channel; u8 dma_stat; - if (ch->udma_irq_status) - return ch->udma_irq_status(drive); - /* default action */ dma_stat = inb(ch->dma_base + 2); return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ } -void udma_timeout(struct ata_device *drive) +static void udma_pci_timeout(struct ata_device *drive) { printk(KERN_ERR "ATA: UDMA timeout occured %s!\n", drive->name); +} + +static void udma_pci_irq_lost(struct ata_device *drive) +{ +} - /* Invoke the chipset specific handler now. */ - if (drive->channel->udma_timeout) - drive->channel->udma_timeout(drive); +/* + * This can be called for a dynamically installed interface. Don't __init it + */ +void ata_init_dma(struct ata_channel *ch, unsigned long dma_base) +{ + if (!request_region(dma_base, 8, ch->name)) { + printk(KERN_ERR "ATA: ERROR: BM DMA portst already in use!\n"); + + return; + } + printk(KERN_INFO" %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + 7); + ch->dma_base = dma_base; + ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev, + PRD_ENTRIES * PRD_BYTES, + &ch->dmatable_dma); + if (ch->dmatable_cpu == NULL) + goto dma_alloc_failure; + + ch->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, + GFP_KERNEL); + if (ch->sg_table == NULL) { + pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES, + ch->dmatable_cpu, ch->dmatable_dma); + goto dma_alloc_failure; + } + /* + * We could just assign them, and then leave it up to the chipset + * specific code to override these after they've called this function. + */ + if (!ch->XXX_udma) + ch->XXX_udma = XXX_ide_dmaproc; + if (!ch->udma_enable) + ch->udma_enable = udma_pci_enable; + if (!ch->udma_start) + ch->udma_start = udma_pci_start; + if (!ch->udma_stop) + ch->udma_stop = udma_pci_stop; + if (!ch->udma_read) + ch->udma_read = udma_pci_read; + if (!ch->udma_write) + ch->udma_write = udma_pci_write; + if (!ch->udma_irq_status) + ch->udma_irq_status = udma_pci_irq_status; + if (!ch->udma_timeout) + ch->udma_timeout = udma_pci_timeout; + if (!ch->udma_irq_lost) + ch->udma_irq_lost = udma_pci_irq_lost; + + if (ch->chipset != ide_trm290) { + u8 dma_stat = inb(dma_base+2); + printk(", BIOS settings: %s:%s, %s:%s", + ch->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", + ch->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); + } + printk("\n"); + return; + +dma_alloc_failure: + printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n"); } -void udma_irq_lost(struct ata_device *drive) +/* + * This is the default read write function. + * + * It's exported only for host chips which use it for fallback or (too) late + * capability checking. + */ + +int ata_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq) { - if (drive->channel->udma_irq_lost) - drive->channel->udma_irq_lost(drive); + if (ata_start_dma(drive, rq)) + return 1; + + if (drive->type != ATA_DISK) + return 0; + + reading <<= 3; + + ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ + if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) { + struct ata_taskfile *args = rq->special; + + outb(args->taskfile.command, IDE_COMMAND_REG); + } else if (drive->addressing) { + outb(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + } else { + outb(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + } + + return udma_start(drive, rq); } -EXPORT_SYMBOL(udma_enable); -EXPORT_SYMBOL(udma_start); -EXPORT_SYMBOL(udma_stop); -EXPORT_SYMBOL(udma_read); -EXPORT_SYMBOL(udma_write); EXPORT_SYMBOL(ata_do_udma); -EXPORT_SYMBOL(udma_irq_status); -EXPORT_SYMBOL(udma_print); -EXPORT_SYMBOL(udma_black_list); -EXPORT_SYMBOL(udma_white_list); +EXPORT_SYMBOL(ide_dma_intr); diff --git a/drivers/ide/pcihost.h b/drivers/ide/pcihost.h index 915ae978eef9..c994b1b1ccc6 100644 --- a/drivers/ide/pcihost.h +++ b/drivers/ide/pcihost.h @@ -10,10 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c index b6b9b207627d..8eaa72565344 100644 --- a/drivers/ide/pdc202xx.c +++ b/drivers/ide/pdc202xx.c @@ -53,220 +53,10 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 -#undef DISPLAY_PDC202XX_TIMINGS - #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif -#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static int pdc202xx_get_info(char *, char **, off_t, int); -extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -static struct pci_dev *bmide_dev; - -char *pdc202xx_pio_verbose (u32 drive_pci) -{ - if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET"); - if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4"); - if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3"); - if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2"); - if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1"); - if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0"); - return("PIO ?"); -} - -char *pdc202xx_dma_verbose (u32 drive_pci) -{ - if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2"); - if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1"); - if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0"); - if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2"); - if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1"); - if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0"); - return("PIO---"); -} - -char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable) -{ - if ((drive_pci & 0x000ff000) == 0x000ff000) - return("NOTSET"); - if ((drive_pci & 0x00012000) == 0x00012000) - return((slow_cable) ? "UDMA 2" : "UDMA 4"); - if ((drive_pci & 0x00024000) == 0x00024000) - return((slow_cable) ? "UDMA 1" : "UDMA 3"); - if ((drive_pci & 0x00036000) == 0x00036000) - return("UDMA 0"); - return(pdc202xx_dma_verbose(drive_pci)); -} - -static char * pdc202xx_info (char *buf, struct pci_dev *dev) -{ - char *p = buf; - - u32 bibma = pci_resource_start(dev, 4); - u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; - u16 reg50h = 0, pmask = (1<<10), smask = (1<<11); - u8 hi = 0, lo = 0; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - u8 c0 = inb_p((unsigned short)bibma + 0x02); - u8 c1 = inb_p((unsigned short)bibma + 0x0a); - - u8 sc11 = inb_p((unsigned short)bibma + 0x11); - u8 sc1a = inb_p((unsigned short)bibma + 0x1a); - u8 sc1b = inb_p((unsigned short)bibma + 0x1b); - u8 sc1c = inb_p((unsigned short)bibma + 0x1c); - u8 sc1d = inb_p((unsigned short)bibma + 0x1d); - u8 sc1e = inb_p((unsigned short)bibma + 0x1e); - u8 sc1f = inb_p((unsigned short)bibma + 0x1f); - - pci_read_config_word(dev, 0x50, ®50h); - pci_read_config_dword(dev, 0x60, ®60h); - pci_read_config_dword(dev, 0x64, ®64h); - pci_read_config_dword(dev, 0x68, ®68h); - pci_read_config_dword(dev, 0x6c, ®6ch); - - switch(dev->device) { - case PCI_DEVICE_ID_PROMISE_20267: - p += sprintf(p, "\n PDC20267 Chipset.\n"); - break; - case PCI_DEVICE_ID_PROMISE_20265: - p += sprintf(p, "\n PDC20265 Chipset.\n"); - break; - case PCI_DEVICE_ID_PROMISE_20262: - p += sprintf(p, "\n PDC20262 Chipset.\n"); - break; - case PCI_DEVICE_ID_PROMISE_20246: - p += sprintf(p, "\n PDC20246 Chipset.\n"); - reg50h |= 0x0c00; - break; - default: - p += sprintf(p, "\n PDC202XX Chipset.\n"); - break; - } - - p += sprintf(p, "------------------------------- General Status ---------------------------------\n"); - p += sprintf(p, "Burst Mode : %sabled\n", (sc1f & 0x01) ? "en" : "dis"); - p += sprintf(p, "Host Mode : %s\n", (sc1f & 0x08) ? "Tri-Stated" : "Normal"); - p += sprintf(p, "Bus Clocking : %s\n", - ((sc1f & 0xC0) == 0xC0) ? "100 External" : - ((sc1f & 0x80) == 0x80) ? "66 External" : - ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal"); - p += sprintf(p, "IO pad select : %s mA\n", - ((sc1c & 0x03) == 0x03) ? "10" : - ((sc1c & 0x02) == 0x02) ? "8" : - ((sc1c & 0x01) == 0x01) ? "6" : - ((sc1c & 0x00) == 0x00) ? "4" : "??"); - SPLIT_BYTE(sc1e, hi, lo); - p += sprintf(p, "Status Polling Period : %d\n", hi); - p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %s %s\n", - (c0&0x80)?"disabled":"enabled ", - (c1&0x80)?"disabled":"enabled "); - p += sprintf(p, "66 Clocking %s %s\n", - (sc11&0x02)?"enabled ":"disabled", - (sc11&0x08)?"enabled ":"disabled"); - p += sprintf(p, " Mode %s Mode %s\n", - (sc1a & 0x01) ? "MASTER" : "PCI ", - (sc1b & 0x01) ? "MASTER" : "PCI "); - p += sprintf(p, " %s %s\n", - (sc1d & 0x08) ? "Error " : - ((sc1d & 0x05) == 0x05) ? "Not My INTR " : - (sc1d & 0x04) ? "Interrupting" : - (sc1d & 0x02) ? "FIFO Full " : - (sc1d & 0x01) ? "FIFO Empty " : "????????????", - (sc1d & 0x80) ? "Error " : - ((sc1d & 0x50) == 0x50) ? "Not My INTR " : - (sc1d & 0x40) ? "Interrupting" : - (sc1d & 0x20) ? "FIFO Full " : - (sc1d & 0x10) ? "FIFO Empty " : "????????????"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no "); - p += sprintf(p, "DMA Mode: %s %s %s %s\n", - pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)), - pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), - pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), - pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); - p += sprintf(p, "PIO Mode: %s %s %s %s\n", - pdc202xx_pio_verbose(reg60h), - 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; -} - -static char * pdc202xx_info_new (char *buf, struct pci_dev *dev) -{ - char *p = buf; -// u32 bibma = pci_resource_start(dev, 4); - -// u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; -// u16 reg50h = 0, word88 = 0; -// int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0; - - switch(dev->device) { - case PCI_DEVICE_ID_PROMISE_20275: - p += sprintf(p, "\n PDC20275 Chipset.\n"); - break; - case PCI_DEVICE_ID_PROMISE_20276: - p += sprintf(p, "\n PDC20276 Chipset.\n"); - break; - case PCI_DEVICE_ID_PROMISE_20269: - p += sprintf(p, "\n PDC20269 TX2 Chipset.\n"); - break; - case PCI_DEVICE_ID_PROMISE_20268: - case PCI_DEVICE_ID_PROMISE_20268R: - p += sprintf(p, "\n PDC20268 TX2 Chipset.\n"); - break; -default: - p += sprintf(p, "\n PDC202XX Chipset.\n"); - break; - } - return (char *)p; -} - -static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - switch(bmide_dev->device) { - case PCI_DEVICE_ID_PROMISE_20275: - case PCI_DEVICE_ID_PROMISE_20276: - case PCI_DEVICE_ID_PROMISE_20269: - case PCI_DEVICE_ID_PROMISE_20268: - case PCI_DEVICE_ID_PROMISE_20268R: - p = pdc202xx_info_new(buffer, bmide_dev); - break; - default: - p = pdc202xx_info(buffer, bmide_dev); - break; - } - return p-buffer; /* => must be less than 4k! */ -} -#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ - -byte pdc202xx_proc = 0; - -const char *pdc_quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - extern char *ide_xfer_verbose (byte xfer_rate); /* A Register */ @@ -322,7 +112,6 @@ static void decode_registers (byte registers, byte value) switch(registers) { case REG_A: - bit2 = 0; printk("A Register "); if (value & 0x80) printk("SYNC_IN "); if (value & 0x40) printk("ERRDY_EN "); @@ -335,7 +124,6 @@ static void decode_registers (byte registers, byte value) printk("PIO(A) = %d ", bit2); break; case REG_B: - bit1 = 0;bit2 = 0; printk("B Register "); if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; } if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; } @@ -349,7 +137,6 @@ static void decode_registers (byte registers, byte value) printk("PIO(B) = %d ", bit2); break; case REG_C: - bit2 = 0; printk("C Register "); if (value & 0x80) printk("DMARQp "); if (value & 0x40) printk("IORDYp "); @@ -379,23 +166,22 @@ static void decode_registers (byte registers, byte value) #endif /* PDC202XX_DECODE_REGISTER_INFO */ -static int check_in_drive_lists(struct ata_device *drive, const char **list) -{ +int check_in_drive_lists(struct ata_device *drive) { + const char *pdc_quirk_drives[] = { + "QUANTUM FIREBALLlct08 08", + "QUANTUM FIREBALLP KA6.4", + "QUANTUM FIREBALLP LM20.4", + "QUANTUM FIREBALLP KX20.5", + "QUANTUM FIREBALLP KX27.3", + "QUANTUM FIREBALLP LM20.5", + NULL + }; + const char**list = pdc_quirk_drives; struct hd_driveid *id = drive->id; - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } + while (*list) + if (strstr(id->model, *list++)) + return 2; return 0; } @@ -523,6 +309,15 @@ static int pdc202xx_tune_chipset(struct ata_device *drive, byte speed) return err; } +#define set_2regs(a, b) \ + OUT_BYTE((a + adj), indexreg); \ + OUT_BYTE(b, datareg); + +#define set_reg_and_wait(value, reg, delay) \ + OUT_BYTE(value, reg); \ + mdelay(delay); + + static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed) { struct ata_channel *hwif = drive->channel; @@ -549,121 +344,79 @@ static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed) case XFER_UDMA_7: speed = XFER_UDMA_6; case XFER_UDMA_6: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x01, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcb, datareg); + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x01); + set_2regs(0x12, 0xcb); break; case XFER_UDMA_5: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x02, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcb, datareg); + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x02); + set_2regs(0x12, 0xcb); break; case XFER_UDMA_4: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x03, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x03); + set_2regs(0x12, 0xcd); break; case XFER_UDMA_3: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x05, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x05); + set_2regs(0x12, 0xcd); break; case XFER_UDMA_2: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x2a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x07, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); + set_2regs(0x10, 0x2a); + set_2regs(0x11, 0x07); + set_2regs(0x12, 0xcd); break; case XFER_UDMA_1: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x3a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x0a, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xd0, datareg); + set_2regs(0x10, 0x3a); + set_2regs(0x11, 0x0a); + set_2regs(0x12, 0xd0); break; case XFER_UDMA_0: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x4a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x0f, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xd5, datareg); + set_2regs(0x10, 0x4a); + set_2regs(0x11, 0x0f); + set_2regs(0x12, 0xd5); break; case XFER_MW_DMA_2: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0x69, datareg); - OUT_BYTE((0x0f + adj), indexreg); - OUT_BYTE(0x25, datareg); + set_2regs(0x0e, 0x69); + set_2regs(0x0f, 0x25); break; case XFER_MW_DMA_1: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0x6b, datareg); - OUT_BYTE((0x0f+ adj), indexreg); - OUT_BYTE(0x27, datareg); + set_2regs(0x0e, 0x6b); + set_2regs(0x0f, 0x27); break; case XFER_MW_DMA_0: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0xdf, datareg); - OUT_BYTE((0x0f + adj), indexreg); - OUT_BYTE(0x5f, datareg); + set_2regs(0x0e, 0xdf); + set_2regs(0x0f, 0x5f); break; #else switch (speed) { #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x23, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x09, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x25, datareg); + set_2regs(0x0c, 0x23); + set_2regs(0x0d, 0x09); + set_2regs(0x13, 0x25); break; case XFER_PIO_3: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x27, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x0d, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x35, datareg); + set_2regs(0x0c, 0x27); + set_2regs(0x0d, 0x0d); + set_2regs(0x13, 0x35); break; case XFER_PIO_2: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x23, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x26, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x64, datareg); + set_2regs(0x0c, 0x23); + set_2regs(0x0d, 0x26); + set_2regs(0x13, 0x64); break; case XFER_PIO_1: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x46, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x29, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0xa4, datareg); + set_2regs(0x0c, 0x46); + set_2regs(0x0d, 0x29); + set_2regs(0x13, 0xa4); break; case XFER_PIO_0: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0xfb, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x2b, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0xac, datareg); + set_2regs(0x0c, 0xfb); + set_2regs(0x0d, 0x2b); + set_2regs(0x13, 0xac); break; default: ; @@ -684,21 +437,15 @@ static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed) * 180, 120, 90, 90, 90, 60, 30 * 11, 5, 4, 3, 2, 1, 0 */ -static int config_chipset_for_pio(struct ata_device *drive, byte pio) +static void config_chipset_for_pio(struct ata_device *drive, byte pio) { - byte speed = 0x00; + byte speed; if (pio == 255) speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); - else - speed = XFER_PIO_0 + min_t(byte, pio, 4); + else speed = XFER_PIO_0 + min_t(byte, pio, 4); - return ((int) pdc202xx_tune_chipset(drive, speed)); -} - -static void pdc202xx_tune_drive(struct ata_device *drive, byte pio) -{ - (void) config_chipset_for_pio(drive, pio); + pdc202xx_tune_chipset(drive, speed); } #ifdef CONFIG_BLK_DEV_IDEDMA @@ -833,8 +580,7 @@ static int config_chipset_for_dma(struct ata_device *drive, byte ultra) if (drive->type != ATA_DISK) return 0; if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ - OUT_BYTE((iordy + adj), indexreg); - OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); + set_2regs(iordy, (IN_BYTE(datareg)|0x03)); } goto jumpbit_is_set; } @@ -971,7 +717,7 @@ fast_ata_pio: on = 0; verbose = 0; no_dma_set: - (void) config_chipset_for_pio(drive, 5); + config_chipset_for_pio(drive, 5); } udma_enable(drive, on, verbose); @@ -979,11 +725,6 @@ no_dma_set: return 0; } -int pdc202xx_quirkproc(struct ata_device *drive) -{ - return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); -} - static int pdc202xx_udma_start(struct ata_device *drive, struct request *rq) { u8 clock = 0; @@ -1119,15 +860,7 @@ somebody_else: return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ } -static void pdc202xx_udma_timeout(struct ata_device *drive) -{ - if (!drive->channel->resetproc) - return; - /* Assume naively that resetting the drive may help. */ - drive->channel->resetproc(drive); -} - -static void pdc202xx_udma_irq_lost(struct ata_device *drive) +static void pdc202xx_bug (struct ata_device *drive) { if (!drive->channel->resetproc) return; @@ -1143,10 +876,8 @@ static int pdc202xx_dmaproc(struct ata_device *drive) void pdc202xx_new_reset(struct ata_device *drive) { - OUT_BYTE(0x04,IDE_CONTROL_REG); - mdelay(1000); - OUT_BYTE(0x00,IDE_CONTROL_REG); - mdelay(1000); + set_reg_and_wait(0x04,IDE_CONTROL_REG, 1000); + set_reg_and_wait(0x00,IDE_CONTROL_REG, 1000); printk("PDC202XX: %s channel reset.\n", drive->channel->unit ? "Secondary" : "Primary"); } @@ -1156,40 +887,12 @@ void pdc202xx_reset(struct ata_device *drive) unsigned long high_16 = pci_resource_start(drive->channel->pci_dev, 4); byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); - OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ + set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100); + set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000); /* 2 seconds ?! */ printk("PDC202XX: %s channel reset.\n", drive->channel->unit ? "Secondary" : "Primary"); } -/* - * Since SUN Cobalt is attempting to do this operation, I should disclose - * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date - * HOTSWAP ATA Infrastructure. - */ -static int pdc202xx_tristate(struct ata_device * drive, int state) -{ -#if 0 - struct ata_channel *hwif = drive->channel; - unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); - byte sc1f = inb(high_16 + 0x001f); - - if (!hwif) - return -EINVAL; - -// hwif->bus_state = state; - - if (state) { - outb(sc1f | 0x08, high_16 + 0x001f); - } else { - outb(sc1f & ~0x08, high_16 + 0x001f); - } -#endif - return 0; -} - static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) { unsigned long high_16 = pci_resource_start(dev, 4); @@ -1213,10 +916,8 @@ static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: - OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ + set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100); + set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000); /* 2 seconds ?! */ break; case PCI_DEVICE_ID_PROMISE_20262: /* @@ -1229,10 +930,8 @@ static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) * reset leaves the timing registers intact, * but resets the drives. */ - OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ + set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100); + set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000); /* 2 seconds ?! */ default: if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { byte irq = 0, irq2 = 0; @@ -1265,31 +964,7 @@ static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) } #endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_MASTER - if (!(primary_mode & 1)) { - printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", - dev->name, primary_mode, (primary_mode|1)); - OUT_BYTE(primary_mode|1, high_16 + 0x001a); - printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); - } - - if (!(secondary_mode & 1)) { - printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ", - dev->name, secondary_mode, (secondary_mode|1)); - OUT_BYTE(secondary_mode|1, high_16 + 0x001b); - printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); - } -#endif - fttk_tx_series: - -#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) - if (!pdc202xx_proc) { - pdc202xx_proc = 1; - bmide_dev = dev; - pdc202xx_display_info = &pdc202xx_get_info; - } -#endif return dev->irq; } @@ -1314,8 +989,8 @@ static unsigned int __init ata66_pdc202xx(struct ata_channel *hwif) static void __init ide_init_pdc202xx(struct ata_channel *hwif) { - hwif->tuneproc = &pdc202xx_tune_drive; - hwif->quirkproc = &pdc202xx_quirkproc; + hwif->tuneproc = &config_chipset_for_pio; + hwif->quirkproc = &check_in_drive_lists; switch(hwif->pci_dev->device) { case PCI_DEVICE_ID_PROMISE_20275: @@ -1329,7 +1004,6 @@ static void __init ide_init_pdc202xx(struct ata_channel *hwif) case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: case PCI_DEVICE_ID_PROMISE_20262: - hwif->busproc = &pdc202xx_tristate; hwif->resetproc = &pdc202xx_reset; case PCI_DEVICE_ID_PROMISE_20246: hwif->speedproc = &pdc202xx_tune_chipset; @@ -1337,19 +1011,13 @@ static void __init ide_init_pdc202xx(struct ata_channel *hwif) break; } -#undef CONFIG_PDC202XX_32_UNMASK -#ifdef CONFIG_PDC202XX_32_UNMASK - hwif->io_32bit = 1; - hwif->unmask = 1; -#endif - #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->udma_start = pdc202xx_udma_start; hwif->udma_stop = pdc202xx_udma_stop; hwif->udma_irq_status = pdc202xx_udma_irq_status; - hwif->udma_irq_lost = pdc202xx_udma_irq_lost; - hwif->udma_timeout = pdc202xx_udma_timeout; + hwif->udma_irq_lost = pdc202xx_bug; + hwif->udma_timeout = pdc202xx_bug; hwif->XXX_udma = pdc202xx_dmaproc; hwif->highmem = 1; if (!noautodma) @@ -1509,7 +1177,7 @@ static struct ata_pci_device chipsets[] __initdata = { int __init init_pdc202xx(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(chipsets); ++i) { ata_register_chipset(&chipsets[i]); diff --git a/drivers/ide/quirks.c b/drivers/ide/quirks.c new file mode 100644 index 000000000000..d4cd05578193 --- /dev/null +++ b/drivers/ide/quirks.c @@ -0,0 +1,231 @@ +/**** vi:set ts=8 sts=8 sw=8:************************************************ + * + * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de> + * + * Copyright (c) 1999-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (c) 1995-1998 Mark Lord + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Just the black and white list handling for BM-DMA operation. + */ + +#include <linux/config.h> +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/delay.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS + +struct drive_list_entry { + char * id_model; + char * id_firmware; +}; + +struct drive_list_entry drive_whitelist[] = { + { "Micropolis 2112A", NULL }, + { "CONNER CTMA 4000", NULL }, + { "CONNER CTT8000-A", NULL }, + { "ST34342A", NULL }, + { NULL, NULL } +}; + +struct drive_list_entry drive_blacklist[] = { + + { "WDC AC11000H", NULL }, + { "WDC AC22100H", NULL }, + { "WDC AC32500H", NULL }, + { "WDC AC33100H", NULL }, + { "WDC AC31600H", NULL }, + { "WDC AC32100H", "24.09P07" }, + { "WDC AC23200L", "21.10N21" }, + { "Compaq CRD-8241B", NULL }, + { "CRD-8400B", NULL }, + { "CRD-8480B", NULL }, + { "CRD-8480C", NULL }, + { "CRD-8482B", NULL }, + { "CRD-84", NULL }, + { "SanDisk SDP3B", NULL }, + { "SanDisk SDP3B-64", NULL }, + { "SANYO CD-ROM CRD", NULL }, + { "HITACHI CDR-8", NULL }, + { "HITACHI CDR-8335", NULL }, + { "HITACHI CDR-8435", NULL }, + { "Toshiba CD-ROM XM-6202B", NULL }, + { "CD-532E-A", NULL }, + { "E-IDE CD-ROM CR-840", NULL }, + { "CD-ROM Drive/F5A", NULL }, + { "RICOH CD-R/RW MP7083A", NULL }, + { "WPI CDD-820", NULL }, + { "SAMSUNG CD-ROM SC-148C", NULL }, + { "SAMSUNG CD-ROM SC-148F", NULL }, + { "SAMSUNG CD-ROM SC", NULL }, + { "SanDisk SDP3B-64", NULL }, + { "SAMSUNG CD-ROM SN-124", NULL }, + { "PLEXTOR CD-R PX-W8432T", NULL }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL }, + { "_NEC DV5800A", NULL }, + { NULL, NULL } + +}; + +static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) +{ + for ( ; drive_table->id_model ; drive_table++) + if ((!strcmp(drive_table->id_model, id->model)) && + ((drive_table->id_firmware && !strstr(drive_table->id_firmware, id->fw_rev)) || + (!drive_table->id_firmware))) + return 1; + return 0; +} + +#else + +/* + * good_dma_drives() lists the model names (from "hdparm -i") + * of drives which do not support mode2 DMA but which are + * known to work fine with this interface under Linux. + */ +const char *good_dma_drives[] = {"Micropolis 2112A", + "CONNER CTMA 4000", + "CONNER CTT8000-A", + "ST34342A", /* for Sun Ultra */ + NULL}; + +/* + * bad_dma_drives() lists the model names (from "hdparm -i") + * of drives which supposedly support (U)DMA but which are + * known to corrupt data with this interface under Linux. + * + * This is an empirical list. Its generated from bug reports. That means + * while it reflects actual problem distributions it doesn't answer whether + * the drive or the controller, or cabling, or software, or some combination + * thereof is the fault. If you don't happen to agree with the kernel's + * opinion of your drive - use hdparm to turn DMA on. + */ +const char *bad_dma_drives[] = {"WDC AC11000H", + "WDC AC22100H", + "WDC AC32100H", + "WDC AC32500H", + "WDC AC33100H", + "WDC AC31600H", + NULL}; + +#endif + +/* + * For both Blacklisted and Whitelisted drives. + * This is setup to be called as an extern for future support + * to other special driver code. + */ +int check_drive_lists(struct ata_device *drive, int good_bad) +{ + struct hd_driveid *id = drive->id; + +#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS + if (good_bad) { + return in_drive_list(id, drive_whitelist); + } else { + int blacklist = in_drive_list(id, drive_blacklist); + if (blacklist) + printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); + return(blacklist); + } +#else + const char **list; + + if (good_bad) { + /* Consult the list of known "good" drives */ + list = good_dma_drives; + while (*list) { + if (!strcmp(*list++,id->model)) + return 1; + } + } else { + /* Consult the list of known "bad" drives */ + list = bad_dma_drives; + while (*list) { + if (!strcmp(*list++,id->model)) { + printk("%s: Disabling (U)DMA for %s\n", + drive->name, id->model); + return 1; + } + } + } +#endif + return 0; +} + +void udma_print(struct ata_device *drive) +{ +#ifdef CONFIG_ARCH_ACORN + printk(", DMA"); +#else + struct hd_driveid *id = drive->id; + char *str = NULL; + + if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && + (id->dma_ultra & (id->dma_ultra >> 14) & 3)) { + if ((id->dma_ultra >> 15) & 1) + str = ", UDMA(mode 7)"; /* UDMA BIOS-enabled! */ + else + str = ", UDMA(133)"; /* UDMA BIOS-enabled! */ + } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && + (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { + if ((id->dma_ultra >> 13) & 1) { + str = ", UDMA(100)"; /* UDMA BIOS-enabled! */ + } else if ((id->dma_ultra >> 12) & 1) { + str = ", UDMA(66)"; /* UDMA BIOS-enabled! */ + } else { + str = ", UDMA(44)"; /* UDMA BIOS-enabled! */ + } + } else if ((id->field_valid & 4) && + (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { + if ((id->dma_ultra >> 10) & 1) { + str = ", UDMA(33)"; /* UDMA BIOS-enabled! */ + } else if ((id->dma_ultra >> 9) & 1) { + str = ", UDMA(25)"; /* UDMA BIOS-enabled! */ + } else { + str = ", UDMA(16)"; /* UDMA BIOS-enabled! */ + } + } else if (id->field_valid & 4) + str = ", (U)DMA"; /* Can be BIOS-enabled! */ + else + str = ", DMA"; + + printk(str); +#endif +} + +/* + * Drive back/white list handling for UDMA capability: + */ + +int udma_black_list(struct ata_device *drive) +{ + return check_drive_lists(drive, 0); +} + +int udma_white_list(struct ata_device *drive) +{ + return check_drive_lists(drive, 1); +} + +EXPORT_SYMBOL(udma_print); +EXPORT_SYMBOL(udma_black_list); +EXPORT_SYMBOL(udma_white_list); |
