diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-03 01:22:27 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-03 01:22:27 +0000 |
commit | f9bbe9da79dbc8557c74efeb158b431cd67ace52 (patch) | |
tree | 3220d014a35f9d88a48668a1468524e988daebff /drivers/block | |
parent | 3d697109c1ff85ef563aec3d5e113ef225ed2792 (diff) |
Upgrade to 2.1.73.
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/Config.in | 24 | ||||
-rw-r--r-- | drivers/block/Makefile | 18 | ||||
-rw-r--r-- | drivers/block/ali14xx.c | 1 | ||||
-rw-r--r-- | drivers/block/cmd640.c | 1 | ||||
-rw-r--r-- | drivers/block/dtc2278.c | 1 | ||||
-rw-r--r-- | drivers/block/ht6560b.c | 2 | ||||
-rw-r--r-- | drivers/block/ide-cd.c | 93 | ||||
-rw-r--r-- | drivers/block/ide-cd.h | 10 | ||||
-rw-r--r-- | drivers/block/ide-disk.c | 65 | ||||
-rw-r--r-- | drivers/block/ide-dma.c | 473 | ||||
-rw-r--r-- | drivers/block/ide-floppy.c | 113 | ||||
-rw-r--r-- | drivers/block/ide-pci.c | 382 | ||||
-rw-r--r-- | drivers/block/ide-probe.c | 107 | ||||
-rw-r--r-- | drivers/block/ide-proc.c | 505 | ||||
-rw-r--r-- | drivers/block/ide-tape.c | 141 | ||||
-rw-r--r-- | drivers/block/ide.c | 252 | ||||
-rw-r--r-- | drivers/block/ide.h | 93 | ||||
-rw-r--r-- | drivers/block/ll_rw_blk.c | 26 | ||||
-rw-r--r-- | drivers/block/ns87415.c | 228 | ||||
-rw-r--r-- | drivers/block/opti621.c | 28 | ||||
-rw-r--r-- | drivers/block/pdc4030.c | 8 | ||||
-rw-r--r-- | drivers/block/qd6580.c | 1 | ||||
-rw-r--r-- | drivers/block/rz1000.c | 43 | ||||
-rw-r--r-- | drivers/block/trm290.c | 181 | ||||
-rw-r--r-- | drivers/block/umc8672.c | 1 |
25 files changed, 1867 insertions, 930 deletions
diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 220148670..b76e9af08 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -23,26 +23,28 @@ else fi if [ "$CONFIG_PCI" = "y" ]; then bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 - bool ' PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA - if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then + bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI + if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then + bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Tekram TRM290 DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - bool ' OPTi 82C621 enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 + bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 + bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 + bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 fi fi fi bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then comment 'Note: most of these also require special kernel boot parameters' - bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES - bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX - bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 - bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B + bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES + bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX + bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 + bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B + bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 + bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 fi - bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 - bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 fi fi fi diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 50e9f6be6..f992a98a5 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -79,11 +79,17 @@ L_OBJS += hd.o endif ifeq ($(CONFIG_BLK_DEV_IDE),y) -LX_OBJS += ide.o -L_OBJS += ide-probe.o + LX_OBJS += ide.o + ifeq ($(CONFIG_PROC_FS),y) + L_OBJS += ide-proc.o + endif + L_OBJS += ide-probe.o else ifeq ($(CONFIG_BLK_DEV_IDE),m) MX_OBJS += ide.o + ifeq ($(CONFIG_PROC_FS),y) + M_OBJS += ide-proc.o + endif M_OBJS += ide-probe.o endif endif @@ -96,6 +102,10 @@ ifeq ($(CONFIG_BLK_DEV_CMD640),y) L_OBJS += cmd640.o endif +ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) +L_OBJS += ide-pci.o +endif + ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) L_OBJS += ide-dma.o endif @@ -137,6 +147,10 @@ ifeq ($(CONFIG_BLK_DEV_OPTI621),y) L_OBJS += opti621.o endif +ifeq ($(CONFIG_BLK_DEV_NS87415),y) +L_OBJS += ns87415.o +endif + ifeq ($(CONFIG_BLK_DEV_IDEDISK),y) L_OBJS += ide-disk.o else diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index 5f6c0f437..c0c7762d6 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -213,6 +213,7 @@ void init_ali14xx (void) ide_hwifs[1].tuneproc = &ali14xx_tune_drive; ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; + ide_hwifs[1].channel = 1; /* initialize controller registers */ if (!initRegisters()) { diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index e833a2bd0..5ffbefaf0 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -797,6 +797,7 @@ int ide_probe_for_cmd640x (void) cmd_hwif1->chipset = ide_cmd640; cmd_hwif0->mate = cmd_hwif1; cmd_hwif1->mate = cmd_hwif0; + cmd_hwif1->channel = 1; #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED cmd_hwif1->tuneproc = &cmd640_tune_drive; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index 30988bd99..63b9143b6 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -127,4 +127,5 @@ void init_dtc2278 (void) ide_hwifs[1].drives[1].no_unmask = 1; ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; + ide_hwifs[1].channel = 1; } diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c index 9d888cfc0..b739f39ee 100644 --- a/drivers/block/ht6560b.c +++ b/drivers/block/ht6560b.c @@ -155,7 +155,6 @@ static void ht6560b_selectproc (ide_drive_t *drive) printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing); #endif } - OUT_BYTE(drive->select.all,IDE_SELECT_REG); } /* @@ -229,6 +228,7 @@ void init_ht6560b (void) ide_hwifs[1].serialized = 1; ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; + ide_hwifs[1].channel = 1; } else printk("\nht6560b: not found\n"); } diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 02f97ec6f..3a8e48722 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -2,7 +2,7 @@ /* * linux/drivers/block/ide-cd.c * Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov> - * Copyright (C) 1996, 1997 Erik Andersen <andersee@debian.org> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * @@ -27,13 +27,6 @@ * unless you have a patch to fix it. I am working on it...) * -Implement ide_cdrom_select_speed using the generic cdrom interface * -Fix ide_cdrom_reset so that it works (it does nothing right now) - * -When trying to mount a cdrom with the tray open, you get an billion - * "tray open or drive not ready" messages until the tray gets closed. - * This is because ide-cd does not properly return drive_status immediatly, - * but instead waits for the drive to close first (bad, bad, bad) - * and keeps on trying, and failing... This bug was revealed by the - * recent changes to the Uniform CD-ROm driver, and I havn't had a - * chance to fix it yet. * * MOSTLY DONE LIST: * Query the drive to find what features are available @@ -185,8 +178,13 @@ * Added identifier so new Sanyo CD-changer works * Better detection if door locking isn't supported * + * 4.06 Dec 17, 1997 -- fixed endless "tray open" messages -ml + * 4.07 Dec 17, 1997 -- fallback to set pc->stat on "tray open" + * *************************************************************************/ +#define IDECD_VERSION "4.07" + #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -194,11 +192,8 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/malloc.h> -#include <linux/ioport.h> #include <linux/interrupt.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/cdrom.h> #include <asm/irq.h> #include <asm/io.h> @@ -418,7 +413,8 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive) (struct packet_command *) pc->sense_data); } - + if (rq->cmd == READ && !rq->current_nr_sectors) + uptodate = 1; ide_end_request (uptodate, HWGROUP(drive)); } @@ -443,7 +439,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, sense_key = err >> 4; if (rq == NULL) - printk ("%s : missing request in cdrom_decode_status\n", + printk ("%s: missing request in cdrom_decode_status\n", drive->name); else { cmd = rq->cmd; @@ -477,16 +473,13 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, because workman constantly polls the drive with this command, and we don't want to uselessly fill up the syslog. */ - if (pc->c[0] != SCMD_READ_SUBCHANNEL) { + if (pc->c[0] != SCMD_READ_SUBCHANNEL) printk ("%s: tray open or drive not ready\n", drive->name); - return 1; - } } else if (sense_key == UNIT_ATTENTION) { /* Check for media change. */ cdrom_saw_media_change (drive); - printk (" %s: media changed\n", drive->name); - return 0; + printk ("%s: media changed\n", drive->name); } else { /* Otherwise, print an error. */ ide_dump_status (drive, "packet command error", @@ -521,7 +514,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, cdrom_saw_media_change (drive); /* Fail the request. */ - printk ("%s : tray open\n", drive->name); + printk ("%s: tray open\n", drive->name); cdrom_end_request (0, drive); } else if (sense_key == UNIT_ATTENTION) { /* Media change. */ @@ -591,7 +584,6 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, if (info->dma) (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); - if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { ide_set_handler (drive, handler, WAIT_CMD); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ @@ -619,7 +611,8 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive, int stat_dum; /* Check for errors. */ - if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1; + if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) + return 1; } else { /* Otherwise, we must wait for DRQ to get set. */ if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) @@ -746,12 +739,12 @@ static void cdrom_read_intr (ide_drive_t *drive) /* Check for errors. */ if (dma) { info->dma = 0; - if ((dma_error = HWIF(drive)->dmaproc(ide_dma_status_bad, drive))) + if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) HWIF(drive)->dmaproc(ide_dma_off, drive); - (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); } - if (cdrom_decode_status (drive, 0, &stat)) return; + if (cdrom_decode_status (drive, 0, &stat)) + return; if (dma) { if (!dma_error) { @@ -764,7 +757,6 @@ static void cdrom_read_intr (ide_drive_t *drive) return; } - /* Read the interrupt reason and the transfer length. */ ireason = IN_BYTE (IDE_NSECTOR_REG); len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG); @@ -779,7 +771,6 @@ static void cdrom_read_intr (ide_drive_t *drive) cdrom_end_request (0, drive); } else cdrom_end_request (1, drive); - return; } @@ -990,7 +981,8 @@ static void cdrom_seek_intr (ide_drive_t *drive) int stat; static int retry = 10; - if (cdrom_decode_status (drive, 0, &stat)) return; + if (cdrom_decode_status (drive, 0, &stat)) + return; CDROM_CONFIG_FLAGS(drive)->seeking = 1; if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { @@ -1088,7 +1080,8 @@ static void cdrom_pc_intr (ide_drive_t *drive) struct packet_command *pc = (struct packet_command *)rq->buffer; /* Check for errors. */ - if (cdrom_decode_status (drive, 0, &stat)) return; + if (cdrom_decode_status (drive, 0, &stat)) + return; /* Read the interrupt reason and the transfer length. */ ireason = IN_BYTE (IDE_NSECTOR_REG); @@ -1251,8 +1244,11 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) ide_init_drive_cmd (&req); req.cmd = PACKET_COMMAND; req.buffer = (char *)pc; - (void) ide_do_drive_cmd (drive, &req, ide_wait); - + if (ide_do_drive_cmd (drive, &req, ide_wait)) { + printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n", + drive->name, req.buffer[0], req.buffer[1]); + /* FIXME: we should probably abort/retry or something */ + } if (pc->stat != 0) { /* The request failed. Retry if it was due to a unit attention status @@ -2692,7 +2688,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) static int ide_cdrom_probe_capabilities (ide_drive_t *drive) { - int stat, nslots; + int stat, nslots, attempts = 3; struct { char pad[8]; struct atapi_capabilities_page cap; @@ -2703,14 +2699,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) if (CDROM_CONFIG_FLAGS (drive)->nec260) return nslots; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, - (char *)&buf, sizeof (buf), NULL); - if (stat) - return nslots; + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + if (attempts-- <= 0) + return 0; + stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, + (char *)&buf, sizeof (buf), NULL); + } while (stat); if (buf.cap.lock == 0) CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; - if (buf.cap.cd_r_write) CDROM_CONFIG_FLAGS (drive)->cd_r = 1; if (buf.cap.cd_rw_write) @@ -2737,11 +2734,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) } } - CDROM_STATE_FLAGS (drive)->curent_speed = ntohs(buf.cap.curspeed)/176; - CDROM_CONFIG_FLAGS (drive)->max_speed = ntohs(buf.cap.maxspeed)/176; + if (drive->id && drive->id->model[0]) { + CDROM_STATE_FLAGS (drive)->current_speed = (ntohs(buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176; + } else { /* no-name ACERs (AOpen) have it backwards */ + CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; + } - stat=0; - printk ("%s: ATAPI %dx CDROM", + printk ("%s: ATAPI %dX CDROM", drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed); if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) printk (" CD%s%s", @@ -2827,7 +2828,7 @@ int ide_cdrom_setup (ide_drive_t *drive) else if (strcmp (drive->id->model, "NEC CD-ROM DRIVE:260") == 0 && - strcmp (drive->id->fw_rev, "1.01") == 0) { + strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */ /* Old NEC260 (not R). This drive was released before the 1.2 version of the spec. */ @@ -2838,7 +2839,7 @@ int ide_cdrom_setup (ide_drive_t *drive) } else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 && - strcmp (drive->id->fw_rev, "A1.1") == 0) { + strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */ /* Wearnes */ CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1; CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1; @@ -2936,21 +2937,23 @@ static ide_module_t ide_cdrom_module = { }; static ide_driver_t ide_cdrom_driver = { + "ide-cdrom", /* name */ + IDECD_VERSION, /* version */ ide_cdrom, /* media */ 0, /* busy */ 1, /* supports_dma */ 1, /* supports_dsc_overlap */ ide_cdrom_cleanup, /* cleanup */ ide_do_rw_cdrom, /* do_request */ - NULL, /* ??? or perhaps - cdrom_end_request? */ + NULL, /* ??? or perhaps cdrom_end_request? */ ide_cdrom_ioctl, /* ioctl */ ide_cdrom_open, /* open */ ide_cdrom_release, /* release */ ide_cdrom_check_media_change, /* media_change */ NULL, /* pre_reset */ NULL, /* capacity */ - NULL /* special */ + NULL, /* special */ + NULL /* proc */ }; diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index afb3e5dbe..53e38e1b1 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -119,11 +119,11 @@ struct ide_cd_config_flags { __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ __u8 supp_disc_present: 1; /* Changer can report exact contents of slots. */ - __u8 max_speed : 4; /* Max speed of the drive */ __u8 seeking : 1; /* Seeking in progress */ __u8 reserved : 6; + byte max_speed; /* Max speed of the drive */ }; -#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_cyl)) +#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) /* State flags. These give information about the current state of the @@ -133,10 +133,10 @@ struct ide_cd_state_flags { __u8 toc_valid : 1; /* Saved TOC information is current. */ __u8 door_locked : 1; /* We think that the drive door is locked. */ __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 curent_speed : 4; /* Current speed of the drive */ __u8 reserved : 3; + byte current_speed; /* Current speed of the drive */ }; -#define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head)) +#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) struct atapi_request_sense { @@ -385,6 +385,8 @@ struct cdrom_info { /* Buffer to hold mechanism status and changer slot table. */ struct atapi_changer_info *changer_info; + struct ide_cd_config_flags config_flags; + struct ide_cd_state_flags state_flags; /* Per-device info needed by cdrom.c generic driver. */ struct cdrom_device_info devinfo; diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index f75a1a5be..5e178b6cd 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -10,32 +10,6 @@ * * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. * - * From hd.c: - * | - * | It traverses the request-list, using interrupts to jump between functions. - * | As nearly all functions can be called within interrupts, we may not sleep. - * | Special care is recommended. Have Fun! - * | - * | modified by Drew Eckhardt to check nr of hd's from the CMOS. - * | - * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * | in the early extended-partition checks and added DM partitions. - * | - * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI). - * | - * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", - * | and general streamlining by Mark Lord (mlord@pobox.com). - * - * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: - * - * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) - * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2") - * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) - * - * This was a rewrite of just about everything from hd.c, though some original - * code is still sprinkled about. Think of it as a major evolution, with - * inspiration from lots of linux users, esp. hamish@zot.apana.org.au - * * Version 1.00 move disk only code from ide.c to ide-disk.c * support optional byte-swapping of all data * Version 1.01 fix previous byte-swapping code @@ -43,6 +17,8 @@ * Verions 1.03 fix display of id->buf_size for big-endian */ +#define IDEDISK_VERSION "1.03" + #undef REALLY_SLOW_IO /* most systems can safely undef this */ #include <linux/config.h> @@ -52,12 +28,9 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/major.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/malloc.h> #include <linux/delay.h> @@ -319,7 +292,7 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); #ifdef CONFIG_BLK_DEV_PDC4030 if (IS_PDC4030_DRIVE) { - if (hwif->is_pdc4030_2 || rq->cmd == READ) { + if (hwif->channel != 0 || rq->cmd == READ) { use_pdc4030_io = 1; } } @@ -494,6 +467,11 @@ static void idedisk_pre_reset (ide_drive_t *drive) drive->special.b.set_multmode = 1; } +static ide_proc_entry_t idedisk_proc[] = { + { "geometry", proc_ide_read_geometry, NULL }, + { NULL, NULL, NULL } +}; + int idedisk_init (void); static ide_module_t idedisk_module = { IDE_DRIVER_MODULE, @@ -505,6 +483,8 @@ static ide_module_t idedisk_module = { * IDE subdriver functions, registered with ide.c */ static ide_driver_t idedisk_driver = { + "ide-disk", /* name */ + IDEDISK_VERSION, /* version */ ide_disk, /* media */ 0, /* busy */ 1, /* supports_dma */ @@ -518,7 +498,8 @@ static ide_driver_t idedisk_driver = { idedisk_media_change, /* media_change */ idedisk_pre_reset, /* pre_reset */ idedisk_capacity, /* capacity */ - idedisk_special /* special */ + idedisk_special, /* special */ + idedisk_proc /* proc */ }; static int idedisk_cleanup (ide_drive_t *drive) @@ -526,20 +507,6 @@ static int idedisk_cleanup (ide_drive_t *drive) return ide_unregister_subdriver(drive); } -static int idedisk_identify_device (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - - if (id == NULL) - return 0; - - /* SunDisk drives: force one unit */ - if (id->model[0] == 'S' && id->model[1] == 'u' && (drive->select.all & (1<<4))) - return 1; - - return 0; -} - static void idedisk_setup (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -554,7 +521,7 @@ static void idedisk_setup (ide_drive_t *drive) drive->removable = 1; } - /* SunDisk drives: treat as non-removable */ + /* SunDisk drives: treat as non-removable; can mess up non-Sun systems! FIXME */ if (id->model[0] == 'S' && id->model[1] == 'u') drive->removable = 0; @@ -634,8 +601,12 @@ int idedisk_init (void) MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_disk, NULL, failed++)) != NULL) { - if (idedisk_identify_device (drive)) + + /* SunDisk drives: ignore "second" drive; can mess up non-Sun systems! FIXME */ + struct hd_driveid *id = drive->id; + if (id && id->model[0] == 'S' && id->model[1] == 'u' && drive->select.b.unit) continue; + if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); continue; diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 6a2886f78..bba735580 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.06 December 3, 1997 + * linux/drivers/block/ide-dma.c Version 4.07 December 5, 1997 * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -49,9 +49,8 @@ * 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 some (all?) ACER motherboards/BIOSs. Hopefully the fix - * still works here (?). + * 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. @@ -69,16 +68,12 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/pci.h> #include <linux/bios32.h> -#include <linux/init.h> #include <asm/io.h> -#include <asm/dma.h> +#include <asm/irq.h> #include "ide.h" @@ -110,23 +105,19 @@ const char *good_dma_drives[] = {"Micropolis 2112A", #define PRD_BYTES 8 #define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES)) -static int config_drive_for_dma (ide_drive_t *); - /* * dma_intr() is the handler for disk read/write DMA interrupts */ -static void dma_intr (ide_drive_t *drive) +void ide_dma_intr (ide_drive_t *drive) { - byte stat, dma_stat; int i; - struct request *rq = HWGROUP(drive)->rq; - unsigned short dma_base = HWIF(drive)->dma_base; + byte stat, dma_stat; - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */ + dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive); stat = GET_STAT(); /* get drive status */ if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { - if ((dma_stat & 7) == 4) { /* verify good DMA status */ + if (!dma_stat) { + struct request *rq = HWGROUP(drive)->rq; rq = HWGROUP(drive)->rq; for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; @@ -134,7 +125,7 @@ static void dma_intr (ide_drive_t *drive) } return; } - printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat); + printk("%s: dma_intr: bad DMA status\n", drive->name); } sti(); ide_error(drive, "dma_intr", stat); @@ -195,23 +186,46 @@ int ide_build_dmatable (ide_drive_t *drive) unsigned long xcount, bcount = 0x10000 - (addr & 0xffff); if (bcount > size) bcount = size; - *table++ = addr; + *table++ = cpu_to_le32(addr); xcount = bcount & 0xffff; if (is_trm290_chipset) xcount = ((xcount >> 2) - 1) << 16; - *table++ = xcount; + *table++ = cpu_to_le32(xcount); addr += bcount; size -= bcount; } } } while (bh != NULL); - if (count) { - if (!is_trm290_chipset) - *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */ - return count; + if (!count) + printk("%s: empty DMA table?\n", drive->name); + else if (!is_trm290_chipset) + *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */ + return count; +} + +static int config_drive_for_dma (ide_drive_t *drive) +{ + const char **list; + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + + if (id && (id->capability & 1) && !HWIF(drive)->no_autodma) { + /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ + if (id->field_valid & 4) /* UltraDMA */ + if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) + return hwif->dmaproc(ide_dma_on, drive); + /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */ + if (id->field_valid & 2) /* regular DMA */ + if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) + return hwif->dmaproc(ide_dma_on, drive); + /* Consult the list of known "good" drives */ + list = good_dma_drives; + while (*list) { + if (!strcmp(*list++,id->model)) + return hwif->dmaproc(ide_dma_on, drive); + } } - printk("%s: empty DMA table?\n", drive->name); - return 0; + return hwif->dmaproc(ide_dma_off_quietly, drive); } /* @@ -233,7 +247,7 @@ int ide_build_dmatable (ide_drive_t *drive) int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned long dma_base = hwif->dma_base; + unsigned int dma_base = hwif->dma_base; unsigned int count, reading = 0; switch (func) { @@ -243,21 +257,8 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_on: drive->using_dma = (func == ide_dma_on); return 0; - case ide_dma_abort: - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - return 0; case ide_dma_check: return config_drive_for_dma (drive); - case ide_dma_status_bad: - return ((inb(dma_base+2) & 7) != 4); /* verify good DMA status */ - case ide_dma_transferred: - return 0; /* NOT IMPLEMENTED: number of bytes actually transferred */ - case ide_dma_begin: - outb(inb(dma_base)|1, dma_base); /* begin DMA */ - return 0; - default: - printk("ide_dmaproc: unsupported func: %d\n", func); - return 1; case ide_dma_read: reading = 1 << 3; case ide_dma_write: @@ -268,50 +269,37 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */ if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - outb(inb(dma_base)|1, dma_base); /* begin DMA */ + case ide_dma_begin: + outb(inb(dma_base)|1, dma_base); /* start DMA */ return 0; - } -} - -static int config_drive_for_dma (ide_drive_t *drive) -{ - const char **list; - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - - if (id && (id->capability & 1)) { - /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ - if (id->field_valid & 4) /* UltraDMA */ - if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) - return hwif->dmaproc(ide_dma_on, drive); - /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */ - if (id->field_valid & 2) /* regular DMA */ - if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) - return hwif->dmaproc(ide_dma_on, drive); - /* Consult the list of known "good" drives */ - list = good_dma_drives; - while (*list) { - if (!strcmp(*list++,id->model)) - return hwif->dmaproc(ide_dma_on, drive); + case ide_dma_end: /* returns 1 on error, 0 otherwise */ + { + byte dma_stat = inb(dma_base+2); + int rc = (dma_stat & 7) != 4; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + return rc; /* verify good DMA status */ } + default: + printk("ide_dmaproc: unsupported func: %d\n", func); + return 1; } - return hwif->dmaproc(ide_dma_off_quietly, drive); } -void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports) +void ide_setup_dma (ide_hwif_t *hwif, unsigned int dma_base, unsigned int num_ports) /* __init */ { static unsigned long dmatable = 0; static unsigned leftover = 0; - printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dmabase, dmabase + num_ports - 1); - if (check_region(dmabase, num_ports)) { + printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dma_base, dma_base + num_ports - 1); + if (check_region(dma_base, num_ports)) { printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n"); return; } - request_region(dmabase, num_ports, hwif->name); - hwif->dma_base = dmabase; + request_region(dma_base, num_ports, hwif->name); + hwif->dma_base = dma_base; if (leftover < (PRD_ENTRIES * PRD_BYTES)) { /* * The BM-DMA uses full 32bit addr, so we can @@ -328,87 +316,18 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_p dmatable += (PRD_ENTRIES * PRD_BYTES); leftover -= (PRD_ENTRIES * PRD_BYTES); hwif->dmaproc = &ide_dmaproc; + if (hwif->chipset != ide_trm290) { - byte dma_stat = inb(dmabase+2); - printk(", BIOS DMA settings: %s:%s %s:%s", - hwif->drives[0].name, (dma_stat & 0x20) ? "yes" : "no ", - hwif->drives[1].name, (dma_stat & 0x40) ? "yes" : "no"); + byte dma_stat = inb(dma_base+2); + printk(", BIOS settings: %s:%s, %s:%s", + hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", + hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); } printk("\n"); } } -#ifdef CONFIG_BLK_DEV_TRM290 -extern void ide_init_trm290(byte, byte, ide_hwif_t *); -#define INIT_TRM290 (&ide_init_trm290) -#else -#define INIT_TRM290 (NULL) -#endif /* CONFIG_BLK_DEV_TRM290 */ - -#ifdef CONFIG_BLK_DEV_OPTI621 -extern void ide_init_opti621(byte, byte, ide_hwif_t *); -#define INIT_OPTI (&ide_init_opti621) -#else -#define INIT_OPTI (NULL) -#endif /* CONFIG_BLK_DEV_OPTI621 */ - -#define DEVID_PIIX (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371_1 <<16)) -#define DEVID_PIIX3 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371SB_1 <<16)) -#define DEVID_PIIX4 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371AB <<16)) -#define DEVID_VP_IDE (PCI_VENDOR_ID_VIA |(PCI_DEVICE_ID_VIA_82C586_1 <<16)) -#define DEVID_PDC20246 (PCI_VENDOR_ID_PROMISE|(PCI_DEVICE_ID_PROMISE_20246 <<16)) -#define DEVID_RZ1000 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1000 <<16)) -#define DEVID_RZ1001 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1001 <<16)) -#define DEVID_CMD640 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_640 <<16)) -#define DEVID_CMD646 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_646 <<16)) -#define DEVID_SIS5513 (PCI_VENDOR_ID_SI |(PCI_DEVICE_ID_SI_5513 <<16)) -#define DEVID_OPTI (PCI_VENDOR_ID_OPTI |(PCI_DEVICE_ID_OPTI_82C621 <<16)) -#define DEVID_OPTI2 (PCI_VENDOR_ID_OPTI |(0xd568 /* from datasheets */ <<16)) -#define DEVID_TRM290 (PCI_VENDOR_ID_TEKRAM |(PCI_DEVICE_ID_TEKRAM_DC290 <<16)) -#define DEVID_NS87410 (PCI_VENDOR_ID_NS |(PCI_DEVICE_ID_NS_87410 <<16)) -#define DEVID_HT6565 (PCI_VENDOR_ID_HOLTEK |(PCI_DEVICE_ID_HOLTEK_6565 <<16)) - -typedef struct ide_pci_enablebit_s { - byte reg; /* byte pci reg holding the enable-bit */ - byte mask; /* mask to isolate the enable-bit */ - byte val; /* value of masked reg when "enabled" */ -} ide_pci_enablebit_t; - -typedef struct ide_pci_device_s { - unsigned int id; - const char *name; - void (*init_hwif)(byte bus, byte fn, ide_hwif_t *hwif); - ide_pci_enablebit_t enablebits[2]; -} ide_pci_device_t; - -static ide_pci_device_t ide_pci_chipsets[] = { - {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, - {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, - {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, - {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} }, - {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} }, - {DEVID_RZ1000, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, - {DEVID_RZ1001, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, - {DEVID_CMD640, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, - {DEVID_OPTI, "OPTI", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} }, - {DEVID_OPTI2, "OPTI2", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} }, - {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} }, - {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} }, - {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, - {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} }, - {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, - {0, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }}; - -__initfunc(static ide_pci_device_t *lookup_devid(unsigned int devid)) -{ - ide_pci_device_t *d = ide_pci_chipsets; - while (d->id && d->id != devid) - ++d; - return d; -} - -/* The next two functions were stolen from cmd640.c, with - a few modifications */ +/* The next two functions were stolen from cmd640.c, with a few modifications */ __initfunc(static void write_pcicfg_dword (byte fn, unsigned short reg, long val)) { @@ -435,244 +354,50 @@ __initfunc(static long read_pcicfg_dword (byte fn, unsigned short reg)) } /* - * Search for an (apparently) unused block of I/O space - * of "size" bytes in length. - */ -__initfunc(static short find_free_region (unsigned short size)) -{ - unsigned short i, base = 0xe800; - for (base = 0xe800; base > 0; base -= 0x800) { - if (!check_region(base,size)) { - for (i = 0; i < size; i++) { - if (inb(base+i) != 0xff) - goto next; - } - return base; /* success */ - } - next: - } - return 0; /* failure */ -} - -/* - * Fetch the Bus-Master I/O Base-Address (BMIBA) from PCI space: + * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: */ -__initfunc(static unsigned int ide_get_or_set_bmiba (byte bus, byte fn, const char *name)) +unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) /* __init */ { - unsigned int bmiba = 0; - unsigned short base; - int rc; - - if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba))) { - printk("%s: failed to read BMIBA\n", name); - } else if ((bmiba &= 0xfff0) == 0) { - printk("%s: BMIBA is invalid (0x%04x, BIOS problem)\n", name, bmiba); - base = find_free_region(16); - if (base) { - printk("%s: setting BMIBA to 0x%04x\n", name, base); - pcibios_write_config_dword(bus, fn, 0x20, base | 1); - pcibios_read_config_dword(bus, fn, 0x20, &bmiba); - bmiba &= 0xfff0; - if (bmiba != base) { + unsigned int new, dma_base = 0; + byte bus = hwif->pci_bus, fn = hwif->pci_fn; + + if (hwif->mate && hwif->mate->dma_base) { + dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); + } else if (pcibios_read_config_dword(bus, fn, 0x20, &dma_base)) { + printk("%s: failed to read dma_base\n", name); + dma_base = 0; + } else if ((dma_base &= ~0xf) == 0 || dma_base == ~0xf) { + printk("%s: dma_base is invalid (0x%04x, BIOS problem)\n", name, dma_base); + new = ide_find_free_region(16 + extra); + hwif->no_autodma = 1; /* default DMA off if we had to configure it here */ + if (new) { + printk("%s: setting dma_base to 0x%04x\n", name, new); + new |= 1; + (void) pcibios_write_config_dword(bus, fn, 0x20, new); + (void) pcibios_read_config_dword(bus, fn, 0x20, &dma_base); + if (dma_base != new) { if (bus == 0) { printk("%s: operation failed, bypassing BIOS to try again\n", name); - write_pcicfg_dword(fn, 0x20, base | 1); - bmiba = read_pcicfg_dword(fn, 0x20) & 0xfff0; + write_pcicfg_dword(fn, 0x20, new); + dma_base = read_pcicfg_dword(fn, 0x20); } - if (bmiba != base) { + if (dma_base != new) { printk("%s: operation failed, DMA disabled\n", name); - bmiba = 0; + dma_base = 0; } } + dma_base &= ~0xf; } } - return bmiba; -} - -/* - * Match a PCI IDE port against an entry in ide_hwifs[], - * based on io_base port if possible. - */ -__initfunc(ide_hwif_t *ide_match_hwif (unsigned int io_base)) -{ - int h; - ide_hwif_t *hwif; - - /* - * Look for a hwif with matching io_base specified using - * parameters to ide_setup(). - */ - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { - if (hwif->chipset == ide_generic) - return hwif; /* a perfect match */ - } - } - /* - * Look for a hwif with matching io_base default value. - * If chipset is "ide_unknown", then claim that hwif slot. - * Otherwise, some other chipset has already claimed it.. :( - */ - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { - if (hwif->chipset == ide_unknown) - return hwif; /* match */ - return NULL; /* already claimed */ - } - } - /* - * Okay, there is no hwif matching our io_base, - * so we'll just claim an unassigned slot. - * Give preference to claiming ide2/ide3 before ide0/ide1, - * just in case there's another interface yet-to-be-scanned - * which uses ports 1f0/170 (the ide0/ide1 defaults). - */ - for (h = 0; h < MAX_HWIFS; ++h) { - int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */ - hwif = &ide_hwifs[hwifs[h]]; - if (hwif->chipset == ide_unknown) - return hwif; /* pick an unused entry */ - } - return NULL; -} - -/* - * ide_setup_pci_device() looks at the primary/secondary interfaces - * on a PCI IDE device and, if they are enabled, prepares the IDE driver - * for use with them. This generic code works for most PCI chipsets. - * - * One thing that is not standardized is the location of the - * primary/secondary interface "enable/disable" bits. For chipsets that - * we "know" about, this information is in the ide_pci_device_t struct; - * for all other chipsets, we just assume both interfaces are enabled. - */ -__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int bmiba, ide_pci_device_t *d)) -{ - unsigned int port, at_least_one_hwif_enabled = 0; - unsigned short base = 0, ctl = 0; - byte tmp = 0; - ide_hwif_t *hwif, *mate = NULL; - - for (port = 0; port <= 1; ++port) { - ide_pci_enablebit_t *e = &(d->enablebits[port]); - if (e->reg) { - if (pcibios_read_config_byte(bus, fn, e->reg, &tmp)) { - printk("%s: unable to read pci reg 0x%x\n", d->name, e->reg); - } else if ((tmp & e->mask) != e->val) - continue; /* port not enabled */ - } - if (pcibios_read_config_word(bus, fn, 0x14+(port*8), &ctl)) - ctl = 0; - if ((ctl &= 0xfffc) == 0) - ctl = 0x3f4 ^ (port << 7); - if (pcibios_read_config_word(bus, fn, 0x10+(port*8), &base)) - base = 0; - if ((base &= 0xfff8) == 0) - base = 0x1F0 ^ (port << 7); - if ((hwif = ide_match_hwif(base)) == NULL) { - printk("%s: no room in hwif table for port %d\n", d->name, port); - continue; - } - hwif->chipset = ide_pci; - hwif->pci_port = port; - if (mate) { - hwif->mate = mate; - mate->mate = hwif; - } - mate = hwif; /* for next iteration */ - if (hwif->io_ports[IDE_DATA_OFFSET] != base) { - ide_init_hwif_ports(hwif->io_ports, base, NULL); - hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2; - } - if (bmiba) { - if ((inb(bmiba+2) & 0x80)) { /* simplex DMA only? */ - printk("%s: simplex device: DMA disabled\n", d->name); - } else { /* supports simultaneous DMA on both channels */ - ide_setup_dma(hwif, bmiba + (8 * port), 8); - } - } - if (d->id) { /* For "known" chipsets, allow other irqs during i/o */ - hwif->drives[0].unmask = 1; - hwif->drives[1].unmask = 1; - } - if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ - d->init_hwif(bus, fn, hwif); - at_least_one_hwif_enabled = 1; - } - if (!at_least_one_hwif_enabled) - printk("%s: neither IDE port enabled (BIOS)\n", d->name); -} - -/* - * ide_scan_pci_device() examines all functions of a PCI device, - * looking for IDE interfaces and/or devices in ide_pci_chipsets[]. - */ -__initfunc(static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)) -{ - unsigned int devid, ccode; - unsigned short pcicmd, class; - ide_pci_device_t *d; - byte hedt, progif; - - if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt)) - hedt = 0; - do { - if (pcibios_read_config_dword(bus, fn, 0x00, &devid) - || devid == 0xffffffff - || pcibios_read_config_dword(bus, fn, 0x08, &ccode)) - return; - d = lookup_devid(devid); - if (d->name == NULL) /* some chips (cmd640, rz1000) are handled elsewhere */ - continue; - progif = (ccode >> 8) & 0xff; - class = ccode >> 16; - if (d->id || class == PCI_CLASS_STORAGE_IDE) { - if (d->id) - printk("%s: IDE device on PCI bus %d function %d\n", d->name, bus, fn); - else - printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n", - d->name, bus, fn, devid & 0xffff, devid >> 16); - /* - * See if IDE ports are enabled - */ - if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) { - printk("%s: error accessing PCICMD\n", d->name); - } else if ((pcicmd & 1) == 0) { - printk("%s: device disabled (BIOS)\n", d->name); - } else { - unsigned int bmiba = 0; - /* - * Check for Bus-Master DMA capability - */ - if (d->id == DEVID_PDC20246 || (class == PCI_CLASS_STORAGE_IDE && (progif & 0x80))) { - if ((!(pcicmd & 4) || !(bmiba = ide_get_or_set_bmiba(bus, fn, d->name)))) { - printk("%s: Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, progif=0x%02x, bmiba=0x%04x\n", d->name, pcicmd, progif, bmiba); - } - } - /* - * Setup the IDE ports - */ - ide_setup_pci_device(bus, fn, bmiba, d); - } - } - } while (hedt == 0x80 && (++fn & 7)); -} - -/* - * ide_scan_pcibus() gets invoked at boot time from ide.c - */ -__initfunc(void ide_scan_pcibus (void)) -{ - unsigned int bus, dev; - - if (!pcibios_present()) - return; - for (bus = 0; bus <= 255; ++bus) { - for (dev = 0; dev <= 31; ++dev) { - ide_scan_pci_device(bus, dev << 3); + if (dma_base) { + if (extra) /* PDC20246 */ + request_region(dma_base+16, extra, name); + dma_base += hwif->channel ? 8 : 0; + if (inb(dma_base+2) & 0x80) { + printk("%s: simplex device: DMA disabled\n", name); + dma_base = 0; } } + return dma_base; } diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index 2856f330f..5572a07ba 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.5 - ALPHA Feb 21, 1997 + * linux/drivers/block/ide-floppy.c Version 0.8 Feb 21, 1997 * * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il> */ @@ -21,8 +21,15 @@ * Use the minimum of the LBA and CHS capacities. * Avoid hwgroup->rq == NULL on the last irq. * Fix potential null dereferencing with DEBUG_LOG. + * Ver 0.8 Dec 7 97 Increase irq timeout from 10 to 50 seconds. + * Add media write-protect detection. + * Issue START command only if TEST UNIT READY fails. + * Add work-around for IOMEGA ZIP revision 21.D. + * Remove idefloppy_get_capabilities(). */ +#define IDEFLOPPY_VERSION "0.8" + #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -31,12 +38,9 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/major.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/malloc.h> @@ -60,6 +64,11 @@ #define IDEFLOPPY_DEBUG_BUGS 1 /* + * Some drives require a longer irq timeout. + */ +#define IDEFLOPPY_WAIT_CMD (5 * WAIT_CMD) + +/* * After each failed packet command we issue a request sense command * and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times. */ @@ -191,6 +200,7 @@ typedef struct { int blocks, block_size, bs_factor; /* Current format */ idefloppy_capacity_descriptor_t capacity; /* Last format capacity */ idefloppy_flexible_disk_page_t flexible_disk_page; /* Copy of the flexible disk page */ + int wp; /* Write protect */ unsigned int flags; /* Status/Action flags */ } idefloppy_floppy_t; @@ -683,13 +693,12 @@ static void idefloppy_pc_intr (ide_drive_t *drive) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { - if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) { + if (HWIF(drive)->dmaproc(ide_dma_end, drive)) { set_bit (PC_DMA_ERROR, &pc->flags); } else { pc->actually_transferred=pc->request_transfer; idefloppy_update_buffers (drive, pc); } - (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */ #if IDEFLOPPY_DEBUG_LOG printk (KERN_INFO "ide-floppy: DMA finished\n"); #endif /* IDEFLOPPY_DEBUG_LOG */ @@ -728,8 +737,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n"); - printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n"); - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); ide_do_reset (drive); return; } @@ -755,7 +763,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) if (temp > pc->buffer_size) { printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); - ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD); + ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); return; } #if IDEFLOPPY_DEBUG_LOG @@ -777,7 +785,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD); /* And set the interrupt handler again */ + ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); /* And set the interrupt handler again */ } static void idefloppy_transfer_pc (ide_drive_t *drive) @@ -795,7 +803,7 @@ static void idefloppy_transfer_pc (ide_drive_t *drive) ide_do_reset (drive); return; } - ide_set_handler (drive, &idefloppy_pc_intr, WAIT_CMD); /* Set the interrupt routine */ + ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ } @@ -843,8 +851,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { - printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n"); - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); } if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); @@ -864,7 +871,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { - ide_set_handler (drive, &idefloppy_transfer_pc, WAIT_CMD); + ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); @@ -934,6 +941,12 @@ static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start) pc->c[4] = start; } +static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc) +{ + idefloppy_init_pc(pc); + pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD; +} + static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector) { int block = sector / floppy->bs_factor; @@ -1041,6 +1054,7 @@ static int idefloppy_get_flexible_disk_page (ide_drive_t *drive) return 1; } header = (idefloppy_mode_parameter_header_t *) pc.buffer; + floppy->wp = header->wp; page = (idefloppy_flexible_disk_page_t *) (header + 1); page->transfer_rate = ntohs (page->transfer_rate); @@ -1144,13 +1158,21 @@ static int idefloppy_open (struct inode *inode, struct file *filp, ide_drive_t * MOD_INC_USE_COUNT; if (drive->usage == 1) { - idefloppy_create_start_stop_cmd (&pc, 1); - (void) idefloppy_queue_pc_tail (drive, &pc); + idefloppy_create_test_unit_ready_cmd(&pc); + if (idefloppy_queue_pc_tail(drive, &pc)) { + idefloppy_create_start_stop_cmd (&pc, 1); + (void) idefloppy_queue_pc_tail (drive, &pc); + } if (idefloppy_get_capacity (drive)) { drive->usage--; MOD_DEC_USE_COUNT; return -EIO; } + if (floppy->wp && (filp->f_mode & 2)) { + drive->usage--; + MOD_DEC_USE_COUNT; + return -EROFS; + } set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags); idefloppy_create_prevent_cmd (&pc, 1); (void) idefloppy_queue_pc_tail (drive, &pc); @@ -1243,9 +1265,9 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id) default: sprintf (buffer, "Reserved");break; } printk (KERN_INFO "Command Packet Size: %s\n", buffer); - printk (KERN_INFO "Model: %s\n",id->model); - printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev); - printk (KERN_INFO "Serial Number: %s\n",id->serial_no); + printk (KERN_INFO "Model: %.40s\n",id->model); + printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev); + printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no); printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512); printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); @@ -1306,51 +1328,13 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id) } /* - * idefloppy_get_capabilities asks the floppy about its various - * parameters. - */ -static void idefloppy_get_capabilities (ide_drive_t *drive) -{ - idefloppy_pc_t pc; - idefloppy_mode_parameter_header_t *header; - idefloppy_capabilities_page_t *capabilities; - - idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE, MODE_SENSE_CURRENT); - if (idefloppy_queue_pc_tail (drive,&pc)) { - printk (KERN_ERR "ide-floppy: Can't get drive capabilities\n"); - return; - } - header = (idefloppy_mode_parameter_header_t *) pc.buffer; - capabilities = (idefloppy_capabilities_page_t *) (header + 1); - - if (!capabilities->sflp) - printk (KERN_INFO "%s: Warning - system floppy device bit is not set\n", drive->name); - -#if IDEFLOPPY_DEBUG_INFO - printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n"); - printk (KERN_INFO "Mode Parameter Header:\n"); - printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length); - printk (KERN_INFO "Medium Type - %d\n",header->medium_type); - printk (KERN_INFO "WP - %d\n",header->wp); - - printk (KERN_INFO "Capabilities Page:\n"); - printk (KERN_INFO "Page code - %d\n",capabilities->page_code); - printk (KERN_INFO "Page length - %d\n",capabilities->page_length); - printk (KERN_INFO "PS - %d\n",capabilities->ps); - printk (KERN_INFO "System Floppy Type device - %s\n",capabilities->sflp ? "Yes":"No"); - printk (KERN_INFO "Supports Reporting progress of Format - %s\n",capabilities->srfp ? "Yes":"No"); - printk (KERN_INFO "Non CD Optical device - %s\n",capabilities->ncd ? "Yes":"No"); - printk (KERN_INFO "Multiple LUN support - %s\n",capabilities->sml ? "Yes":"No"); - printk (KERN_INFO "Total LUN supported - %s\n",capabilities->tlun ? "Yes":"No"); -#endif /* IDEFLOPPY_DEBUG_INFO */ -} - -/* * Driver initialization. */ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) { struct idefloppy_id_gcw gcw; + int major = HWIF(drive)->major, i; + int minor = drive->select.b.unit << PARTN_BITS; *((unsigned short *) &gcw) = drive->id->config; drive->driver_data = floppy; @@ -1360,8 +1344,12 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) floppy->pc = floppy->pc_stack; if (gcw.drq_type == 1) set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags); + if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 && + strcmp(drive->id->fw_rev, "21.D") == 0) { + for (i = 0; i < 1 << PARTN_BITS; i++) + max_sectors[major][minor + i] = 64; + } - idefloppy_get_capabilities (drive); (void) idefloppy_get_capacity (drive); } @@ -1387,6 +1375,8 @@ static ide_module_t idefloppy_module = { * IDE subdriver functions, registered with ide.c */ static ide_driver_t idefloppy_driver = { + "ide-floppy", /* name */ + IDEFLOPPY_VERSION, /* version */ ide_floppy, /* media */ 0, /* busy */ 1, /* supports_dma */ @@ -1400,7 +1390,8 @@ static ide_driver_t idefloppy_driver = { idefloppy_media_change, /* media_change */ NULL, /* pre_reset */ idefloppy_capacity, /* capacity */ - NULL /* special */ + NULL, /* special */ + NULL /* proc */ }; /* diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c new file mode 100644 index 000000000..adcf99525 --- /dev/null +++ b/drivers/block/ide-pci.c @@ -0,0 +1,382 @@ +/* + * linux/drivers/block/ide-pci.c Version 1.00 December 8, 1997 + * + * Copyright (c) 1995-1998 Mark Lord + * May be copied or modified under the terms of the GNU General Public License + */ + +/* + * This modules provides support for automatic detection and + * configuration of all PCI IDE interfaces present in a system. + */ + +#include <linux/config.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/bios32.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include "ide.h" + +#define DEVID_PIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1}) +#define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) +#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) +#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) +#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) +#define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) +#define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) +#define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640}) +#define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646}) +#define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513}) +#define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621}) +#define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558}) +#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, 0xd568}) /* from datasheets */ +#define DEVID_TRM290 ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290}) +#define DEVID_NS87410 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410}) +#define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415}) +#define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565}) + +#define IDE_IGNORE ((void *)-1) + +#ifdef CONFIG_BLK_DEV_TRM290 +extern void ide_init_trm290(ide_hwif_t *); +#define INIT_TRM290 &ide_init_trm290 +#else +#define INIT_TRM290 IDE_IGNORE +#endif + +#ifdef CONFIG_BLK_DEV_OPTI621 +extern void ide_init_opti621(ide_hwif_t *); +#define INIT_OPTI621 &ide_init_opti621 +#else +#define INIT_OPTI621 NULL +#endif + +#ifdef CONFIG_BLK_DEV_NS87415 +extern void ide_init_ns87415(ide_hwif_t *); +#define INIT_NS87415 &ide_init_ns87415 +#else +#define INIT_NS87415 IDE_IGNORE +#endif + +#ifdef CONFIG_BLK_DEV_RZ1000 +extern void ide_init_rz1000(ide_hwif_t *); +#define INIT_RZ1000 &ide_init_rz1000 +#else +#define INIT_RZ1000 IDE_IGNORE +#endif + +typedef struct ide_pci_enablebit_s { + byte reg; /* byte pci reg holding the enable-bit */ + byte mask; /* mask to isolate the enable-bit */ + byte val; /* value of masked reg when "enabled" */ +} ide_pci_enablebit_t; + +typedef struct ide_pci_device_s { + ide_pci_devid_t devid; + const char *name; + void (*init_hwif)(ide_hwif_t *hwif); + ide_pci_enablebit_t enablebits[2]; +} ide_pci_device_t; + +static ide_pci_device_t ide_pci_chipsets[] __initdata = { + {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, + {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, + {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, + {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} }, + {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} }, + {DEVID_RZ1000, "RZ1000", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_RZ1001, "RZ1001", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_CMD640, "CMD640", IDE_IGNORE, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} }, + {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} }, + {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} }, + {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_OPTI621, "OPTI621", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} }, + {DEVID_OPTI621X,"OPTI621X", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} }, + {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }}; + +/* + * Search for an (apparently) unused block of I/O space + * of "size" bytes in length. Ideally we ought to do a pass + * through pcicfg space to eliminate ports already allocated + * by the BIOS, to avoid conflicts later in the init cycle, + * but we don't. FIXME + */ +unsigned int ide_find_free_region (unsigned short size) /* __init */ +{ + static unsigned short base = 0x5800; /* it works for me */ + unsigned short i; + + for (; base > 0; base -= 0x200) { + if (!check_region(base,size)) { + for (i = 0; i < size; i++) { + if (inb(base+i) != 0xff) + goto next; + } + return base; /* success */ + } + next: + } + return 0; /* failure */ +} + +/* + * Match a PCI IDE port against an entry in ide_hwifs[], + * based on io_base port if possible. + */ +__initfunc(static ide_hwif_t *ide_match_hwif (unsigned int io_base, const char *name)) +{ + int h; + ide_hwif_t *hwif; + + /* + * Look for a hwif with matching io_base specified using + * parameters to ide_setup(). + */ + for (h = 0; h < MAX_HWIFS; ++h) { + hwif = &ide_hwifs[h]; + if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { + if (hwif->chipset == ide_generic) + return hwif; /* a perfect match */ + } + } + /* + * Look for a hwif with matching io_base default value. + * If chipset is "ide_unknown", then claim that hwif slot. + * Otherwise, some other chipset has already claimed it.. :( + */ + for (h = 0; h < MAX_HWIFS; ++h) { + hwif = &ide_hwifs[h]; + if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { + if (hwif->chipset == ide_unknown) + return hwif; /* match */ + printk("%s: port 0x%04x already claimed by %s\n", name, io_base, hwif->name); + return NULL; /* already claimed */ + } + } + /* + * Okay, there is no hwif matching our io_base, + * so we'll just claim an unassigned slot. + * Give preference to claiming other slots before claiming ide0/ide1, + * just in case there's another interface yet-to-be-scanned + * which uses ports 1f0/170 (the ide0/ide1 defaults). + */ + for (h = 0; h < MAX_HWIFS; ++h) { + int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */ + hwif = &ide_hwifs[hwifs[h]]; + if (hwif->chipset == ide_unknown) + return hwif; /* pick an unused entry */ + } + printk("%s: too many IDE interfaces, no room in table\n", name); + return NULL; +} + +__initfunc(static int ide_setup_pci_baseregs (byte bus, byte fn, const char *name)) +{ + unsigned int base, readback; + byte reg, progif = 0; + + /* + * Place both IDE interfaces into PCI "native" mode: + */ + if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) { + if ((progif & 0xa) != 0xa) { + printk("%s: device not capable of full native PCI mode\n", name); + return 1; + } + printk("%s: placing both ports into native PCI mode\n", name); + (void) pcibios_write_config_byte(bus, fn, 0x09, progif|5); + if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) { + printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif); + return 1; + } + } + /* + * Setup base registers for IDE command/control spaces for each interface: + */ + if (!(base = ide_find_free_region(32))) + return 1; + for (reg = 0x10; reg <= 0x1c; reg += 4, base += 8) { + (void) pcibios_write_config_dword(bus, fn, reg, base|1); + if (pcibios_read_config_dword(bus, fn, reg, &readback) || (readback &= ~1) != base) { + printk("%s: readback failed for basereg 0x%02x: wrote 0x%04x, read 0x%x04\n", name, reg, base, readback); + return 1; + } + } + return 0; +} + +/* + * ide_setup_pci_device() looks at the primary/secondary interfaces + * on a PCI IDE device and, if they are enabled, prepares the IDE driver + * for use with them. This generic code works for most PCI chipsets. + * + * One thing that is not standardized is the location of the + * primary/secondary interface "enable/disable" bits. For chipsets that + * we "know" about, this information is in the ide_pci_device_t struct; + * for all other chipsets, we just assume both interfaces are enabled. + */ +__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int ccode, ide_pci_device_t *d)) +{ + unsigned int port, at_least_one_hwif_enabled = 0, no_autodma = 0; + unsigned short pcicmd = 0; + byte tmp = 0, progif = 0, pciirq = 0; + ide_hwif_t *hwif, *mate = NULL; + + if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd) + || pcibios_read_config_byte(bus, fn, 0x09, &progif) + || pcibios_read_config_byte(bus, fn, 0x3c, &pciirq)) + { + printk("%s: error accessing PCI regs\n", d->name); + return; + } + if (!(pcicmd & 1)) { /* is device disabled? */ + /* + * PnP BIOS was *supposed* to have set this device up for us, + * but we can do it ourselves, so long as the BIOS has assigned an IRQ + * (or possibly the device is using a "legacy header" for IRQs). + * Maybe the user deliberately *disabled* the device, + * but we'll eventually ignore it again if no drives respond. + */ + if (ide_setup_pci_baseregs(bus, fn, d->name) + || pcibios_write_config_word(bus, fn, 0x04, pcicmd|1) + || pcibios_read_config_word(bus, fn, 0x04, &pcicmd) + || !(pcicmd & 1)) + { + printk("%s: device disabled (BIOS)\n", d->name); + return; + } + no_autodma = 1; /* default DMA off if we had to configure it here */ + printk("%s: device enabled (Linux)\n", d->name); + } + if (!pciirq || pciirq >= NR_IRQS) { /* is pciirq invalid? */ + if (pciirq || (progif & 0x5)) /* don't complain if using "legacy" mode */ + printk("%s: BIOS returned %d for IRQ (ignored)\n", d->name, pciirq); + pciirq = 0; /* probe for it instead */ + } + /* + * Set up the IDE ports + */ + for (port = 0; port <= 1; ++port) { + unsigned int base = 0, ctl = 0; + ide_pci_enablebit_t *e = &(d->enablebits[port]); + if (e->reg && (pcibios_read_config_byte(bus, fn, e->reg, &tmp) || (tmp & e->mask) != e->val)) + continue; /* port not enabled */ + if (pcibios_read_config_dword(bus, fn, 0x14+(port*8), &ctl) || (ctl &= ~3) == 0) + ctl = port ? 0x374 : 0x3f4; /* use default value */ + if (pcibios_read_config_dword(bus, fn, 0x10+(port*8), &base) || (base &= ~7) == 0) + base = port ? 0x170 : 0x1f0; /* use default value */ + if ((hwif = ide_match_hwif(base, d->name)) == NULL) + continue; /* no room in ide_hwifs[] */ + if (hwif->io_ports[IDE_DATA_OFFSET] != base) { + ide_init_hwif_ports(hwif->io_ports, base, NULL); + hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2; + } + hwif->chipset = ide_pci; + hwif->pci_bus = bus; + hwif->pci_fn = fn; + hwif->pci_devid = d->devid; + hwif->channel = port; + hwif->irq = pciirq; + if (mate) { + hwif->mate = mate; + mate->mate = hwif; + } + if (no_autodma) + hwif->no_autodma = 1; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((ccode >> 16) == PCI_CLASS_STORAGE_IDE && (ccode & 0x8000))) { + unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0; + unsigned int dma_base = ide_get_or_set_dma_base(hwif, extra, d->name); + if (dma_base && !(pcicmd & 4)) { + /* + * Set up BM-DMA capability (PnP BIOS should have done this) + */ + hwif->no_autodma = 1; /* default DMA off if we had to configure it here */ + (void) pcibios_write_config_word(bus, fn, 0x04, (pcicmd|4)); + if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd) || !(pcicmd & 4)) { + printk("%s: %s error updating PCICMD\n", hwif->name, d->name); + dma_base = 0; + } + } + if (dma_base) + ide_setup_dma(hwif, dma_base, 8); + else + printk("%s: %s Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, ccode=0x%04x, dma_base=0x%04x\n", + hwif->name, d->name, pcicmd, ccode, dma_base); + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ + d->init_hwif(hwif); + mate = hwif; + at_least_one_hwif_enabled = 1; + } + if (!at_least_one_hwif_enabled) + printk("%s: neither IDE port enabled (BIOS)\n", d->name); +} + +/* + * ide_scan_pci_device() examines all functions of a PCI device, + * looking for IDE interfaces and/or devices in ide_pci_chipsets[]. + * We cannot use pcibios_find_class() cuz it doesn't work in all systems. + */ +static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn) +{ + unsigned int ccode; + ide_pci_devid_t devid; + ide_pci_device_t *d; + byte hedt; + + if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt)) + hedt = 0; + do { + if (pcibios_read_config_word(bus, fn, 0x00, &devid.vid) + || devid.vid == 0xffff + || pcibios_read_config_word(bus, fn, 0x02, &devid.did) + || IDE_PCI_DEVID_EQ(devid, IDE_PCI_DEVID_NULL) + || pcibios_read_config_dword(bus, fn, 0x08, &ccode)) + return; + for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); + if (d->init_hwif == IDE_IGNORE) + printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name); + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(fn & 1)) + continue; /* OPTI Viper-M uses same devid for functions 0 and 1 */ + else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (ccode >> 16) == PCI_CLASS_STORAGE_IDE) { + if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) + printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n", + d->name, bus, fn, devid.vid, devid.did); + else + printk("%s: PCI bus %d function %d\n", d->name, bus, fn); + ide_setup_pci_device(bus, fn, ccode, d); + } + } while (hedt == 0x80 && (++fn & 7)); +} + +/* + * ide_scan_pcibus() gets invoked at boot time from ide.c + * + * Loops over all PCI devices on all PCI buses, invoking ide_scan_pci_device(). + * We cannot use pcibios_find_class() cuz it doesn't work in all systems. + */ +void ide_scan_pcibus (void) /* __init */ +{ + unsigned int bus, dev; + + if (!pcibios_present()) + return; + for (bus = 0; bus <= 255; ++bus) { + for (dev = 0; dev < 256; dev += 8) { + ide_scan_pci_device(bus, dev); + } + } +} + diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 9ae187b7e..8e9336037 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-probe.c Version 1.02 Jul 29, 1997 + * linux/drivers/block/ide-probe.c Version 1.03 Dec 5, 1997 * - * Copyright (C) 1994-1996 Linus Torvalds & authors (see below) + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ /* @@ -10,36 +10,11 @@ * * This is the IDE probe module, as evolved from hd.c and ide.c. * - * From hd.c: - * | - * | It traverses the request-list, using interrupts to jump between functions. - * | As nearly all functions can be called within interrupts, we may not sleep. - * | Special care is recommended. Have Fun! - * | - * | modified by Drew Eckhardt to check nr of hd's from the CMOS. - * | - * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * | in the early extended-partition checks and added DM partitions. - * | - * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI). - * | - * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", - * | and general streamlining by Mark Lord (mlord@pobox.com). - * - * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: - * - * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) - * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2") - * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) - * - * This was a rewrite of just about everything from hd.c, though some original - * code is still sprinkled about. Think of it as a major evolution, with - * inspiration from lots of linux users, esp. hamish@zot.apana.org.au - * * Version 1.00 move drive probing code from ide.c to ide-probe.c * Version 1.01 fix compilation problem for m68k * Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot - * by Andrea Arcangeli <arcangeli@mbox.queen.it> + * by Andrea Arcangeli <arcangeli@mbox.queen.it> + * Version 1.03 fix for (hwif->chipset == ide_4drives) */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -51,12 +26,9 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/major.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/malloc.h> #include <linux/delay.h> @@ -105,6 +77,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap); ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap); + id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */ drive->present = 1; printk("%s: %s, ", drive->name, id->model); @@ -115,7 +88,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) byte type = (id->config >> 8) & 0x1f; printk("ATAPI "); #ifdef CONFIG_BLK_DEV_PDC4030 - if (HWIF(drive)->is_pdc4030_2) { + if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) { printk(" -- not supported on 2nd Promise port\n"); drive->present = 0; return; @@ -160,8 +133,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) */ static void delay_50ms (void) { - unsigned long timer = jiffies + ((HZ + 19)/20) + 1; - while (timer > jiffies); + unsigned long timeout = jiffies + ((HZ + 19)/20) + 1; + while (0 < (signed long)(timeout - jiffies)); } /* @@ -180,6 +153,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) ide_ioreg_t hd_status; unsigned long timeout; unsigned long irqs = 0; + byte s, a; if (!HWIF(drive)->irq) { /* already got an IRQ? */ probe_irq_off(probe_irq_on()); /* clear dangling irqs */ @@ -188,9 +162,11 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) } delay_50ms(); /* take a deep breath */ - if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) { - printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name); - hd_status = IDE_STATUS_REG; /* ancient Seagate drives */ + a = IN_BYTE(IDE_ALTSTATUS_REG); + s = IN_BYTE(IDE_STATUS_REG); + if ((a ^ s) & ~INDEX_STAT) { + printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a); + hd_status = IDE_STATUS_REG; /* ancient Seagate drives, broken interfaces */ } else hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ @@ -208,7 +184,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { - if (jiffies > timeout) { + if (0 < (signed long)(jiffies - timeout)) { if (irqs) (void) probe_irq_off(irqs); return 1; /* drive timed-out */ @@ -285,9 +261,11 @@ static int do_probe (ide_drive_t *drive, byte cmd) SELECT_DRIVE(hwif,drive); delay_50ms(); if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { - OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */ - delay_50ms(); /* allow BUSY_STAT to assert & clear */ - return 3; /* no i/f present: avoid killing ethernet cards */ + if (drive->select.b.unit != 0) { + SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ + delay_50ms(); /* allow BUSY_STAT to assert & clear */ + } + return 3; /* no i/f present: mmm.. this should be a 4 -ml */ } if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) @@ -302,7 +280,7 @@ static int do_probe (ide_drive_t *drive, byte cmd) rc = 3; /* not present or maybe ATAPI */ } if (drive->select.b.unit != 0) { - OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */ + SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ delay_50ms(); (void) GET_STAT(); /* ensure drive irq is clear */ } @@ -367,7 +345,7 @@ static void probe_cmos_for_drives (ide_hwif_t *hwif) int unit; #ifdef CONFIG_BLK_DEV_PDC4030 - if (hwif->is_pdc4030_2) + if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) return; #endif /* CONFIG_BLK_DEV_PDC4030 */ outb_p(0x12,0x70); /* specify CMOS address 0x12 */ @@ -400,12 +378,12 @@ static void probe_hwif (ide_hwif_t *hwif) return; if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) probe_cmos_for_drives (hwif); + if ((hwif->chipset != ide_4drives || !hwif->mate->present) #if CONFIG_BLK_DEV_PDC4030 - if (!hwif->is_pdc4030_2 && - (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1))) { -#else - if (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)) { + && (hwif->chipset != ide_pdc4030 || hwif->channel == 0) #endif /* CONFIG_BLK_DEV_PDC4030 */ + && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1))) + { int msgout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; @@ -431,8 +409,10 @@ static void probe_hwif (ide_hwif_t *hwif) (void) probe_for_drive (drive); if (drive->present && !hwif->present) { hwif->present = 1; - ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name); - ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); + if (hwif->chipset != ide_4drives || !hwif->mate->present) { + ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name); + ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); + } } } if (hwif->reset) { @@ -446,7 +426,8 @@ static void probe_hwif (ide_hwif_t *hwif) do { delay_50ms(); stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); - } while ((stat & BUSY_STAT) && jiffies < timeout); + } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); + } restore_flags(flags); for (unit = 0; unit < MAX_DRIVES; ++unit) { @@ -521,13 +502,11 @@ static int init_irq (ide_hwif_t *hwif) save_match(hwif, h, &match); } if (hwif->serialized) { - ide_hwif_t *mate = &ide_hwifs[hwif->index^1]; - if (index == mate->index || h->irq == mate->irq) + if (hwif->mate && hwif->mate->irq == h->irq) save_match(hwif, h, &match); } if (h->serialized) { - ide_hwif_t *mate = &ide_hwifs[h->index^1]; - if (hwif->irq == mate->irq) + if (h->mate && hwif->irq == h->mate->irq) save_match(hwif, h, &match); } } @@ -603,7 +582,7 @@ static void init_gendisk (ide_hwif_t *hwif) { struct gendisk *gd, **gdp; unsigned int unit, units, minors; - int *bs; + int *bs, *max_sect; /* figure out maximum drive number on the interface */ for (units = MAX_DRIVES; units > 0; --units) { @@ -615,13 +594,17 @@ static void init_gendisk (ide_hwif_t *hwif) gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); bs = kmalloc (minors*sizeof(int), GFP_KERNEL); + max_sect = kmalloc (minors*sizeof(int), GFP_KERNEL); memset(gd->part, 0, minors * sizeof(struct hd_struct)); /* cdroms and msdos f/s are examples of non-1024 blocksizes */ blksize_size[hwif->major] = bs; - for (unit = 0; unit < minors; ++unit) + max_sectors[hwif->major] = max_sect; + for (unit = 0; unit < minors; ++unit) { *bs++ = BLOCK_SIZE; + *max_sect++ = 244; + } for (unit = 0; unit < units; ++unit) hwif->drives[unit].part = &gd->part[unit << PARTN_BITS]; @@ -640,9 +623,8 @@ static void init_gendisk (ide_hwif_t *hwif) hwif->gd = *gdp = gd; /* link onto tail of list */ } -static int hwif_init (int h) +static int hwif_init (ide_hwif_t *hwif) { - ide_hwif_t *hwif = &ide_hwifs[h]; void (*rfn)(void); if (!hwif->present) @@ -692,7 +674,6 @@ static int hwif_init (int h) return hwif->present; } -int ideprobe_init (void); static ide_module_t ideprobe_module = { IDE_PROBE_MODULE, ideprobe_init, @@ -713,9 +694,11 @@ int ideprobe_init (void) * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports */ for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) probe_hwif (&ide_hwifs[index]); + if (probe[index]) + probe_hwif(&ide_hwifs[index]); for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) hwif_init (index); + if (probe[index]) + hwif_init(&ide_hwifs[index]); ide_register_module(&ideprobe_module); MOD_DEC_USE_COUNT; return 0; diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c new file mode 100644 index 000000000..55ad22521 --- /dev/null +++ b/drivers/block/ide-proc.c @@ -0,0 +1,505 @@ +/* + * linux/drivers/block/proc_ide.c Version 1.01 December 12, 1997 + * + * Copyright (C) 1997-1998 Mark Lord + */ + +/* + * This is the /proc/ide/ filesystem implementation. + * + * The major reason this exists is to provide sufficient access + * to driver and config data, such that user-mode programs can + * be developed to handle chipset tuning for most PCI interfaces. + * This should provide better utilities, and less kernel bloat. + * + * The entire pci config space for a PCI interface chipset can be + * retrieved by just reading it. e.g. "cat /proc/ide3/pci" + * + * To modify registers, do something like: + * echo "40:88" >/proc/ide/ide3/pci + * That expression writes 0x88 to pci config register 0x40 + * on the chip which controls ide3. Multiple tuples can be issued, + * and the writes will be completed as an atomic set: + * echo "40:88 41:35 42:00 43:00" >/proc/ide/ide3/pci + * All numbers must be pairs of ascii hex digits. + * + * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY + * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the + * returned data as 256 16-bit words. The "hdparm" utility will + * be updated someday soon to use this mechanism. + * + * Feel free to develop and distribute fancy GUI configuration + * utilities for you favorite PCI chipsets. I'll be working on + * one for the Promise 20246 someday soon. -ml + * + */ + +#include <linux/config.h> +#include <asm/uaccess.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/bios32.h> +#include <linux/ctype.h> +#include "ide.h" + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/* + * Standard exit stuff: + */ +#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \ +{ \ + len -= off; \ + if (len < count) { \ + *eof = 1; \ + if (len <= 0) \ + return 0; \ + } else \ + len = count; \ + *start = page + off; \ + return len; \ +} + + +#ifdef CONFIG_PCI + +static int ide_getxdigit(char c) +{ + int digit; + if (isdigit(c)) + digit = c - '0'; + else if (isxdigit(c)) + digit = tolower(c) - 'a' + 10; + else + digit = -1; + return digit; +} + + +static int xx_xx_parse_error (const char *start, unsigned long maxlen) +{ + char errbuf[7]; + int i, len = MIN(6, maxlen); + for (i = 0; i < len; ++i) { + char c = start[i]; + if (!c || c == '\n') + c = '\0'; + else if (iscntrl(c)) + c = '?'; + errbuf[i] = c; + } + errbuf[i] = '\0'; + printk("proc_ide: error: expected 'xx:xx', but got '%s'\n", errbuf); + return -EINVAL; +} + +static int proc_ide_write_pci + (struct file *file, const char *buffer, unsigned long count, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *)data; + int for_real = 0; + unsigned long n, flags; + const char *start; + + if (!suser()) + return -EACCES; + /* + * Skip over leading whitespace + */ + while (count && isspace(*buffer)) { + --count; + ++buffer; + } + /* + * Do one full pass to verify all parameters, + * then do another to actually write the pci regs. + */ + save_flags(flags); + do { + const char *p = buffer; + n = count; + if (for_real) { + unsigned long timeout = jiffies + (3 * HZ); + cli(); /* ensure all PCI writes are done together */ + while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) { + sti(); + if (0 < (signed long)(timeout - jiffies)) { + printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name); + return -EBUSY; + } + cli(); + } + } + while (n) { + int d1, d2, rc; + byte reg, val; + start = p; +#if 0 + printk("loop(%d): n=%ld, input=%.5s\n", for_real, n, p); +#endif + if (n < 5) + goto parse_error; + if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++))) + goto parse_error; + reg = (d1 << 4) | d2; + if (*p++ != ':') + goto parse_error; + if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++))) + goto parse_error; + val = (d1 << 4) | d2; + if (n > 5 && !isspace(*p)) + goto parse_error; + n -= 5; + while (n && isspace(*p)) { + --n; + ++p; + } + if (for_real) { +#if 0 + printk("proc_ide_write_pci: reg=0x%02x, val=0x%02x\n", reg, val); +#endif + rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val); + if (rc) { + restore_flags(flags); + printk("proc_ide_write_pci: error writing bus %d fn %d reg 0x%02x value 0x%02x\n", + hwif->pci_bus, hwif->pci_fn, reg, val); + printk("proc_ide_write_pci: %s\n", pcibios_strerror(rc)); + return -EIO; + } + } + } + } while (!for_real++); + restore_flags(flags); + return count; +parse_error: + restore_flags(flags); + return xx_xx_parse_error(start, n); +} + +static int proc_ide_read_pci + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *)data; + char *out = page; + int len, reg = 0; + + out += sprintf(out, "Bus %d Function %d Vendor %04x Device %04x Channel %d\n", + hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel); + do { + byte val; + int rc = pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, reg, &val); + if (rc) { + printk("proc_ide_read_pci: error reading bus %d fn %d reg 0x%02x\n", + hwif->pci_bus, hwif->pci_fn, reg); + printk("proc_ide_read_pci: %s\n", pcibios_strerror(rc)); + return -EIO; + out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n'); + } else + out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n'); + } while (reg < 0x100); + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_imodel + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *) data; + int len; + const char *vids, *dids; + + vids = pci_strvendor(hwif->pci_devid.vid); + dids = pci_strdev(hwif->pci_devid.vid, hwif->pci_devid.did); + len = sprintf(page,"%s: %s\n", vids ? vids : "(none)", dids ? dids : "(none)"); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} +#endif /* CONFIG_PCI */ + +static int proc_ide_read_type + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *) data; + int len; + const char *name; + + switch (hwif->chipset) { + case ide_unknown: name = "(none)"; break; + case ide_generic: name = "generic"; break; + case ide_pci: name = "pci"; break; + case ide_cmd640: name = "cmd640"; break; + case ide_dtc2278: name = "dtc2278"; break; + case ide_ali14xx: name = "ali14xx"; break; + case ide_qd6580: name = "qd6580"; break; + case ide_umc8672: name = "umc8672"; break; + case ide_ht6560b: name = "ht6560b"; break; + case ide_pdc4030: name = "pdc4030"; break; + case ide_rz1000: name = "rz1000"; break; + case ide_trm290: name = "trm290"; break; + case ide_4drives: name = "4drives"; break; + default: name = "(unknown)"; break; + } + len = sprintf(page, "%s\n", name); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_mate + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *) data; + int len; + + len = sprintf(page, "%s\n", hwif->mate->name); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_channel + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *) data; + int len; + + page[0] = hwif->channel ? '1' : '0'; + page[1] = '\n'; + len = 2; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_get_identify (ide_drive_t *drive, byte *buf) +{ + struct request rq; + byte *end; + + ide_init_drive_cmd(&rq); + rq.buffer = buf; + *buf++ = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY; + *buf++ = 0; + *buf++ = 0; + *buf++ = 1; + end = buf + (SECTOR_WORDS * 4); + while (buf != end) + *buf++ = 0; /* pre-zero it, in case identify fails */ + (void) ide_do_drive_cmd(drive, &rq, ide_wait); + return 0; +} + +static int proc_ide_read_identify + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!proc_ide_get_identify(drive, page)) { + unsigned short *val = ((unsigned short *)page) + 2; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_settings + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + char *out = page; + int len; + + out += sprintf(out,"multcount %i\n", drive->mult_count); + out += sprintf(out,"io_32bit %i\n", drive->io_32bit); + out += sprintf(out,"unmaskirq %i\n", drive->unmask); + out += sprintf(out,"using_dma %i\n", drive->using_dma); + out += sprintf(out,"nowerr %i\n", drive->bad_wstat == BAD_R_STAT); + out += sprintf(out,"keepsettings %i\n", drive->keep_settings); + out += sprintf(out,"nice %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2); + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +int proc_ide_read_capacity + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + int len; + + len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive)); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +int proc_ide_read_geometry + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + char *out = page; + int len; + + out += sprintf(out,"physical %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect); + out += sprintf(out,"logical %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect); + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_dmodel + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + struct hd_driveid *id = drive->id; + int len; + + len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)"); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_driver + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + ide_driver_t *driver = (ide_driver_t *) drive->driver; + int len; + + if (!driver) + len = sprintf(page, "(none)\n"); + else + len = sprintf(page, "%s version %s\n", driver->name, driver->version); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_ide_read_media + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + const char *media; + int len; + + switch (drive->media) { + case ide_disk: media = "disk\n"; + break; + case ide_cdrom: media = "cdrom\n"; + break; + case ide_tape: media = "tape\n"; + break; + case ide_floppy:media = "floppy\n"; + break; + default: media = "UNKNOWN\n"; + break; + } + strcpy(page,media); + len = strlen(media); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + + +static ide_proc_entry_t generic_drive_entries[] = { + { "capacity", proc_ide_read_capacity, NULL }, + { "driver", proc_ide_read_driver, NULL }, + { "identify", proc_ide_read_identify, NULL }, + { "media", proc_ide_read_media, NULL }, + { "model", proc_ide_read_dmodel, NULL }, + { "settings", proc_ide_read_settings, NULL }, + { NULL, NULL, NULL } +}; + +void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p) +{ + struct proc_dir_entry *ent; + + if (!drive->proc || !p) + return; + while (p->name != NULL) { + ent = create_proc_entry(p->name, 0, drive->proc); + if (!ent) return; + ent->data = drive; + ent->read_proc = p->read_proc; + ent->write_proc = p->write_proc; + p++; + } +} + +void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p) +{ + if (!drive->proc || !p) + return; + while (p->name != NULL) { + remove_proc_entry(p->name, drive->proc); + p++; + } +} + +static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent) +{ + int d; + + for (d = 0; d < MAX_DRIVES; d++) { + ide_drive_t *drive = &hwif->drives[d]; + + if (!drive->present) + continue; + drive->proc = create_proc_entry(drive->name, S_IFDIR, parent); + if (drive->proc) + ide_add_proc_entries(drive, generic_drive_entries); + } +} + +static void create_proc_ide_interfaces (struct proc_dir_entry *parent) +{ + int h; + struct proc_dir_entry *hwif_ent, *ent; + + for (h = 0; h < MAX_HWIFS; h++) { + ide_hwif_t *hwif = &ide_hwifs[h]; + + if (!hwif->present) + continue; + hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent); + if (!hwif_ent) return; +#ifdef CONFIG_PCI + if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) { + ent = create_proc_entry("pci", 0, hwif_ent); + if (!ent) return; + ent->data = hwif; + ent->read_proc = proc_ide_read_pci; + ent->write_proc = proc_ide_write_pci;; + + ent = create_proc_entry("model", 0, hwif_ent); + if (!ent) return; + ent->data = hwif; + ent->read_proc = proc_ide_read_imodel; + } +#endif /* CONFIG_PCI */ + ent = create_proc_entry("channel", 0, hwif_ent); + if (!ent) return; + ent->data = hwif; + ent->read_proc = proc_ide_read_channel; + + if (hwif->mate && hwif->mate->present) { + ent = create_proc_entry("mate", 0, hwif_ent); + if (!ent) return; + ent->data = hwif; + ent->read_proc = proc_ide_read_mate; + } + + ent = create_proc_entry("type", 0, hwif_ent); + if (!ent) return; + ent->data = hwif; + ent->read_proc = proc_ide_read_type; + + create_proc_ide_drives(hwif, hwif_ent); + } +} + +void proc_ide_init(void) +{ + struct proc_dir_entry *ent; + ent = create_proc_entry("ide", S_IFDIR, 0); + if (!ent) return; + create_proc_ide_interfaces(ent); +} diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index e9d7f1433..a30fc9a58 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.11 - BETA Dec 2, 1996 + * linux/drivers/block/ide-tape.c Version 1.12 Dec 7, 1997 * * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il> * @@ -206,6 +206,11 @@ * Use ide_stall_queue() for DSC overlap. * Use the maximum speed rather than the current speed * to compute the request service time. + * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data + * corruption, which could occur if the total number + * of bytes written to the tape was not an integral + * number of tape blocks. + * Add support for INTERRUPT DRQ devices. * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -315,6 +320,8 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ +#define IDETAPE_VERSION "1.12" + #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -323,12 +330,9 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/major.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/malloc.h> @@ -692,6 +696,7 @@ typedef struct { #define IDETAPE_PIPELINE_ERROR 3 /* Error detected in a pipeline stage */ #define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */ #define IDETAPE_FILEMARK 5 /* Currently on a filemark */ +#define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */ /* * Supported ATAPI tape drives packet commands @@ -1152,11 +1157,6 @@ static void idetape_postpone_request (ide_drive_t *drive) */ static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq) { - unsigned int major = HWIF(drive)->major; - struct blk_dev_struct *bdev = &blk_dev[major]; - - bdev->current_request=HWGROUP (drive)->rq; /* Since we may have taken it out */ - ide_init_drive_cmd (rq); rq->buffer = (char *) pc; rq->cmd = IDETAPE_PC_RQ1; @@ -1542,16 +1542,12 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup) ide_drive_t *drive = hwgroup->drive; struct request *rq = hwgroup->rq; idetape_tape_t *tape = drive->driver_data; - unsigned int major = HWIF(drive)->major; - struct blk_dev_struct *bdev = &blk_dev[major]; int error; #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_end_request\n"); #endif /* IDETAPE_DEBUG_LOG */ - bdev->current_request=rq; /* Since we may have taken it out */ - switch (uptodate) { case 0: error = IDETAPE_ERROR_GENERAL; break; case 1: error = 0; break; @@ -1723,18 +1719,23 @@ static void idetape_pc_intr (ide_drive_t *drive) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { - if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) { - set_bit (PC_DMA_ERROR, &pc->flags); + if (HWIF(drive)->dmaproc(ide_dma_end, drive)) { /* - * We will currently correct the following in - * idetape_analyze_error. + * A DMA error is sometimes expected. For example, + * if the tape is crossing a filemark during a + * READ command, it will issue an irq and position + * itself before the filemark, so that only a partial + * data transfer will occur (which causes the DMA + * error). In that case, we will later ask the tape + * how much bytes of the original request were + * actually transferred (we can't receive that + * information from the DMA engine on most chipsets). */ - pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive); + set_bit (PC_DMA_ERROR, &pc->flags); } else { pc->actually_transferred=pc->request_transfer; idetape_update_buffers (pc); } - (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */ #if IDETAPE_DEBUG_LOG printk (KERN_INFO "ide-tape: DMA finished\n"); #endif /* IDETAPE_DEBUG_LOG */ @@ -1780,7 +1781,7 @@ static void idetape_pc_intr (ide_drive_t *drive) if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n"); printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); ide_do_reset (drive); return; } @@ -1873,11 +1874,31 @@ static void idetape_pc_intr (ide_drive_t *drive) * we will handle the next request. * */ + +static void idetape_transfer_pc(ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t *pc = tape->pc; + idetape_ireason_reg_t ireason; + + if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); + return; + } + ireason.all=IN_BYTE (IDE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { + printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); + ide_do_reset (drive); + return; + } + ide_set_handler(drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */ + atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ +} + static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) { idetape_tape_t *tape = drive->driver_data; idetape_bcount_reg_t bcount; - idetape_ireason_reg_t ireason; int dma_ok=0; #if IDETAPE_DEBUG_BUGS @@ -1918,7 +1939,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n"); - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); } if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); @@ -1929,35 +1950,19 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); OUT_BYTE (drive->select.all,IDE_SELECT_REG); - - ide_set_handler (drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */ - OUT_BYTE (WIN_PACKETCMD,IDE_COMMAND_REG); /* Issue the packet command */ - - if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { /* Wait for DRQ to be ready - Assuming Accelerated DRQ */ - /* - * We currently only support tape drives which report - * accelerated DRQ assertion. For this case, specs - * allow up to 50us. We really shouldn't get here. - * - * ??? Still needs to think what to do if we reach - * here anyway. - */ - printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); - return; - } - ireason.all=IN_BYTE (IDE_IREASON_REG); - if (!ireason.b.cod || ireason.b.io) { - printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); - ide_do_reset (drive); - return; - } - atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ #ifdef CONFIG_BLK_DEV_IDEDMA if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } #endif /* CONFIG_BLK_DEV_IDEDMA */ + if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { + ide_set_handler(drive, &idetape_transfer_pc, WAIT_CMD); + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + } else { + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + idetape_transfer_pc(drive); + } } static void idetape_media_access_finished (ide_drive_t *drive) @@ -2179,7 +2184,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; - struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major]; struct request *postponed_rq = tape->postponed_rq; idetape_status_reg_t status; @@ -2198,32 +2202,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned } /* - * This is an important point. We will try to remove our request - * from the block device request queue while we service the - * request. Note that the request must be returned to - * bdev->current_request before the next call to - * ide_end_drive_cmd or ide_do_drive_cmd to conform with the - * normal behavior of the IDE driver, which leaves the active - * request in bdev->current_request during I/O. - * - * This will eliminate fragmentation of disk/cdrom requests - * around a tape request, now that we are using ide_next to - * insert pending pipeline requests, since we have only one - * ide-tape.c data request in the device request queue, and - * thus once removed, ll_rw_blk.c will only see requests from - * the other device. - * - * The potential fragmentation inefficiency was pointed to me - * by Mark Lord. - * - * Uhuh.. the following "fix" is actually not entirely correct. - * Some day we should probably move to a per device request - * queue, rather than per interface. - */ - if (rq->next != NULL && rq->rq_dev != rq->next->rq_dev) - bdev->current_request=rq->next; - - /* * Retry a failed packet command */ if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { @@ -2612,8 +2590,8 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive) if (tape->merge_stage_size % tape->tape_block_size) { blocks++; i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; - memset (tape->merge_stage->bh->b_data + tape->merge_stage->bh->b_count, 0, i); - tape->merge_stage->bh->b_count += i; + memset (tape->bh->b_data + tape->bh->b_count, 0, i); + tape->bh->b_count += i; } (void) idetape_add_chrdev_write_request (drive, blocks); tape->merge_stage_size = 0; @@ -3378,9 +3356,9 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) case 1: printk (KERN_INFO "16 bytes\n");break; default: printk (KERN_INFO "Reserved\n");break; } - printk (KERN_INFO "Model: %s\n",id->model); - printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev); - printk (KERN_INFO "Serial Number: %s\n",id->serial_no); + printk (KERN_INFO "Model: %.40s\n",id->model); + printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev); + printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no); printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512); printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); @@ -3532,6 +3510,7 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) ide_hwif_t *hwif = HWIF(drive); unsigned long t1, tmid, tn, t; u16 speed; + struct idetape_id_gcw gcw; drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ @@ -3543,6 +3522,9 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->chrdev_direction = idetape_direction_none; tape->pc = tape->pc_stack; tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + *((unsigned short *) &gcw) = drive->id->config; + if (gcw.drq_type == 1) + set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); idetape_get_mode_sense_results (drive); @@ -3635,6 +3617,8 @@ static ide_module_t idetape_module = { * IDE subdriver functions, registered with ide.c */ static ide_driver_t idetape_driver = { + "ide-tape", /* name */ + IDETAPE_VERSION, /* version */ ide_tape, /* media */ 1, /* busy */ 1, /* supports_dma */ @@ -3648,7 +3632,8 @@ static ide_driver_t idetape_driver = { NULL, /* media_change */ idetape_pre_reset, /* pre_reset */ NULL, /* capacity */ - NULL /* special */ + NULL, /* special */ + NULL /* proc */ }; /* diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 50af139cd..3b9a17283 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.05 November 30, 1997 + * linux/drivers/block/ide.c Version 6.11 December 5, 1997 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -95,6 +95,9 @@ * added support for BIOS-enabled UltraDMA * rename all "promise" things to "pdc4030" * fix EZ-DRIVE handling on small disks + * Version 6.11 fix probe error in ide_scan_devices() + * fix ancient "jiffies" polling bugs + * mask all hwgroup interrupts on each irq entry * * Some additional driver compile-time options are in ide.h * @@ -111,18 +114,14 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/mm.h> -#include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/major.h> -#include <linux/blkdev.h> #include <linux/errno.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/malloc.h> #include <linux/bios32.h> #include <linux/pci.h> #include <linux/delay.h> -#include <linux/init.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -312,11 +311,12 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) if (io_32bit) { #if SUPPORT_VLB_SYNC if (io_32bit & 2) { + unsigned long flags; + save_flags(flags); cli(); do_vlb_sync(IDE_NSECTOR_REG); insl(IDE_DATA_REG, buffer, wcount); - if (drive->unmask) - sti(); + restore_flags(flags); } else #endif /* SUPPORT_VLB_SYNC */ insl(IDE_DATA_REG, buffer, wcount); @@ -344,11 +344,12 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) if (io_32bit) { #if SUPPORT_VLB_SYNC if (io_32bit & 2) { + unsigned long flags; + save_flags(flags); cli(); do_vlb_sync(IDE_NSECTOR_REG); outsl(IDE_DATA_REG, buffer, wcount); - if (drive->unmask) - sti(); + restore_flags(flags); } else #endif /* SUPPORT_VLB_SYNC */ outsl(IDE_DATA_REG, buffer, wcount); @@ -469,13 +470,13 @@ static void atapi_reset_pollfunc (ide_drive_t *drive) ide_hwgroup_t *hwgroup = HWGROUP(drive); byte stat; - OUT_BYTE (drive->select.all, IDE_SELECT_REG); + SELECT_DRIVE(HWIF(drive),drive); udelay (10); if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) { printk("%s: ATAPI reset complete\n", drive->name); } else { - if (jiffies < hwgroup->poll_timeout) { + if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); return; /* continue polling */ } @@ -500,7 +501,7 @@ static void reset_pollfunc (ide_drive_t *drive) byte tmp; if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { - if (jiffies < hwgroup->poll_timeout) { + if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { ide_set_handler (drive, &reset_pollfunc, HZ/20); return; /* continue polling */ } @@ -542,7 +543,7 @@ static void pre_reset (ide_drive_t *drive) drive->unmask = 0; drive->io_32bit = 0; if (drive->using_dma) - HWIF(drive)->dmaproc(ide_dma_off, drive); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); } if (drive->driver != NULL) DRIVER(drive)->pre_reset(drive); @@ -576,7 +577,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { pre_reset(drive); - OUT_BYTE (drive->select.all, IDE_SELECT_REG); + SELECT_DRIVE(hwif,drive); udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; @@ -808,7 +809,7 @@ static void drive_cmd_intr (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; byte *args = (byte *) rq->buffer; - byte stat = GET_STAT(); + byte test, stat = GET_STAT(); ide_sti(); if ((stat & DRQ_STAT) && args && args[3]) { @@ -818,7 +819,10 @@ static void drive_cmd_intr (ide_drive_t *drive) drive->io_32bit = io_32bit; stat = GET_STAT(); } - if (OK_STAT(stat,READY_STAT,BAD_STAT)) + test = stat; + if (drive->media == ide_cdrom) + test = stat &~BUSY_STAT; + if (OK_STAT(test,READY_STAT,BAD_STAT)) ide_end_drive_cmd (drive, stat, GET_ERR()); else ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ @@ -870,7 +874,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou ide_sti(); timeout += jiffies; while ((stat = GET_STAT()) & BUSY_STAT) { - if (jiffies > timeout) { + if (0 < (signed long)(jiffies - timeout)) { restore_flags(flags); ide_error(drive, "status timeout", stat); return 1; @@ -1007,7 +1011,7 @@ repeat: do { if (!drive->queue) continue; - if (drive->sleep && drive->sleep > jiffies) + if (drive->sleep && 0 < (signed long)(drive->sleep - jiffies)) continue; if (!best) { best = drive; @@ -1019,7 +1023,7 @@ repeat: best = drive; } while ((drive = drive->next) != hwgroup->drive); if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) { - long t = (signed) (WAKEUP(best) - jiffies); + long t = (signed) (WAKEUP(best) - jiffies); /* BUGGY? */ if (t >= WAIT_MIN_SLEEP) { /* * We *may* have some time to spare, but first let's see if @@ -1029,7 +1033,7 @@ repeat: do { if (drive->sleep) /* this drive tried to be nice to us */ continue; - if (WAKEUP(drive) > jiffies - best->service_time && WAKEUP(drive) < jiffies + t) { + if (WAKEUP(drive) > (jiffies - best->service_time) && WAKEUP(drive) < (jiffies + t)) { /* BUGGY? */ ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP)); goto repeat; } @@ -1057,7 +1061,7 @@ static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup) sleep = drive->sleep; } while ((drive = drive->next) != hwgroup->drive); if (sleep) { - if (sleep < jiffies + WAIT_MIN_SLEEP) + if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) sleep = jiffies + WAIT_MIN_SLEEP; hwgroup->timer.expires = sleep; add_timer(&hwgroup->timer); @@ -1189,7 +1193,7 @@ void ide_timer_expiry (unsigned long data) handler(drive); else { /* abort the operation */ if (hwgroup->hwif->dmaproc) - (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive); + (void) hwgroup->hwif->dmaproc (ide_dma_end, drive); ide_error(drive, "irq timeout", GET_STAT()); } cli(); @@ -1229,7 +1233,6 @@ void ide_timer_expiry (unsigned long data) static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) { byte stat; - unsigned int unit; ide_hwif_t *hwif = hwgroup->hwif; /* @@ -1237,27 +1240,18 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) */ do { if (hwif->irq == irq) { - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (!drive->present) - continue; - SELECT_DRIVE(hwif,drive); - udelay(100); /* Ugly, but wait_stat() may not be safe here */ - if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) { - /* Try to not flood the console with msgs */ - static unsigned long last_msgtime = 0; - if ((last_msgtime + (HZ/2)) < jiffies) { - last_msgtime = jiffies; - (void) ide_dump_status(drive, "unexpected_intr", stat); - } + stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { + /* Try to not flood the console with msgs */ + static unsigned long last_msgtime = 0; + if (0 < (signed long)(jiffies - (last_msgtime + HZ))) { + last_msgtime = jiffies; + printk("%s%s: unexpected interrupt, status=0x%02x\n", + hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat); } - if ((stat & DRQ_STAT)) - try_to_flush_leftover_data(drive); } } } while ((hwif = hwif->next) != hwgroup->hwif); - SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */ - udelay(100); /* Ugly, but wait_stat() may not be safe here */ } /* @@ -1266,14 +1260,28 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { ide_hwgroup_t *hwgroup = dev_id; + ide_hwif_t *hwif = hwgroup->hwif; ide_handler_t *handler; - if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_STATUS_OFFSET], - hwgroup->hwif->io_ports[IDE_IRQ_OFFSET])) + if (!ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET])) return; - - if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) { + do { + if (hwif->irq != irq) disable_irq(hwif->irq); + } while ((hwif = hwif->next) != hwgroup->hwif); + if (irq == hwif->irq && (handler = hwgroup->handler) != NULL) { ide_drive_t *drive = hwgroup->drive; +#if 1 /* temporary, remove later -- FIXME */ + { + struct request *rq = hwgroup->rq; + if (rq != NULL + &&( MAJOR(rq->rq_dev) != HWIF(drive)->major + || (MINOR(rq->rq_dev) >> PARTN_BITS) != drive->select.b.unit)) + { + printk("ide_intr: got IRQ from wrong device: email mlord@pobox.com!!\n"); + return; + } + } +#endif /* temporary */ hwgroup->handler = NULL; del_timer(&(hwgroup->timer)); if (drive->unmask) @@ -1289,6 +1297,10 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) unexpected_intr(irq, hwgroup); } cli(); + hwif = hwgroup->hwif; + do { + if (hwif->irq != irq) enable_irq(hwif->irq); + } while ((hwif = hwif->next) != hwgroup->hwif); } /* @@ -1627,6 +1639,7 @@ void ide_unregister (unsigned int index) */ unregister_blkdev(hwif->major, hwif->name); kfree(blksize_size[hwif->major]); + kfree(max_sectors[hwif->major]); blk_dev[hwif->major].request_fn = NULL; blk_dev[hwif->major].data = NULL; blk_dev[hwif->major].queue = NULL; @@ -1686,13 +1699,15 @@ found: static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int err; + int err, major, minor; ide_drive_t *drive; unsigned long flags; struct request rq; + kdev_t dev; - if (!inode || !(inode->i_rdev)) + if (!inode || !(dev = inode->i_rdev)) return -EINVAL; + major = MAJOR(dev); minor = MINOR(dev); if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; ide_init_drive_cmd (&rq); @@ -1726,6 +1741,23 @@ static int ide_ioctl (struct inode *inode, struct file *file, case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); + case BLKFRASET: + if (!suser()) return -EACCES; + max_readahead[major][minor] = arg; + return 0; + + case BLKFRAGET: + return put_user(max_readahead[major][minor], (long *) arg); + + case BLKSECTSET: + if (!suser()) return -EACCES; + if (!arg || arg > 0xff) return -EINVAL; + max_sectors[major][minor] = arg; + return 0; + + case BLKSECTGET: + return put_user(max_sectors[major][minor], (long *) arg); + case BLKRRPART: /* Re-read partition tables */ if (!suser()) return -EACCES; return ide_revalidate_disk(inode->i_rdev); @@ -2074,6 +2106,9 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i * This is the default for most chipsets, * except the cmd640. * "idex=serialize" : do not overlap operations on idex and ide(x^1) + * "idex=four" : four drives on idex and ide(x^1) share same ports + * "idex=reset" : reset interface before first use + * "idex=nodma" : do not enable DMA by default on either drive * * The following are valid ONLY on ide0, * and the defaults for the base,ctl ports must not be altered. @@ -2175,8 +2210,8 @@ __initfunc(void ide_setup (char *s)) /* * Be VERY CAREFUL changing this: note hardcoded indexes below */ - const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "qd6580", - "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "four", "reset", NULL}; + const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "nodma", "four", + "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL}; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -2184,42 +2219,19 @@ __initfunc(void ide_setup (char *s)) /* * Cryptic check to ensure chipset not already set for hwif: */ - if (i > 0 || (i <= -5 && i != -13)) { + if (i > 0 || i <= -7) { /* is parameter a chipset name? */ if (hwif->chipset != ide_unknown) - goto bad_option; - if (i <= -5) { - if (ide_hwifs[1].chipset != ide_unknown) - goto bad_option; - /* - * Interface keywords work only for ide0: - */ - if (hw != 0) - goto bad_hwif; - printk("\n"); - } + goto bad_option; /* chipset already specified */ + if (i != -7 && hw != 0) + goto bad_hwif; /* chipset drivers are for "ide0=" only */ + if (ide_hwifs[hw^1].chipset != ide_unknown) + goto bad_option; /* chipset for 2nd port already specified */ + printk("\n"); } switch (i) { - case -13: /* "reset" */ - hwif->reset = 1; - goto done; -#ifdef CONFIG_BLK_DEV_4DRIVES - case -12: /* "four" drives on one set of ports */ - { - ide_hwif_t *mate = &ide_hwifs[hw^1]; - mate->mate = hwif; - hwif->mate = mate; - hwif->chipset = mate->chipset = ide_4drives; - hwif->serialized = mate->serialized = 1; - mate->drives[0].select.all ^= 0x20; - mate->drives[1].select.all ^= 0x20; - memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports)); - mate->irq = hwif->irq; - goto done; - } -#endif /* CONFIG_BLK_DEV_4DRIVES */ #ifdef CONFIG_BLK_DEV_PDC4030 - case -11: /* "dc4030" */ + case -14: /* "dc4030" */ { extern void setup_pdc4030(ide_hwif_t *); setup_pdc4030(hwif); @@ -2227,7 +2239,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_PDC4030 */ #ifdef CONFIG_BLK_DEV_ALI14XX - case -10: /* "ali14xx" */ + case -13: /* "ali14xx" */ { extern void init_ali14xx (void); init_ali14xx(); @@ -2235,7 +2247,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_ALI14XX */ #ifdef CONFIG_BLK_DEV_UMC8672 - case -9: /* "umc8672" */ + case -12: /* "umc8672" */ { extern void init_umc8672 (void); init_umc8672(); @@ -2243,7 +2255,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_UMC8672 */ #ifdef CONFIG_BLK_DEV_DTC2278 - case -8: /* "dtc2278" */ + case -11: /* "dtc2278" */ { extern void init_dtc2278 (void); init_dtc2278(); @@ -2251,7 +2263,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_DTC2278 */ #ifdef CONFIG_BLK_DEV_CMD640 - case -7: /* "cmd640_vlb" */ + case -10: /* "cmd640_vlb" */ { extern int cmd640_vlb; /* flag for cmd640.c */ cmd640_vlb = 1; @@ -2259,7 +2271,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_CMD640 */ #ifdef CONFIG_BLK_DEV_HT6560B - case -6: /* "ht6560b" */ + case -9: /* "ht6560b" */ { extern void init_ht6560b (void); init_ht6560b(); @@ -2267,13 +2279,31 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_HT6560B */ #if CONFIG_BLK_DEV_QD6580 - case -5: /* "qd6580" (has secondary i/f) */ + case -8: /* "qd6580" */ { extern void init_qd6580 (void); init_qd6580(); goto done; } #endif /* CONFIG_BLK_DEV_QD6580 */ +#ifdef CONFIG_BLK_DEV_4DRIVES + case -7: /* "four" drives on one set of ports */ + { + ide_hwif_t *mate = &ide_hwifs[hw^1]; + mate->drives[0].select.all ^= 0x20; + mate->drives[1].select.all ^= 0x20; + hwif->chipset = mate->chipset = ide_4drives; + mate->irq = hwif->irq; + memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports)); + goto do_serialize; + } +#endif /* CONFIG_BLK_DEV_4DRIVES */ + case -6: /* nodma */ + hwif->no_autodma = 1; + goto done; + case -5: /* "reset" */ + hwif->reset = 1; + goto done; case -4: /* "noautotune" */ hwif->drives[0].autotune = 2; hwif->drives[1].autotune = 2; @@ -2284,8 +2314,9 @@ __initfunc(void ide_setup (char *s)) goto done; case -2: /* "serialize" */ do_serialize: - ide_hwifs[hw].serialized = 1; /* serialize */ - ide_hwifs[hw^1].serialized = 1; /* with mate */ + hwif->mate = &ide_hwifs[hw^1]; + hwif->mate->mate = hwif; + hwif->serialized = hwif->mate->serialized = 1; goto done; case -1: /* "noprobe" */ @@ -2395,44 +2426,37 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) /* * probe_for_hwifs() finds/initializes "known" IDE interfaces - * - * This routine should ideally be using pcibios_find_class() to find all - * PCI IDE interfaces, but that function causes some systems to "go weird". */ __initfunc(static void probe_for_hwifs (void)) { #ifdef CONFIG_PCI - /* - * Find/initialize PCI IDE interfaces - */ if (pcibios_present()) { -#ifdef CONFIG_BLK_DEV_IDEDMA - { - extern void ide_scan_pcibus(void); - ide_scan_pcibus(); - } -#endif +#ifdef CONFIG_BLK_DEV_IDEPCI + ide_scan_pcibus(); +#else #ifdef CONFIG_BLK_DEV_RZ1000 { extern void ide_probe_for_rz100x(void); ide_probe_for_rz100x(); } -#endif +#endif /* CONFIG_BLK_DEV_RZ1000 */ +#endif /* CONFIG_BLK_DEV_IDEPCI */ } -#endif /* CONFIG_PCI */ +#endif /* CONFIG_PCI */ + #ifdef CONFIG_BLK_DEV_CMD640 { extern void ide_probe_for_cmd640x(void); ide_probe_for_cmd640x(); } -#endif +#endif /* CONFIG_BLK_DEV_CMD640 */ #ifdef CONFIG_BLK_DEV_PDC4030 { extern int init_pdc4030(void); (void) init_pdc4030(); } -#endif +#endif /* CONFIG_BLK_DEV_PDC4030 */ } __initfunc(void ide_init_builtin_drivers (void)) @@ -2460,6 +2484,10 @@ __initfunc(void ide_init_builtin_drivers (void)) #endif /* __mc68000__ */ #endif /* CONFIG_BLK_DEV_IDE */ +#ifdef CONFIG_PROC_FS + proc_ide_init(); +#endif + /* * Attempt to match drivers for the available drives */ @@ -2552,18 +2580,19 @@ static void setup_driver_defaults (ide_drive_t *drive) ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n) { unsigned int unit, index, i; - ide_drive_t *drive; for (index = 0; index < MAX_HWIFS; ++index) if (ide_hwifs[index].present) goto search; ide_init_module(IDE_PROBE_MODULE); search: for (index = 0, i = 0; index < MAX_HWIFS; ++index) { - for (unit = 0; unit < MAX_DRIVES; ++unit) { - drive = &ide_hwifs[index].drives[unit]; - if (drive->present && drive->media == media && - drive->driver == driver && ++i > n) - return drive; + ide_hwif_t *hwif = &ide_hwifs[index]; + if (hwif->present) { + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + if (drive->present && drive->media == media && drive->driver == driver && ++i > n) + return drive; + } } } return NULL; @@ -2590,6 +2619,7 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio drive->nice1 = 1; } drive->revalidate = 1; + ide_add_proc_entries(drive, driver->proc); return 0; } @@ -2603,6 +2633,7 @@ int ide_unregister_subdriver (ide_drive_t *drive) restore_flags(flags); return 1; } + ide_remove_proc_entries(drive, DRIVER(drive)->proc); drive->driver = NULL; restore_flags(flags); return 0; @@ -2694,6 +2725,9 @@ EXPORT_SYMBOL(ide_end_request); EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_stall_queue); +EXPORT_SYMBOL(ide_add_proc_entries); +EXPORT_SYMBOL(ide_remove_proc_entries); +EXPORT_SYMBOL(proc_ide_read_geometry); EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_unregister); diff --git a/drivers/block/ide.h b/drivers/block/ide.h index dd3549ac9..dfcb80fa5 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -7,10 +7,15 @@ */ #include <linux/config.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/hdreg.h> +#include <linux/blkdev.h> +#include <linux/proc_fs.h> #include <asm/ide.h> /* - * This is the multiple IDE interface driver, as evolved from hd.c. + * This is the multiple IDE interface driver, as evolved from hd.c. * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15). * There can be up to two drives per interface, as per the ATA-2 spec. * @@ -22,7 +27,7 @@ /****************************************************************************** * IDE driver configuration options (play with these as desired): - * + * * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary */ #undef REALLY_FAST_IO /* define if ide ports are perfect */ @@ -164,18 +169,13 @@ typedef unsigned char byte; /* used everywhere */ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ -#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290) #define SELECT_DRIVE(hwif,drive) \ { \ if (hwif->selectproc) \ hwif->selectproc(drive); \ - else \ - OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \ + OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \ } -#else -#define SELECT_DRIVE(hwif,drive) OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); -#endif /* CONFIG_BLK_DEV_HT6560B || CONFIG_BLK_DEV_PDC4030 */ - + /* * Now for the data we need to maintain per-drive: ide_drive_t */ @@ -248,7 +248,7 @@ typedef struct ide_drive_s { byte bios_sect __attribute__ ((aligned (8))); /* BIOS/fdisk/LILO sectors per track */ unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned short cyl; /* "real" number of cyls */ - unsigned int timing_data; /* for use by tuneproc()'s */ + unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ void *hwif; /* actually (ide_hwif_t *) */ struct wait_queue *wqueue; /* used to wait for drive in open() */ struct hd_driveid *id; /* drive model identification info */ @@ -256,6 +256,7 @@ typedef struct ide_drive_s { char name[4]; /* drive name, such as "hda" */ void *driver; /* (ide_driver_t *) */ void *driver_data; /* extra driver data */ + struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ } ide_drive_t; /* @@ -269,12 +270,9 @@ typedef struct ide_drive_s { * Returns 1 if DMA read/write could not be started, in which case the caller * should either try again later, or revert to PIO for the current request. */ -typedef enum { ide_dma_read = 0, ide_dma_write = 1, - ide_dma_abort = 2, ide_dma_check = 3, - ide_dma_status_bad = 4, ide_dma_transferred = 5, - ide_dma_begin = 6, ide_dma_on = 7, - ide_dma_off = 8, ide_dma_off_quietly = 9 } - ide_dma_action_t; +typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end, + ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly + } ide_dma_action_t; typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); @@ -293,7 +291,7 @@ typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); typedef void (ide_tuneproc_t)(ide_drive_t *, byte); /* - * This is used to provide HT6560B & PDC4030 & TRM290 interface support. + * This is used to provide support for strange interfaces */ typedef void (ide_selectproc_t) (ide_drive_t *); @@ -305,8 +303,16 @@ typedef enum { ide_unknown, ide_generic, ide_pci, ide_cmd640, ide_dtc2278, ide_ali14xx, ide_qd6580, ide_umc8672, ide_ht6560b, ide_pdc4030, ide_rz1000, ide_trm290, - ide_4drives } - hwif_chipset_t; + ide_4drives + } hwif_chipset_t; + +typedef struct ide_pci_devid_s { + unsigned short vid; + unsigned short did; +} ide_pci_devid_t; + +#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0}) +#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did) typedef struct hwif_s { struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ @@ -315,13 +321,14 @@ typedef struct hwif_s { ide_drive_t drives[MAX_DRIVES]; /* drive info */ struct gendisk *gd; /* gendisk structure */ ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ -#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290) ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ -#endif ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ unsigned long *dmatable; /* dma physical region descriptor table */ struct hwif_s *mate; /* other hwif from same PCI chip */ - unsigned short dma_base; /* base addr for dma ports (triton) */ + unsigned int dma_base; /* base addr for dma ports */ + unsigned int config_data; /* for use by chipset-specific code */ + unsigned int select_data; /* for use by chipset-specific code */ + struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ int irq; /* our irq number */ byte major; /* our major number */ char name[6]; /* name of interface, eg. "ide0" */ @@ -331,11 +338,12 @@ typedef struct hwif_s { unsigned present : 1; /* this interface exists */ unsigned serialized : 1; /* serialized operation with mate hwif */ unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ -#ifdef CONFIG_BLK_DEV_PDC4030 - unsigned is_pdc4030_2: 1;/* 2nd i/f on pdc4030 */ -#endif /* CONFIG_BLK_DEV_PDC4030 */ - unsigned reset : 1; /* reset after probe */ - unsigned pci_port : 1; /* for dual-port chips: 0=primary, 1=secondary */ + unsigned reset : 1; /* reset after probe */ + unsigned no_autodma : 1; /* don't automatically enable DMA at boot */ + byte channel; /* for dual-port chips: 0=primary, 1=secondary */ + byte pci_bus; /* for pci chipsets */ + byte pci_fn; /* for pci chipsets */ + ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */ #if (DISK_RECOVERY_TIME > 0) unsigned long last_time; /* time when previous rq was done */ #endif @@ -358,6 +366,20 @@ typedef struct hwgroup_s { } ide_hwgroup_t; /* + * /proc/ide interface + */ +typedef struct { + char *name; + read_proc_t *read_proc; + write_proc_t *write_proc; +} ide_proc_entry_t; + +void proc_ide_init(void); +void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p); +void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p); +read_proc_t proc_ide_read_geometry; + +/* * Subdrivers support. */ #define IDE_SUBDRIVER_VERSION 1 @@ -374,6 +396,8 @@ typedef unsigned long (ide_capacity_proc)(ide_drive_t *); typedef void (ide_special_proc)(ide_drive_t *); typedef struct ide_driver_s { + const char *name; + const char *version; byte media; unsigned busy : 1; unsigned supports_dma : 1; @@ -388,6 +412,7 @@ typedef struct ide_driver_s { ide_pre_reset_proc *pre_reset; ide_capacity_proc *capacity; ide_special_proc *special; + ide_proc_entry_t *proc; } ide_driver_t; #define DRIVER(drive) ((ide_driver_t *)((drive)->driver)) @@ -410,7 +435,7 @@ typedef struct ide_module_s { /* * ide_hwifs[] is the master data structure used to keep track * of just about everything in ide.c. Whenever possible, routines - * should be using pointers to a drive (ide_drive_t *) or + * should be using pointers to a drive (ide_drive_t *) or * pointers to a hwif (ide_hwif_t *), rather than indexing this * structure directly (the allocation/layout may change!). * @@ -533,7 +558,7 @@ typedef enum * If action is ide_next, then the rq is queued immediately after * the currently-being-processed-request (if any), and the function * returns without waiting for the new rq to be completed. As above, - * This is VERY DANGEROUS, and is intended for careful use by the + * This is VERY DANGEROUS, and is intended for careful use by the * ATAPI tape/cdrom driver code. * * If action is ide_end, then the rq is queued at the end of the @@ -542,7 +567,7 @@ typedef enum * use by the ATAPI tape/cdrom driver code. */ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action); - + /* * Clean up after success/failure of an explicit drive cmd. * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). @@ -617,10 +642,16 @@ ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n); int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); int ide_unregister_subdriver (ide_drive_t *drive); +#ifdef CONFIG_BLK_DEV_IDEPCI +unsigned int ide_find_free_region (unsigned short size) __init; +void ide_scan_pcibus (void) __init; +#endif #ifdef CONFIG_BLK_DEV_IDEDMA int ide_build_dmatable (ide_drive_t *drive); +void ide_dma_intr (ide_drive_t *drive); int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); -void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports); +void ide_setup_dma (ide_hwif_t *hwif, unsigned int dmabase, unsigned int num_ports) __init; +unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; #endif #ifdef CONFIG_BLK_DEV_IDE diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 925423581..d4a83f9a1 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -87,6 +87,18 @@ int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, }; */ int * max_readahead[MAX_BLKDEV] = { NULL, NULL, }; +/* + * Max number of sectors per request + */ +int * max_sectors[MAX_BLKDEV] = { NULL, NULL, }; + +static inline int get_max_sectors(kdev_t dev) +{ + if (!max_sectors[MAJOR(dev)]) + return 244; /* 254? */ + return max_sectors[MAJOR(dev)][MINOR(dev)]; +} + static inline struct request **get_queue(kdev_t dev) { int major = MAJOR(dev); @@ -300,9 +312,7 @@ void add_request(struct blk_dev_struct * dev, struct request * req) sti(); } -#define MAX_SECTORS 244 - -static inline void attempt_merge (struct request *req) +static inline void attempt_merge (struct request *req, int max_sectors) { struct request *next = req->next; @@ -310,7 +320,7 @@ static inline void attempt_merge (struct request *req) return; if (req->sector + req->nr_sectors != next->sector) return; - if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors >= MAX_SECTORS) + if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors) return; req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; @@ -324,7 +334,7 @@ void make_request(int major,int rw, struct buffer_head * bh) { unsigned int sector, count; struct request * req; - int rw_ahead, max_req; + int rw_ahead, max_req, max_sectors; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -391,6 +401,7 @@ void make_request(int major,int rw, struct buffer_head * bh) /* * Try to coalesce the new request with old requests */ + max_sectors = get_max_sectors(bh->b_rdev); cli(); req = *get_queue(bh->b_rdev); if (!req) { @@ -428,7 +439,7 @@ void make_request(int major,int rw, struct buffer_head * bh) continue; if (req->cmd != rw) continue; - if (req->nr_sectors >= MAX_SECTORS) + if (req->nr_sectors + count > max_sectors) continue; if (req->rq_dev != bh->b_rdev) continue; @@ -438,7 +449,7 @@ void make_request(int major,int rw, struct buffer_head * bh) req->bhtail = bh; req->nr_sectors += count; /* Can we now merge this req with the next? */ - attempt_merge(req); + attempt_merge(req, max_sectors); /* or to the beginning? */ } else if (req->sector - count == sector) { bh->b_reqnext = req->bh; @@ -684,6 +695,7 @@ __initfunc(int blk_dev_init(void)) } memset(ro_bits,0,sizeof(ro_bits)); memset(max_readahead, 0, sizeof(max_readahead)); + memset(max_sectors, 0, sizeof(max_sectors)); #ifdef CONFIG_AMIGA_Z2RAM z2_init(); #endif diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c new file mode 100644 index 000000000..62ae86f61 --- /dev/null +++ b/drivers/block/ns87415.c @@ -0,0 +1,228 @@ +/* + * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 + * + * Copyright (C) 1997-1998 Mark Lord + * + * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu) + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> +#include <linux/pci.h> +#include <linux/bios32.h> +#include <asm/io.h> +#include "ide.h" + + +#undef INCLUDE_OBSOLETE_NS87514_STUFF /* define this if you absolutely *need* the timings stuff */ + + +#ifdef INCLUDE_OBSOLETE_NS87514_STUFF +/* + * This part adapted from code from David S. Miller (davem@caipfs.rutgers.edu) + * which was in turn adapted from code from Mark Lord. + * + * Here as a temporary measure only. Will be removed once /proc/ide/ is working. + */ +#include "ide_modes.h" + +static void ns87415_program_modes(ide_drive_t *drive, byte active_count, byte recovery_count) +{ + ide_hwif_t *hwif = HWIF(drive); + byte cfg_reg, regval; + + cfg_reg = (0x44 + (8 * HWIF(drive)->channel) + (4 * drive->select.b.unit)); + + /* set identical PIO timings for read/write */ + regval = (17 - active_count) | ((16 - recovery_count) << 4); + pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg, regval); + pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg + 1, regval); +} + +static void set_ide_modes(ide_drive_t *drive, ide_pio_data_t *d, int bus_speed) +{ + int setup_time, active_time, cycle_time = d->cycle_time; + byte setup_count, active_count, pio_mode = d->pio_mode; + byte recovery_count, recovery_count2, cycle_count; + int recovery_time, clock_time; + + if(pio_mode > 5) + pio_mode = 5; + + setup_time = ide_pio_timings[pio_mode].setup_time; + active_time = ide_pio_timings[pio_mode].active_time; + + recovery_time = cycle_time - (setup_time + active_time); + clock_time = 1000 / bus_speed; + + cycle_count = (cycle_time + clock_time - 1) / clock_time; + setup_count = (setup_time + clock_time - 1) / clock_time; + active_count = (active_time + clock_time - 1) / clock_time; + + if(active_count < 2) + active_count = 2; + + recovery_count = (recovery_time + clock_time - 1) / clock_time; + recovery_count2 = cycle_count - (setup_count + active_count); + + if(recovery_count2 > recovery_count) + recovery_count = recovery_count2; + if(recovery_count < 2) + recovery_count = 2; + if(recovery_count > 17) { + active_count += recovery_count - 17; + recovery_count = 17; + } + + if(active_count > 16) + active_count = 16; + if(recovery_count > 16) + recovery_count = 16; + + printk("active[%d CLKS] recovery[%d CLKS]\n", active_count, recovery_count); + + ns87415_program_modes(drive, active_count, recovery_count); +} + +/* Configure for best PIO mode. */ +static void ns87415_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + ide_pio_data_t d; + int bus_speed = ide_system_bus_speed(); + + switch(mode_wanted) { + case 6: + case 7: + /* Changes to Fast-devsel are unsupported. */ + return; + + case 8: + case 9: + mode_wanted &= 1; + /* XXX set_prefetch_mode(index, mode_wanted); */ + printk("%s: %sbled NS87415 prefetching...\n", drive->name, mode_wanted ? "en" : "dis"); + return; + }; + + (void) ide_get_best_pio_mode(drive, mode_wanted, 5, &d); + + printk("%s: selected NS87415 PIO mode%d (%dns)%s ", + drive->name, d.pio_mode, d.cycle_time, + d.overridden ? " (overriding vendor mode)" : ""); + + set_ide_modes(drive, &d, bus_speed); +} +#endif /* INCLUDE_OBSOLETE_NS87514_STUFF */ + +static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = {0}; + +/* + * This routine either enables/disables (according to drive->present) + * the IRQ associated with the port (HWIF(drive)), + * and selects either PIO or DMA handshaking for the next I/O operation. + */ +static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned int bit, new, *old = (unsigned int *) hwif->select_data; + unsigned int flags; + + save_flags(flags); + cli(); + + new = *old; + + /* adjust IRQ enable bit */ + bit = 1 << (8 + hwif->channel); + new = drive->present ? (new | bit) : (new & ~bit); + + /* select PIO or DMA */ + bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1)); + new = use_dma ? (new | bit) : (new & ~bit); + + if (new != *old) { + *old = new; + (void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, new); + } + restore_flags(flags); +} + +static void ns87415_selectproc (ide_drive_t *drive) +{ + ns87415_prepare_drive (drive, drive->using_dma); +} + +static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + + switch (func) { + case ide_dma_end: /* returns 1 on error, 0 otherwise */ + { + byte dma_stat = inb(hwif->dma_base+2); + int rc = (dma_stat & 7) != 4; + outb(7, hwif->dma_base); /* from errata: stop DMA, clear INTR & ERROR */ + outb(dma_stat|6, hwif->dma_base+2); /* clear the INTR & ERROR bits */ + return rc; /* verify good DMA status */ + } + case ide_dma_write: + case ide_dma_read: + ns87415_prepare_drive(drive, 1); /* select DMA xfer */ + if (!ide_dmaproc(func, drive)) /* use standard DMA stuff */ + return 0; + ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ + return 1; + default: + return ide_dmaproc(func, drive); /* use standard DMA stuff */ + } +} + +__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) +{ + unsigned int ctrl, progif, using_inta; + + /* + * We cannot probe for IRQ: both ports share common IRQ on INTA. + * Also, leave IRQ masked during drive probing, to prevent infinite + * interrupts from a potentially floating INTA.. + * + * IRQs get unmasked in selectproc when drive is first used. + */ + (void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &ctrl); + (void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &progif); + /* is irq in "native" mode? */ + using_inta = progif & (1 << (hwif->channel << 1)); + if (!using_inta) + using_inta = ctrl & (1 << (4 + hwif->channel)); + (void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, ctrl); + if (hwif->mate) { + hwif->select_data = hwif->mate->select_data; + } else { + hwif->select_data = (unsigned int) &ns87415_control[ns87415_count++]; + ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */ + if (using_inta) + ctrl &= ~(1 << 6); /* unmask INTA */ + *((unsigned int *)hwif->select_data) = ctrl; + /* + * Set prefetch size to 512 bytes for both ports, + * but don't turn on/off prefetching here. + */ + pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, 0x55, 0xee); + } + if (!using_inta) + hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ + else if (!hwif->irq && hwif->mate && hwif->mate->irq) + hwif->irq = hwif->mate->irq; /* share IRQ with mate */ + + hwif->dmaproc = &ns87415_dmaproc; + hwif->selectproc = &ns87415_selectproc; +#ifdef INCLUDE_OBSOLETE_NS87514_STUFF + hwif->tuneproc = &ns87415_tuneproc; +#endif /* INCLUDE_OBSOLETE_NS87514_STUFF */ +} diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c index 0e0b23758..a4c94b0e6 100644 --- a/drivers/block/opti621.c +++ b/drivers/block/opti621.c @@ -110,7 +110,7 @@ int reg_base; /* there are stored pio numbers from other calls of opti621_tune_drive */ static void compute_pios(ide_drive_t *drive, byte pio) -/* Store values into drive->timing_data +/* Store values into drive->drive_data * second_contr - 0 for primary controller, 1 for secondary * slave_drive - 0 -> pio is for master, 1 -> pio is for slave * pio - PIO mode for selected drive (for other we don't know) @@ -119,17 +119,17 @@ static void compute_pios(ide_drive_t *drive, byte pio) int d; ide_hwif_t *hwif = HWIF(drive); - drive->timing_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL); + drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL); for (d = 0; d < 2; ++d) { drive = &hwif->drives[d]; if (drive->present) { - if (drive->timing_data == PIO_DONT_KNOW) - drive->timing_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL); + if (drive->drive_data == PIO_DONT_KNOW) + drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL); #ifdef OPTI621_DEBUG - printk("%s: Selected PIO mode %d\n", drive->name, drive->timing_data); + printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data); #endif } else { - drive->timing_data = PIO_NOT_EXIST; + drive->drive_data = PIO_NOT_EXIST; } } } @@ -192,7 +192,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks) clks->address_time = cmpt_clk(adr_setup, bus_speed); clks->data_time = cmpt_clk(data_pls, bus_speed); clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time - -adr_setup-data_pls, bus_speed); + - adr_setup-data_pls, bus_speed); if (clks->address_time<1) clks->address_time = 1; if (clks->address_time>4) clks->address_time = 4; if (clks->data_time<1) clks->data_time = 1; @@ -220,10 +220,10 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio) byte cycle1, cycle2, misc; ide_hwif_t *hwif = HWIF(drive); - /* set drive->timing_data for both drives */ + /* set drive->drive_data for both drives */ compute_pios(drive, pio); - pio1 = hwif->drives[0].timing_data; - pio2 = hwif->drives[1].timing_data; + pio1 = hwif->drives[0].drive_data; + pio2 = hwif->drives[1].drive_data; compute_clocks(pio1, &first); compute_clocks(pio2, &second); @@ -274,11 +274,11 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio) } /* - * ide_init_opti621() is Called from idedma.c once for each hwif found at boot. + * ide_init_opti621() is called once for each hwif found at boot. */ -void ide_init_opti621 (byte bus, byte fn, ide_hwif_t *hwif) +void ide_init_opti621 (ide_hwif_t *hwif) { - hwif->drives[0].timing_data = PIO_DONT_KNOW; - hwif->drives[1].timing_data = PIO_DONT_KNOW; + hwif->drives[0].drive_data = PIO_DONT_KNOW; + hwif->drives[1].drive_data = PIO_DONT_KNOW; hwif->tuneproc = &opti621_tune_drive; } diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index c161e58b6..30baff570 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -72,9 +72,7 @@ static void promise_selectproc (ide_drive_t *drive) { unsigned int number; - OUT_BYTE(drive->select.all,IDE_SELECT_REG); - udelay(1); /* paranoia */ - number = ((HWIF(drive)->is_pdc4030_2)<<1) + drive->select.b.unit; + number = (HWIF(drive)->channel << 1) + drive->select.b.unit; OUT_BYTE(number,IDE_FEATURE_REG); } @@ -134,7 +132,7 @@ int init_pdc4030 (void) drive = &hwif->drives[0]; second_hwif = &ide_hwifs[hwif->index+1]; - if(hwif->is_pdc4030_2) /* we've already been found ! */ + if(hwif->chipset == ide_pdc4030) /* we've already been found ! */ return 1; if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) @@ -172,6 +170,7 @@ int init_pdc4030 (void) hwif->chipset = second_hwif->chipset = ide_pdc4030; hwif->mate = second_hwif; second_hwif->mate = hwif; + second_hwif->channel = 1; hwif->selectproc = second_hwif->selectproc = &promise_selectproc; /* Shift the remaining interfaces down by one */ for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) { @@ -182,7 +181,6 @@ int init_pdc4030 (void) h->io_ports[IDE_CONTROL_OFFSET] = (h-1)->io_ports[IDE_CONTROL_OFFSET]; h->noprobe = (h-1)->noprobe; } - second_hwif->is_pdc4030_2 = 1; ide_init_hwif_ports(second_hwif->io_ports, hwif->io_ports[IDE_DATA_OFFSET], NULL); second_hwif->io_ports[IDE_CONTROL_OFFSET] = hwif->io_ports[IDE_CONTROL_OFFSET]; second_hwif->irq = hwif->irq; diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index 296aef3a7..9c13bfea9 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -65,4 +65,5 @@ void init_qd6580 (void) ide_hwifs[0].tuneproc = &tune_qd6580; ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; + ide_hwifs[1].channel = 1; } diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c index b7270c559..670fe3e58 100644 --- a/drivers/block/rz1000.c +++ b/drivers/block/rz1000.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/rz1000.c Version 0.03 Mar 20, 1996 + * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) + * Copyright (C) 1995-1998 Linus Torvalds & author (see below) */ /* @@ -9,6 +9,8 @@ * * This file provides support for disabling the buggy read-ahead * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards. + * + * Dunno if this fixes both ports, or only the primary port (?). */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -26,21 +28,40 @@ #include <linux/pci.h> #include "ide.h" -static void init_rz1000 (byte bus, byte fn, const char *name) +#ifdef CONFIG_BLK_DEV_IDEPCI + +__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif)) /* called from ide-pci.c */ +{ + unsigned short reg; + + hwif->chipset = ide_rz1000; + if (!pcibios_read_config_word (hwif->pci_bus, hwif->pci_fn, 0x40, ®) + && !pcibios_write_config_word(hwif->pci_bus, hwif->pci_fn, 0x40, reg & 0xdfff)) + { + printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name); + } else { + hwif->serialized = 1; + hwif->drives[0].no_unmask = 1; + hwif->drives[1].no_unmask = 1; + printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name); + } +} + +#else + +__initfunc(static void init_rz1000 (byte bus, byte fn, const char *name)) { unsigned short reg, h; - printk("%s: buggy IDE controller: ", name); if (!pcibios_read_config_word (bus, fn, PCI_COMMAND, ®) && !(reg & 1)) { - printk("disabled (BIOS)\n"); + printk("%s: buggy IDE controller disabled (BIOS)\n", name); return; } if (!pcibios_read_config_word (bus, fn, 0x40, ®) && !pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff)) { - printk("disabled read-ahead\n"); + printk("IDE: disabled chipset read-ahead (buggy %s)\n", name); } else { - printk("\n"); for (h = 0; h < MAX_HWIFS; ++h) { ide_hwif_t *hwif = &ide_hwifs[h]; if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170) @@ -50,13 +71,15 @@ static void init_rz1000 (byte bus, byte fn, const char *name) hwif->serialized = 1; hwif->drives[0].no_unmask = 1; hwif->drives[1].no_unmask = 1; - printk(" %s: serialized, disabled unmasking\n", hwif->name); + if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170) + hwif->channel = 1; + printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name); } } } } -void ide_probe_for_rz100x (void) +__initfunc(void ide_probe_for_rz100x (void)) /* called from ide.c */ { byte index, bus, fn; @@ -65,3 +88,5 @@ void ide_probe_for_rz100x (void) for (index = 0; !pcibios_find_device (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, index, &bus, &fn); ++index) init_rz1000 (bus, fn, "RZ1001"); } + +#endif CONFIG_BLK_DEV_IDEPCI diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index 7b8fb308c..f88f597d8 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/trm290.c Version 1.00 December 3, 1997 + * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 * * Copyright (c) 1997-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -34,18 +34,20 @@ * The configuration registers are addressed in normal I/O port space * and are used as follows: * - * 0x3df2 when WRITTEN: chiptest register (byte, write-only) + * trm290_base depends on jumper settings, and is probed for by ide-dma.c + * + * trm290_base+2 when WRITTEN: chiptest register (byte, write-only) * bit7 must always be written as "1" * bits6-2 undefined * bit1 1=legacy_compatible_mode, 0=native_pci_mode * bit0 1=test_mode, 0=normal(default) * - * 0x3df2 when READ: status register (byte, read-only) + * trm290_base+2 when READ: status register (byte, read-only) * bits7-2 undefined * bit1 channel0 busmaster interrupt status 0=none, 1=asserted * bit0 channel0 interrupt status 0=none, 1=asserted * - * 0x3df3 Interrupt mask register + * trm290_base+3 Interrupt mask register * bits7-5 undefined * bit4 legacy_header: 1=present, 0=absent * bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only) @@ -53,7 +55,7 @@ * bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default) * bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default) * - * 0x3df1 "CPR" Config Pointer Register (byte) + * trm290_base+1 "CPR" Config Pointer Register (byte) * bit7 1=autoincrement CPR bits 2-0 after each access of CDR * bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state * bit5 0=enabled master burst access (default), 1=disable (write only) @@ -61,7 +63,7 @@ * bit3 0=primary IDE channel, 1=secondary IDE channel * bits2-0 register index for accesses through CDR port * - * 0x3df0 "CDR" Config Data Register (word) + * trm290_base+0 "CDR" Config Data Register (word) * two sets of seven config registers, * selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6), * each index defined below: @@ -130,98 +132,137 @@ #include <linux/blkdev.h> #include <linux/init.h> #include <linux/hdreg.h> +#include <linux/pci.h> +#include <linux/bios32.h> +#include <linux/delay.h> + #include <asm/io.h> #include "ide.h" -static void select_dma_or_pio(ide_hwif_t *hwif, int dma) +static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { - static int previous[2] = {-1,-1}; + ide_hwif_t *hwif = HWIF(drive); + unsigned int reg; unsigned long flags; - if (previous[hwif->pci_port] != dma) { - unsigned short cfg1 = dma ? 0xa3 : 0x21; - previous[hwif->pci_port] = dma; - save_flags(flags); - cli(); - outb(0x51|(hwif->pci_port<<3),0x3df1); - outw(cfg1,0x3df0); - restore_flags(flags); + /* select PIO or DMA */ + reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82); + + save_flags(flags); + cli(); + + if (reg != hwif->select_data) { + hwif->select_data = reg; + outb(0x51|(hwif->channel<<3), hwif->config_data+1); /* set PIO/DMA */ + outw(reg & 0xff, hwif->config_data); + } + + /* enable IRQ if not probing */ + if (drive->present) { + reg = inw(hwif->config_data+3) & 0x13; + reg &= ~(1 << hwif->channel); + outw(reg, hwif->config_data+3); } + + restore_flags(flags); } -/* - * trm290_dma_intr() is the handler for trm290 disk read/write DMA interrupts - */ -static void trm290_dma_intr (ide_drive_t *drive) +static void trm290_selectproc (ide_drive_t *drive) { - byte stat; - int i; - struct request *rq = HWGROUP(drive)->rq; - - stat = GET_STAT(); /* get drive status */ - if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { - unsigned short dma_stat = inw(HWIF(drive)->dma_base + 2); - if (dma_stat == 0x00ff) { - rq = HWGROUP(drive)->rq; - for (i = rq->nr_sectors; i > 0;) { - i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); - } - return; - } - printk("%s: bad trm290 DMA status: 0x%04x\n", drive->name, dma_stat); - } - sti(); - ide_error(drive, "dma_intr", stat); + trm290_prepare_drive(drive, drive->using_dma); } static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned int count, reading = 1 << 1; + unsigned int count, reading = 2, writing = 0; - if (drive->media == ide_disk) { - switch (func) { - case ide_dma_write: - reading = 0; + switch (func) { + case ide_dma_write: + reading = 0; + writing = 1; #ifdef TRM290_NO_DMA_WRITES - break; /* always use PIO for writes */ + break; /* always use PIO for writes */ #endif - case ide_dma_read: - if (!(count = ide_build_dmatable(drive))) - break; /* try PIO instead of DMA */ - select_dma_or_pio(hwif, 1); /* select DMA mode */ - outl_p(virt_to_bus(hwif->dmatable)|reading, hwif->dma_base); - outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ - ide_set_handler(drive, &trm290_dma_intr, WAIT_CMD); - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + case ide_dma_read: + if (!(count = ide_build_dmatable(drive))) + break; /* try PIO instead of DMA */ + trm290_prepare_drive(drive, 1); /* select DMA xfer */ + outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base); + outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ + if (drive->media != ide_disk) return 0; - default: - return ide_dmaproc(func, drive); - } + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + case ide_dma_begin: + return 0; + case ide_dma_end: + return (inw(hwif->dma_base+2) != 0x00ff); + default: + return ide_dmaproc(func, drive); } - select_dma_or_pio(hwif, 0); /* force PIO mode for this operation */ + trm290_prepare_drive(drive, 0); /* select PIO xfer */ return 1; } -static void trm290_selectproc (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - - select_dma_or_pio(hwif, drive->using_dma); - OUT_BYTE(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); -} - /* * Invoked from ide-dma.c at boot time. */ -__initfunc(void ide_init_trm290 (byte bus, byte fn, ide_hwif_t *hwif)) +__initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) { + unsigned int cfgbase = 0; + unsigned long flags; + byte reg, progif; + hwif->chipset = ide_trm290; - hwif->selectproc = trm290_selectproc; - hwif->drives[0].autotune = 2; /* play it safe */ - hwif->drives[1].autotune = 2; /* play it safe */ - ide_setup_dma(hwif, hwif->pci_port ? 0x3d74 : 0x3df4, 2); + if (!pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, 0x09, &progif) && (progif & 5) + && !pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x20, &cfgbase) && cfgbase) + { + hwif->config_data = cfgbase & ~1; + printk("TRM290: chip config base at 0x%04x\n", hwif->config_data); + } else { + hwif->config_data = 0x3df4; + printk("TRM290: using default config base at 0x%04x\n", hwif->config_data); + } + + save_flags(flags); + cli(); + /* put config reg into first byte of hwif->select_data */ + outb(0x51|(hwif->channel<<3), hwif->config_data+1); + hwif->select_data = 0x21; /* select PIO as default */ + outb(hwif->select_data, hwif->config_data); + reg = inb(hwif->config_data+3); /* get IRQ info */ + reg = (reg & 0x10) | 0x03; /* mask IRQs for both ports */ + outb(reg, hwif->config_data+3); + restore_flags(flags); + + if ((reg & 0x10)) + hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ + else if (!hwif->irq && hwif->mate && hwif->mate->irq) + hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */ + ide_setup_dma(hwif, (hwif->channel ? hwif->config_data ^ 0x0080 : hwif->config_data) + 4, 2); hwif->dmaproc = &trm290_dmaproc; + hwif->selectproc = &trm290_selectproc; + hwif->no_autodma = 1; /* play it safe for now */ +#if 1 + { + /* + * My trm290-based card doesn't seem to work with all possible values + * for the control basereg, so this kludge ensures that we use only + * values that are known to work. Ugh. -ml + */ + unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4; + static unsigned short next_offset = 0; + + outb(0x54|(hwif->channel<<3), hwif->config_data+1); + old = inw(hwif->config_data) & ~1; + if (old != compat && inb(old+2) == 0xff) { + compat += (next_offset += 0x400); /* leave lower 10 bits untouched */ + hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; /* FIXME: should do a check_region */ + outw(compat|1, hwif->config_data); + printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1); + } + } +#endif } diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c index 628e13bb5..8856dad35 100644 --- a/drivers/block/umc8672.c +++ b/drivers/block/umc8672.c @@ -153,4 +153,5 @@ void init_umc8672 (void) /* called from ide.c */ ide_hwifs[1].tuneproc = &tune_umc; ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; + ide_hwifs[1].channel = 1; } |