diff options
Diffstat (limited to 'i386/i386at/gpl/linux/block')
-rw-r--r-- | i386/i386at/gpl/linux/block/cmd640.c | 738 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/floppy.c | 4100 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/genhd.c | 610 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/ide-cd.c | 2770 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/ide.c | 3087 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/ide.h | 655 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/ide_modes.h | 142 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/rz1000.c | 56 | ||||
-rw-r--r-- | i386/i386at/gpl/linux/block/triton.c | 467 |
9 files changed, 0 insertions, 12625 deletions
diff --git a/i386/i386at/gpl/linux/block/cmd640.c b/i386/i386at/gpl/linux/block/cmd640.c deleted file mode 100644 index 99a139d..0000000 --- a/i386/i386at/gpl/linux/block/cmd640.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * linux/drivers/block/cmd640.c Version 0.07 Jan 27, 1996 - * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) - */ - -/* - * Principal Author/Maintainer: abramov@cecmow.enet.dec.com (Igor Abramov) - * - * This file provides support for the advanced features and bugs - * of IDE interfaces using the CMD Technologies 0640 IDE interface chip. - * - * Version 0.01 Initial version, hacked out of ide.c, - * and #include'd rather than compiled separately. - * This will get cleaned up in a subsequent release. - * - * Version 0.02 Fixes for vlb initialization code, enable - * read-ahead for versions 'B' and 'C' of chip by - * default, some code cleanup. - * - * Version 0.03 Added reset of secondary interface, - * and black list for devices which are not compatible - * with read ahead mode. Separate function for setting - * readahead is added, possibly it will be called some - * day from ioctl processing code. - * - * Version 0.04 Now configs/compiles separate from ide.c -ml - * - * Version 0.05 Major rewrite of interface timing code. - * Added new function cmd640_set_mode to set PIO mode - * from ioctl call. New drives added to black list. - * - * Version 0.06 More code cleanup. Readahead is enabled only for - * detected hard drives, not included in readahed - * black list. - * - * Version 0.07 Changed to more conservative drive tuning policy. - * Unknown drives, which report PIO < 4 are set to - * (reported_PIO - 1) if it is supported, or to PIO0. - * List of known drives extended by info provided by - * CMD at their ftp site. - * - * Version 0.08 Added autotune/noautotune support. -ml - * - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <asm/io.h> -#include "ide.h" -#include "ide_modes.h" - -int cmd640_vlb = 0; - -/* - * CMD640 specific registers definition. - */ - -#define VID 0x00 -#define DID 0x02 -#define PCMD 0x04 -#define PSTTS 0x06 -#define REVID 0x08 -#define PROGIF 0x09 -#define SUBCL 0x0a -#define BASCL 0x0b -#define BaseA0 0x10 -#define BaseA1 0x14 -#define BaseA2 0x18 -#define BaseA3 0x1c -#define INTLINE 0x3c -#define INPINE 0x3d - -#define CFR 0x50 -#define CFR_DEVREV 0x03 -#define CFR_IDE01INTR 0x04 -#define CFR_DEVID 0x18 -#define CFR_AT_VESA_078h 0x20 -#define CFR_DSA1 0x40 -#define CFR_DSA0 0x80 - -#define CNTRL 0x51 -#define CNTRL_DIS_RA0 0x40 -#define CNTRL_DIS_RA1 0x80 -#define CNTRL_ENA_2ND 0x08 - -#define CMDTIM 0x52 -#define ARTTIM0 0x53 -#define DRWTIM0 0x54 -#define ARTTIM1 0x55 -#define DRWTIM1 0x56 -#define ARTTIM23 0x57 -#define DIS_RA2 0x04 -#define DIS_RA3 0x08 -#define DRWTIM23 0x58 -#define BRST 0x59 - -static ide_tuneproc_t cmd640_tune_drive; - -/* Interface to access cmd640x registers */ -static void (*put_cmd640_reg)(int reg_no, int val); -static byte (*get_cmd640_reg)(int reg_no); - -enum { none, vlb, pci1, pci2 }; -static int bus_type = none; -static int cmd640_chip_version; -static int cmd640_key; -static int bus_speed; /* MHz */ - -/* - * For some unknown reasons pcibios functions which read and write registers - * do not always work with cmd640. We use direct IO instead. - */ - -/* PCI method 1 access */ - -static void put_cmd640_reg_pci1(int reg_no, int val) -{ - unsigned long flags; - - save_flags(flags); - cli(); - outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8); - outb_p(val, (reg_no & 3) + 0xcfc); - restore_flags(flags); -} - -static byte get_cmd640_reg_pci1(int reg_no) -{ - byte b; - unsigned long flags; - - save_flags(flags); - cli(); - outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8); - b = inb_p(0xcfc + (reg_no & 3)); - restore_flags(flags); - return b; -} - -/* PCI method 2 access (from CMD datasheet) */ - -static void put_cmd640_reg_pci2(int reg_no, int val) -{ - unsigned long flags; - - save_flags(flags); - cli(); - outb_p(0x10, 0xcf8); - outb_p(val, cmd640_key + reg_no); - outb_p(0, 0xcf8); - restore_flags(flags); -} - -static byte get_cmd640_reg_pci2(int reg_no) -{ - byte b; - unsigned long flags; - - save_flags(flags); - cli(); - outb_p(0x10, 0xcf8); - b = inb_p(cmd640_key + reg_no); - outb_p(0, 0xcf8); - restore_flags(flags); - return b; -} - -/* VLB access */ - -static void put_cmd640_reg_vlb(int reg_no, int val) -{ - unsigned long flags; - - save_flags(flags); - cli(); - outb_p(reg_no, cmd640_key + 8); - outb_p(val, cmd640_key + 0xc); - restore_flags(flags); -} - -static byte get_cmd640_reg_vlb(int reg_no) -{ - byte b; - unsigned long flags; - - save_flags(flags); - cli(); - outb_p(reg_no, cmd640_key + 8); - b = inb_p(cmd640_key + 0xc); - restore_flags(flags); - return b; -} - -/* - * Probe for CMD640x -- pci method 1 - */ - -static int probe_for_cmd640_pci1(void) -{ - long id; - int k; - - for (k = 0x80000000; k <= 0x8000f800; k += 0x800) { - outl(k, 0xcf8); - id = inl(0xcfc); - if (id != 0x06401095) - continue; - put_cmd640_reg = put_cmd640_reg_pci1; - get_cmd640_reg = get_cmd640_reg_pci1; - cmd640_key = k; - return 1; - } - return 0; -} - -/* - * Probe for CMD640x -- pci method 2 - */ - -static int probe_for_cmd640_pci2(void) -{ - int i; - int v_id; - int d_id; - - for (i = 0xc000; i <= 0xcf00; i += 0x100) { - outb(0x10, 0xcf8); - v_id = inw(i); - d_id = inw(i + 2); - outb(0, 0xcf8); - if (v_id != 0x1095 || d_id != 0x640) - continue; - put_cmd640_reg = put_cmd640_reg_pci2; - get_cmd640_reg = get_cmd640_reg_pci2; - cmd640_key = i; - return 1; - } - return 0; -} - -/* - * Probe for CMD640x -- vlb - */ - -static int probe_for_cmd640_vlb(void) { - byte b; - - outb(CFR, 0x178); - b = inb(0x17c); - if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) { - outb(CFR, 0x78); - b = inb(0x7c); - if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h)) - return 0; - cmd640_key = 0x70; - } else { - cmd640_key = 0x170; - } - put_cmd640_reg = put_cmd640_reg_vlb; - get_cmd640_reg = get_cmd640_reg_vlb; - return 1; -} - -/* - * Low level reset for controller, actually it has nothing specific for - * CMD640, but I don't know how to use standard reset routine before - * we recognized any drives. - */ - -static void cmd640_reset_controller(int iface_no) -{ - int retry_count = 600; - int base_port = iface_no ? 0x170 : 0x1f0; - - outb_p(4, base_port + 7); - udelay(5); - outb_p(0, base_port + 7); - - do { - udelay(5); - retry_count -= 1; - } while ((inb_p(base_port + 7) & 0x80) && retry_count); - - if (retry_count == 0) - printk("cmd640: failed to reset controller %d\n", iface_no); -#if 0 - else - printk("cmd640: controller %d reset [%d]\n", - iface_no, retry_count); -#endif -} - -/* - * Probe for Cmd640x and initialize it if found - */ - -int ide_probe_for_cmd640x(void) -{ - int second_port; - byte b; - - if (probe_for_cmd640_pci1()) { - bus_type = pci1; - } else if (probe_for_cmd640_pci2()) { - bus_type = pci2; - } else if (cmd640_vlb && probe_for_cmd640_vlb()) { - /* May be remove cmd640_vlb at all, and probe in any case */ - bus_type = vlb; - } else { - return 0; - } - - ide_hwifs[0].serialized = 1; /* ensure this *always* gets set */ - -#if 0 - /* Dump initial state of chip registers */ - for (b = 0; b != 0xff; b++) { - printk(" %2x%c", get_cmd640_reg(b), - ((b&0xf) == 0xf) ? '\n' : ','); - } - -#endif - - /* - * Undocumented magic. (There is no 0x5b port in specs) - */ - - put_cmd640_reg(0x5b, 0xbd); - if (get_cmd640_reg(0x5b) != 0xbd) { - printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n"); - return 0; - } - put_cmd640_reg(0x5b, 0); - - /* - * Documented magic. - */ - - cmd640_chip_version = get_cmd640_reg(CFR) & CFR_DEVREV; - if (cmd640_chip_version == 0) { - printk ("ide: wrong CMD640 version -- 0\n"); - return 0; - } - - /* - * Setup the most conservative timings for all drives, - */ - put_cmd640_reg(ARTTIM0, 0xc0); - put_cmd640_reg(ARTTIM1, 0xc0); - put_cmd640_reg(ARTTIM23, 0xcc); /* 0xc0? */ - - /* - * Do not initialize secondary controller for vlbus - */ - second_port = (bus_type != vlb); - - /* - * Set the maximum allowed bus speed (it is safest until we - * find how to detect bus speed) - * Normally PCI bus runs at 33MHz, but often works overclocked to 40 - */ - bus_speed = (bus_type == vlb) ? 50 : 40; - - /* - * Setup Control Register - */ - b = get_cmd640_reg(CNTRL); - - if (second_port) - b |= CNTRL_ENA_2ND; - else - b &= ~CNTRL_ENA_2ND; - - /* - * Disable readahead for drives at primary interface - */ - b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1); - - put_cmd640_reg(CNTRL, b); - - /* - * Note that we assume that the first interface is at 0x1f0, - * and that the second interface, if enabled, is at 0x170. - */ - ide_hwifs[0].chipset = ide_cmd640; - ide_hwifs[0].tuneproc = &cmd640_tune_drive; - if (ide_hwifs[0].drives[0].autotune == 0) - ide_hwifs[0].drives[0].autotune = 1; - if (ide_hwifs[0].drives[1].autotune == 0) - ide_hwifs[0].drives[1].autotune = 1; - - /* - * Initialize 2nd IDE port, if required - */ - if (second_port) { - ide_hwifs[1].chipset = ide_cmd640; - ide_hwifs[1].tuneproc = &cmd640_tune_drive; - if (ide_hwifs[1].drives[0].autotune == 0) - ide_hwifs[1].drives[0].autotune = 1; - if (ide_hwifs[1].drives[1].autotune == 0) - ide_hwifs[1].drives[1].autotune = 1; - /* We reset timings, and disable read-ahead */ - put_cmd640_reg(ARTTIM23, (DIS_RA2 | DIS_RA3)); - put_cmd640_reg(DRWTIM23, 0); - - cmd640_reset_controller(1); - } - - printk("ide: buggy CMD640%c interface at ", - 'A' - 1 + cmd640_chip_version); - switch (bus_type) { - case vlb : - printk("local bus, port 0x%x", cmd640_key); - break; - case pci1: - printk("pci, (0x%x)", cmd640_key); - break; - case pci2: - printk("pci,(access method 2) (0x%x)", cmd640_key); - break; - } - - /* - * Reset interface timings - */ - put_cmd640_reg(CMDTIM, 0); - - printk("\n ... serialized, secondary interface %s\n", - second_port ? "enabled" : "disabled"); - - return 1; -} - -int cmd640_off(void) { - static int a = 0; - byte b; - - if (bus_type == none || a == 1) - return 0; - a = 1; - b = get_cmd640_reg(CNTRL); - b &= ~CNTRL_ENA_2ND; - put_cmd640_reg(CNTRL, b); - return 1; -} - -/* - * Sets readahead mode for specific drive - * in the future it could be called from ioctl - */ - -static void set_readahead_mode(int mode, int if_num, int dr_num) -{ - static int masks[2][2] = - { - {CNTRL_DIS_RA0, CNTRL_DIS_RA1}, - {DIS_RA2, DIS_RA3} - }; - - int port = (if_num == 0) ? CNTRL : ARTTIM23; - int mask = masks[if_num][dr_num]; - byte b; - - b = get_cmd640_reg(port); - if (mode) - b &= ~mask; /* Enable readahead for specific drive */ - else - b |= mask; /* Disable readahed for specific drive */ - put_cmd640_reg(port, b); -} - -static struct readahead_black_list { - const char* name; - int mode; -} drives_ra[] = { - { "ST3655A", 0 }, - { "SAMSUNG", 0 }, /* Be conservative */ - { NULL, 0 } -}; - -static int strmatch(const char* pattern, const char* name) { - char c1, c2; - - while (1) { - c1 = *pattern++; - c2 = *name++; - if (c1 == 0) { - return 0; - } - if (c1 != c2) - return 1; - } -} - -static int known_drive_readahead(char* name) { - int i; - - for (i = 0; drives_ra[i].name != NULL; i++) { - if (strmatch(drives_ra[i].name, name) == 0) { - return drives_ra[i].mode; - } - } - return -1; -} - -static int arttim[4] = {2, 2, 2, 2}; /* Address setup count (in clocks) */ -static int a_count[4] = {1, 1, 1, 1}; /* Active count (encoded) */ -static int r_count[4] = {1, 1, 1, 1}; /* Recovery count (encoded) */ - -/* - * Convert address setup count from number of clocks - * to representation used by controller - */ - -inline static int pack_arttim(int clocks) -{ - if (clocks <= 2) return 0x40; - else if (clocks == 3) return 0x80; - else if (clocks == 4) return 0x00; - else return 0xc0; -} - -/* - * Pack active and recovery counts into single byte representation - * used by controller - */ - -inline static int pack_counts(int act_count, int rec_count) -{ - return ((act_count & 0x0f)<<4) | (rec_count & 0x0f); -} - -inline int max(int a, int b) { return a > b ? a : b; } -inline int max4(int *p) { return max(p[0], max(p[1], max(p[2], p[3]))); } - -/* - * Set timing parameters - */ - -static void cmd640_set_timing(int if_num, int dr_num) -{ - int b_reg; - int ac, rc, at; - - /* - * Set address setup count and drive read/write timing registers. - * Primary interface has individual count/timing registers for - * each drive. Secondary interface has common set of registers, and - * we should set timings for the slowest drive. - */ - - if (if_num == 0) { - b_reg = dr_num ? ARTTIM1 : ARTTIM0; - at = arttim[dr_num]; - ac = a_count[dr_num]; - rc = r_count[dr_num]; - } else { - b_reg = ARTTIM23; - at = max(arttim[2], arttim[3]); - ac = max(a_count[2], a_count[3]); - rc = max(r_count[2], r_count[3]); - } - - put_cmd640_reg(b_reg, pack_arttim(at)); - put_cmd640_reg(b_reg + 1, pack_counts(ac, rc)); - - /* - * Update CMDTIM (IDE Command Block Timing Register) - */ - - ac = max4(r_count); - rc = max4(a_count); - put_cmd640_reg(CMDTIM, pack_counts(ac, rc)); -} - -/* - * Standard timings for PIO modes - */ - -static struct pio_timing { - int mc_time; /* Minimal cycle time (ns) */ - int av_time; /* Address valid to DIOR-/DIOW- setup (ns) */ - int ds_time; /* DIOR data setup (ns) */ -} pio_timings[6] = { - { 70, 165, 600 }, /* PIO Mode 0 */ - { 50, 125, 383 }, /* PIO Mode 1 */ - { 30, 100, 240 }, /* PIO Mode 2 */ - { 30, 80, 180 }, /* PIO Mode 3 */ - { 25, 70, 125 }, /* PIO Mode 4 -- should be 120, not 125 */ - { 20, 50, 100 } /* PIO Mode ? (nonstandard) */ -}; - -static void cmd640_timings_to_clocks(int mc_time, int av_time, int ds_time, - int clock_time, int drv_idx) -{ - int a, b; - - arttim[drv_idx] = (mc_time + clock_time - 1)/clock_time; - - a = (av_time + clock_time - 1)/clock_time; - if (a < 2) - a = 2; - b = (ds_time + clock_time - 1)/clock_time - a; - if (b < 2) - b = 2; - if (b > 0x11) { - a += b - 0x11; - b = 0x11; - } - if (a > 0x10) - a = 0x10; - if (cmd640_chip_version > 1) - b -= 1; - if (b > 0x10) - b = 0x10; - - a_count[drv_idx] = a; - r_count[drv_idx] = b; -} - -static void set_pio_mode(int if_num, int drv_num, int mode_num) { - int p_base; - int i; - - p_base = if_num ? 0x170 : 0x1f0; - outb_p(3, p_base + 1); - outb_p(mode_num | 8, p_base + 2); - outb_p((drv_num | 0xa) << 4, p_base + 6); - outb_p(0xef, p_base + 7); - for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++) - udelay(10000); -} - -/* - * Set a specific pio_mode for a drive - */ - -static void cmd640_set_mode(ide_drive_t* drive, int pio_mode) { - int interface_number; - int drive_number; - int clock_time; /* ns */ - int mc_time, av_time, ds_time; - - interface_number = HWIF(drive)->index; - drive_number = drive->select.b.unit; - clock_time = 1000/bus_speed; - - mc_time = pio_timings[pio_mode].mc_time; - av_time = pio_timings[pio_mode].av_time; - ds_time = pio_timings[pio_mode].ds_time; - - cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time, - interface_number*2 + drive_number); - set_pio_mode(interface_number, drive_number, pio_mode); - cmd640_set_timing(interface_number, drive_number); -} - -/* - * Drive PIO mode "autoconfiguration". - * Ideally, this code should *always* call cmd640_set_mode(), but it doesn't. - */ - -static void cmd640_tune_drive(ide_drive_t *drive, byte pio_mode) { - int interface_number; - int drive_number; - int clock_time; /* ns */ - int max_pio; - int mc_time, av_time, ds_time; - struct hd_driveid* id; - int readahead; /* there is a global named read_ahead */ - - if (pio_mode != 255) { - cmd640_set_mode(drive, pio_mode); - return; - } - - interface_number = HWIF(drive)->index; - drive_number = drive->select.b.unit; - clock_time = 1000/bus_speed; - id = drive->id; - if ((max_pio = ide_scan_pio_blacklist(id->model)) != -1) { - ds_time = pio_timings[max_pio].ds_time; - } else { - max_pio = id->tPIO; - ds_time = pio_timings[max_pio].ds_time; - if (id->field_valid & 2) { - if ((id->capability & 8) && (id->eide_pio_modes & 7)) { - if (id->eide_pio_modes & 4) max_pio = 5; - else if (id->eide_pio_modes & 2) max_pio = 4; - else max_pio = 3; - ds_time = id->eide_pio_iordy; - } else { - ds_time = id->eide_pio; - } - if (ds_time == 0) - ds_time = pio_timings[max_pio].ds_time; - } - - /* - * Conservative "downgrade" - */ - if (max_pio < 4 && max_pio != 0) { - max_pio -= 1; - ds_time = pio_timings[max_pio].ds_time; - } - } - mc_time = pio_timings[max_pio].mc_time; - av_time = pio_timings[max_pio].av_time; - cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time, - interface_number*2 + drive_number); - set_pio_mode(interface_number, drive_number, max_pio); - cmd640_set_timing(interface_number, drive_number); - - /* - * Disable (or set) readahead mode - */ - - readahead = 0; - if (cmd640_chip_version > 1) { /* Mmmm.. probably should be > 2 ?? */ - readahead = known_drive_readahead(id->model); - if (readahead == -1) - readahead = 1; /* Mmmm.. probably be 0 ?? */ - set_readahead_mode(readahead, interface_number, drive_number); - } - - printk ("Mode and Timing set to PIO%d, Readahead is %s\n", - max_pio, readahead ? "enabled" : "disabled"); -} - diff --git a/i386/i386at/gpl/linux/block/floppy.c b/i386/i386at/gpl/linux/block/floppy.c deleted file mode 100644 index ee4a898..0000000 --- a/i386/i386at/gpl/linux/block/floppy.c +++ /dev/null @@ -1,4100 +0,0 @@ -/* - * linux/kernel/floppy.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1993, 1994 Alain Knaff - */ -/* - * 02.12.91 - Changed to static variables to indicate need for reset - * and recalibrate. This makes some things easier (output_byte reset - * checking etc), and means less interrupt jumping in case of errors, - * so the code is hopefully easier to understand. - */ - -/* - * This file is certainly a mess. I've tried my best to get it working, - * but I don't like programming floppies, and I have only one anyway. - * Urgel. I should check for more errors, and do more graceful error - * recovery. Seems there are problems with several drives. I've tried to - * correct them. No promises. - */ - -/* - * As with hd.c, all routines within this file can (and will) be called - * by interrupts, so extreme caution is needed. A hardware interrupt - * handler may not sleep, or a kernel panic will happen. Thus I cannot - * call "floppy-on" directly, but have to set a special timer interrupt - * etc. - */ - -/* - * 28.02.92 - made track-buffering routines, based on the routines written - * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus. - */ - -/* - * Automatic floppy-detection and formatting written by Werner Almesberger - * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with - * the floppy-change signal detection. - */ - -/* - * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed - * FDC data overrun bug, added some preliminary stuff for vertical - * recording support. - * - * 1992/9/17: Added DMA allocation & DMA functions. -- hhb. - * - * TODO: Errors are still not counted properly. - */ - -/* 1992/9/20 - * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl) - * modelled after the freeware MS/DOS program fdformat/88 V1.8 by - * Christoph H. Hochst\"atter. - * I have fixed the shift values to the ones I always use. Maybe a new - * ioctl() should be created to be able to modify them. - * There is a bug in the driver that makes it impossible to format a - * floppy as the first thing after bootup. - */ - -/* - * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and - * this helped the floppy driver as well. Much cleaner, and still seems to - * work. - */ - -/* 1994/6/24 --bbroad-- added the floppy table entries and made - * minor modifications to allow 2.88 floppies to be run. - */ - -/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more - * disk types. - */ - -/* - * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger - * format bug fixes, but unfortunately some new bugs too... - */ - -/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write - * errors to allow safe writing by specialized programs. - */ - -/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks - * by defining bit 1 of the "stretch" parameter to mean put sectors on the - * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's - * drives are "upside-down"). - */ - -/* - * 1995/8/26 -- Andreas Busse -- added Mips support. - */ - -/* - * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependend - * features to asm/floppy.h. - */ - - -#define FLOPPY_SANITY_CHECK -#undef FLOPPY_SILENT_DCL_CLEAR - -#define REALLY_SLOW_IO - -#define DEBUGT 2 -#define DCL_DEBUG /* debug disk change line */ - -/* do print messages for unexpected interrupts */ -static int print_unex=1; -#include <linux/utsname.h> -#include <linux/module.h> - -/* the following is the mask of allowed drives. By default units 2 and - * 3 of both floppy controllers are disabled, because switching on the - * motor of these drives causes system hangs on some PCI computers. drive - * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if - * a drive is allowed. */ -static int FLOPPY_IRQ=6; -static int FLOPPY_DMA=2; -static int allowed_drive_mask = 0x33; - - -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/tqueue.h> -#define FDPATCHES -#include <linux/fdreg.h> - - -#include <linux/fd.h> - - -#define OLDFDRAWCMD 0x020d /* send a raw command to the fdc */ - -struct old_floppy_raw_cmd { - void *data; - long length; - - unsigned char rate; - unsigned char flags; - unsigned char cmd_count; - unsigned char cmd[9]; - unsigned char reply_count; - unsigned char reply[7]; - int track; -}; - -#include <linux/errno.h> -#include <linux/malloc.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/delay.h> -#include <linux/mc146818rtc.h> /* CMOS defines */ -#include <linux/ioport.h> - -#include <asm/dma.h> -#include <asm/floppy.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/segment.h> - -#define MAJOR_NR FLOPPY_MAJOR - -#include <linux/blk.h> - - -/* Dma Memory related stuff */ - -/* Pure 2^n version of get_order */ -static inline int __get_order (int size) -{ - int order; - -#ifdef _ASM_IO_H2 - __asm__ __volatile__("bsr %1,%0" - : "=r" (order) - : "r" (size / PAGE_SIZE)); -#else - for (order = 0; order < NR_MEM_LISTS; ++order) - if (size <= (PAGE_SIZE << order)) - return order; -#endif - return NR_MEM_LISTS; -} - -static unsigned long dma_mem_alloc(int size) -{ - int order = __get_order(size); - - if (order >= NR_MEM_LISTS) - return(0); - return __get_dma_pages(GFP_KERNEL,order); -} - -/* End dma memory related stuff */ - -static unsigned int fake_change = 0; -static int initialising=1; - -static inline int TYPE(kdev_t x) { - return (MINOR(x)>>2) & 0x1f; -} -static inline int DRIVE(kdev_t x) { - return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5); -} -#define ITYPE(x) (((x)>>2) & 0x1f) -#define TOMINOR(x) ((x & 3) | ((x & 4) << 5)) -#define UNIT(x) ((x) & 0x03) /* drive on fdc */ -#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */ -#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2)) - /* reverse mapping from unit and fdc to drive */ -#define DP (&drive_params[current_drive]) -#define DRS (&drive_state[current_drive]) -#define DRWE (&write_errors[current_drive]) -#define FDCS (&fdc_state[fdc]) -#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags)) -#define SETF(x) (set_bit(x##_BIT, &DRS->flags)) -#define TESTF(x) (test_bit(x##_BIT, &DRS->flags)) - -#define UDP (&drive_params[drive]) -#define UDRS (&drive_state[drive]) -#define UDRWE (&write_errors[drive]) -#define UFDCS (&fdc_state[FDC(drive)]) -#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags)) -#define USETF(x) (set_bit(x##_BIT, &UDRS->flags)) -#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags)) - -#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive) - -#define DPRINT1(x,x1) printk(DEVICE_NAME "%d: " x,current_drive,(x1)) - -#define DPRINT2(x,x1,x2) printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2)) - -#define DPRINT3(x,x1,x2,x3) printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3)) - -#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2) -#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH) - -#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x))) - -/* read/write */ -#define COMMAND raw_cmd->cmd[0] -#define DR_SELECT raw_cmd->cmd[1] -#define TRACK raw_cmd->cmd[2] -#define HEAD raw_cmd->cmd[3] -#define SECTOR raw_cmd->cmd[4] -#define SIZECODE raw_cmd->cmd[5] -#define SECT_PER_TRACK raw_cmd->cmd[6] -#define GAP raw_cmd->cmd[7] -#define SIZECODE2 raw_cmd->cmd[8] -#define NR_RW 9 - -/* format */ -#define F_SIZECODE raw_cmd->cmd[2] -#define F_SECT_PER_TRACK raw_cmd->cmd[3] -#define F_GAP raw_cmd->cmd[4] -#define F_FILL raw_cmd->cmd[5] -#define NR_F 6 - -/* - * Maximum disk size (in kilobytes). This default is used whenever the - * current disk size is unknown. - * [Now it is rather a minimum] - */ -#define MAX_DISK_SIZE 2 /* 3984*/ - -#define K_64 0x10000 /* 64KB */ - -/* - * globals used by 'result()' - */ -#define MAX_REPLIES 17 -static unsigned char reply_buffer[MAX_REPLIES]; -static int inr; /* size of reply buffer, when called from interrupt */ -#define ST0 (reply_buffer[0]) -#define ST1 (reply_buffer[1]) -#define ST2 (reply_buffer[2]) -#define ST3 (reply_buffer[0]) /* result of GETSTATUS */ -#define R_TRACK (reply_buffer[3]) -#define R_HEAD (reply_buffer[4]) -#define R_SECTOR (reply_buffer[5]) -#define R_SIZECODE (reply_buffer[6]) - -#define SEL_DLY (2*HZ/100) - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -/* - * this struct defines the different floppy drive types. - */ -static struct { - struct floppy_drive_params params; - const char *name; /* name printed while booting */ -} default_drive_params[]= { -/* NOTE: the time values in jiffies should be in msec! - CMOS drive type - | Maximum data rate supported by drive type - | | Head load time, msec - | | | Head unload time, msec (not used) - | | | | Step rate interval, usec - | | | | | Time needed for spinup time (jiffies) - | | | | | | Timeout for spinning down (jiffies) - | | | | | | | Spindown offset (where disk stops) - | | | | | | | | Select delay - | | | | | | | | | RPS - | | | | | | | | | | Max number of tracks - | | | | | | | | | | | Interrupt timeout - | | | | | | | | | | | | Max nonintlv. sectors - | | | | | | | | | | | | | -Max Errors- flags */ -{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0, - 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" }, - -{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0, - 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/ - -{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0, - 0, { 2, 5, 6,23,10,20,11, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/ - -{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0, - 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/ - -{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0, - 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/ - -{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0, - 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/ - -{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0, - 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/ -/* | --autodetected formats--- | | | - * read_track | | Name printed when booting - * | Native format - * Frequency of disk change checks */ -}; - -static struct floppy_drive_params drive_params[N_DRIVE]; -static struct floppy_drive_struct drive_state[N_DRIVE]; -static struct floppy_write_errors write_errors[N_DRIVE]; -static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; - -/* - * This struct defines the different floppy types. - * - * Bit 0 of 'stretch' tells if the tracks need to be doubled for some - * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch' - * tells if the disk is in Commodore 1581 format, which means side 0 sectors - * are located on side 1 of the disk but with a side 0 ID, and vice-versa. - * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the - * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical - * side 0 is on physical side 0 (but with the misnamed sector IDs). - * 'stretch' should probably be renamed to something more general, like - * 'options'. Other parameters should be self-explanatory (see also - * setfdprm(8)). - */ -static struct floppy_struct floppy_type[32] = { - { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */ - { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */ - { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */ - { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */ - { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */ - { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */ - { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */ - { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */ - { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */ - { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"CompaQ"}, /* 9 2.88MB 3.5" */ - - { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */ - { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */ - { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */ - { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */ - { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */ - { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */ - { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */ - { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */ - { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */ - { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */ - - { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */ - { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */ - { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */ - { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */ - { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */ - { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */ - { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */ - { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */ - { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */ - - { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */ - { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */ - { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */ -}; - -#define NUMBER(x) (sizeof(x) / sizeof(*(x))) -#define SECTSIZE (_FD_SECTSIZE(*floppy)) - -/* Auto-detection: Disk type used until the next media change occurs. */ -static struct floppy_struct *current_type[N_DRIVE] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -/* - * User-provided type information. current_type points to - * the respective entry of this array. - */ -static struct floppy_struct user_params[N_DRIVE]; - -static int floppy_sizes[256]; -static int floppy_blocksizes[256] = { 0, }; - -/* - * The driver is trying to determine the correct media format - * while probing is set. rw_interrupt() clears it after a - * successful access. - */ -static int probing = 0; - -/* Synchronization of FDC access. */ -#define FD_COMMAND_NONE -1 -#define FD_COMMAND_ERROR 2 -#define FD_COMMAND_OKAY 3 - -static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0; -static struct wait_queue *fdc_wait = NULL, *command_done = NULL; -#ifdef MACH -extern int issig (void); -#define NO_SIGNAL (! issig () || ! interruptible) -#else -#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible) -#endif -#define CALL(x) if ((x) == -EINTR) return -EINTR -#define ECALL(x) if ((ret = (x))) return ret; -#define _WAIT(x,i) CALL(ret=wait_til_done((x),i)) -#define WAIT(x) _WAIT((x),interruptible) -#define IWAIT(x) _WAIT((x),1) - -/* Errors during formatting are counted here. */ -static int format_errors; - -/* Format request descriptor. */ -static struct format_descr format_req; - -/* - * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps - * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), - * H is head unload time (1=16ms, 2=32ms, etc) - */ - -/* - * Track buffer - * Because these are written to by the DMA controller, they must - * not contain a 64k byte boundary crossing, or data will be - * corrupted/lost. Alignment of these is enforced in boot/head.S. - * Note that you must not change the sizes below without updating head.S. - */ -static char *floppy_track_buffer=0; -static int max_buffer_sectors=0; - -static int *errors; -typedef void (*done_f)(int); -static struct cont_t { - void (*interrupt)(void); /* this is called after the interrupt of the - * main command */ - void (*redo)(void); /* this is called to retry the operation */ - void (*error)(void); /* this is called to tally an error */ - done_f done; /* this is called to say if the operation has - * succeeded/failed */ -} *cont=NULL; - -static void floppy_ready(void); -static void floppy_start(void); -static void process_fd_request(void); -static void recalibrate_floppy(void); -static void floppy_shutdown(void); - -static int floppy_grab_irq_and_dma(void); -static void floppy_release_irq_and_dma(void); - -/* - * The "reset" variable should be tested whenever an interrupt is scheduled, - * after the commands have been sent. This is to ensure that the driver doesn't - * get wedged when the interrupt doesn't come because of a failed command. - * reset doesn't need to be tested before sending commands, because - * output_byte is automatically disabled when reset is set. - */ -#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } } -static void reset_fdc(void); - -/* - * These are global variables, as that's the easiest way to give - * information to interrupts. They are the data used for the current - * request. - */ -#define NO_TRACK -1 -#define NEED_1_RECAL -2 -#define NEED_2_RECAL -3 - -/* */ -static int usage_count = 0; - - -/* buffer related variables */ -static int buffer_track = -1; -static int buffer_drive = -1; -static int buffer_min = -1; -static int buffer_max = -1; - -/* fdc related variables, should end up in a struct */ -static struct floppy_fdc_state fdc_state[N_FDC]; -static int fdc; /* current fdc */ - -static struct floppy_struct * floppy = floppy_type; -static unsigned char current_drive = 0; -static long current_count_sectors = 0; -static unsigned char sector_t; /* sector in track */ - -#ifdef DEBUGT -static long unsigned debugtimer; -#endif - -/* - * Debugging - * ========= - */ -static inline void set_debugt(void) -{ -#ifdef DEBUGT - debugtimer = jiffies; -#endif -} - -static inline void debugt(const char *message) -{ -#ifdef DEBUGT - if (DP->flags & DEBUGT) - printk("%s dtime=%lu\n", message, jiffies-debugtimer); -#endif -} - -typedef void (*timeout_fn)(unsigned long); -static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, - (timeout_fn) floppy_shutdown }; - -static const char *timeout_message; - -#ifdef FLOPPY_SANITY_CHECK -static void is_alive(const char *message) -{ - /* this routine checks whether the floppy driver is "alive" */ - if (fdc_busy && command_status < 2 && !fd_timeout.prev){ - DPRINT1("timeout handler died: %s\n",message); - } -} -#endif - -#ifdef FLOPPY_SANITY_CHECK - -#define OLOGSIZE 20 - -static void (*lasthandler)(void) = NULL; -static int interruptjiffies=0; -static int resultjiffies=0; -static int resultsize=0; -static int lastredo=0; - -static struct output_log { - unsigned char data; - unsigned char status; - unsigned long jiffies; -} output_log[OLOGSIZE]; - -static int output_log_pos=0; -#endif - -#define CURRENTD -1 -#define MAXTIMEOUT -2 - -static void reschedule_timeout(int drive, const char *message, int marg) -{ - if (drive == CURRENTD) - drive = current_drive; - del_timer(&fd_timeout); - if (drive < 0 || drive > N_DRIVE) { - fd_timeout.expires = jiffies + 20*HZ; - drive=0; - } else - fd_timeout.expires = jiffies + UDP->timeout; - add_timer(&fd_timeout); - if (UDP->flags & FD_DEBUG){ - DPRINT("reschedule timeout "); - printk(message, marg); - printk("\n"); - } - timeout_message = message; -} - -static int maximum(int a, int b) -{ - if(a > b) - return a; - else - return b; -} -#define INFBOUND(a,b) (a)=maximum((a),(b)); - -static int minimum(int a, int b) -{ - if(a < b) - return a; - else - return b; -} -#define SUPBOUND(a,b) (a)=minimum((a),(b)); - - -/* - * Bottom half floppy driver. - * ========================== - * - * This part of the file contains the code talking directly to the hardware, - * and also the main service loop (seek-configure-spinup-command) - */ - -/* - * disk change. - * This routine is responsible for maintaining the FD_DISK_CHANGE flag, - * and the last_checked date. - * - * last_checked is the date of the last check which showed 'no disk change' - * FD_DISK_CHANGE is set under two conditions: - * 1. The floppy has been changed after some i/o to that floppy already - * took place. - * 2. No floppy disk is in the drive. This is done in order to ensure that - * requests are quickly flushed in case there is no disk in the drive. It - * follows that FD_DISK_CHANGE can only be cleared if there is a disk in - * the drive. - * - * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet. - * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on - * each seek. If a disk is present, the disk change line should also be - * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk - * change line is set, this means either that no disk is in the drive, or - * that it has been removed since the last seek. - * - * This means that we really have a third possibility too: - * The floppy has been changed after the last seek. - */ - -static int disk_change(int drive) -{ - int fdc=FDC(drive); -#ifdef FLOPPY_SANITY_CHECK - if (jiffies < UDP->select_delay + UDRS->select_date) - DPRINT("WARNING disk change called early\n"); - if (!(FDCS->dor & (0x10 << UNIT(drive))) || - (FDCS->dor & 3) != UNIT(drive) || - fdc != FDC(drive)){ - DPRINT("probing disk change on unselected drive\n"); - DPRINT3("drive=%d fdc=%d dor=%x\n",drive, FDC(drive), - FDCS->dor); - } -#endif - -#ifdef DCL_DEBUG - if (UDP->flags & FD_DEBUG){ - DPRINT1("checking disk change line for drive %d\n",drive); - DPRINT1("jiffies=%ld\n", jiffies); - DPRINT1("disk change line=%x\n",fd_inb(FD_DIR)&0x80); - DPRINT1("flags=%x\n",UDRS->flags); - } -#endif - if (UDP->flags & FD_BROKEN_DCL) - return UTESTF(FD_DISK_CHANGED); - if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80){ - USETF(FD_VERIFY); /* verify write protection */ - if (UDRS->maxblock){ - /* mark it changed */ - USETF(FD_DISK_CHANGED); - - /* invalidate its geometry */ - if (UDRS->keep_data >= 0) { - if ((UDP->flags & FTD_MSG) && - current_type[drive] != NULL) - DPRINT("Disk type is undefined after " - "disk change\n"); - current_type[drive] = NULL; - floppy_sizes[TOMINOR(current_drive)] = MAX_DISK_SIZE; - } - } - /*USETF(FD_DISK_NEWCHANGE);*/ - return 1; - } else { - UDRS->last_checked=jiffies; - UCLEARF(FD_DISK_NEWCHANGE); - } - return 0; -} - -static inline int is_selected(int dor, int unit) -{ - return ((dor & (0x10 << unit)) && (dor &3) == unit); -} - -static int set_dor(int fdc, char mask, char data) -{ - register unsigned char drive, unit, newdor,olddor; - - if (FDCS->address == -1) - return -1; - - olddor = FDCS->dor; - newdor = (olddor & mask) | data; - if (newdor != olddor){ - unit = olddor & 0x3; - if (is_selected(olddor, unit) && !is_selected(newdor,unit)){ - drive = REVDRIVE(fdc,unit); -#ifdef DCL_DEBUG - if (UDP->flags & FD_DEBUG){ - DPRINT("calling disk change from set_dor\n"); - } -#endif - disk_change(drive); - } - FDCS->dor = newdor; - fd_outb(newdor, FD_DOR); - - unit = newdor & 0x3; - if (!is_selected(olddor, unit) && is_selected(newdor,unit)){ - drive = REVDRIVE(fdc,unit); - UDRS->select_date = jiffies; - } - } - if (newdor & 0xf0) - floppy_grab_irq_and_dma(); - if (olddor & 0xf0) - floppy_release_irq_and_dma(); - return olddor; -} - -static void twaddle(void) -{ - if (DP->select_delay) - return; - fd_outb(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR); - fd_outb(FDCS->dor, FD_DOR); - DRS->select_date = jiffies; -} - -/* reset all driver information about the current fdc. This is needed after - * a reset, and after a raw command. */ -static void reset_fdc_info(int mode) -{ - int drive; - - FDCS->spec1 = FDCS->spec2 = -1; - FDCS->need_configure = 1; - FDCS->perp_mode = 1; - FDCS->rawcmd = 0; - for (drive = 0; drive < N_DRIVE; drive++) - if (FDC(drive) == fdc && - (mode || UDRS->track != NEED_1_RECAL)) - UDRS->track = NEED_2_RECAL; -} - -/* selects the fdc and drive, and enables the fdc's input/dma. */ -static void set_fdc(int drive) -{ - if (drive >= 0 && drive < N_DRIVE){ - fdc = FDC(drive); - current_drive = drive; - } - if (fdc != 1 && fdc != 0) { - printk("bad fdc value\n"); - return; - } - set_dor(fdc,~0,8); - set_dor(1-fdc, ~8, 0); - if (FDCS->rawcmd == 2) - reset_fdc_info(1); - if (fd_inb(FD_STATUS) != STATUS_READY) - FDCS->reset = 1; -} - -/* locks the driver */ -static int lock_fdc(int drive, int interruptible) -{ - if (!usage_count){ - printk("trying to lock fdc while usage count=0\n"); - return -1; - } - floppy_grab_irq_and_dma(); - cli(); - while (fdc_busy && NO_SIGNAL) - interruptible_sleep_on(&fdc_wait); - if (fdc_busy){ - sti(); - return -EINTR; - } - fdc_busy = 1; - sti(); - command_status = FD_COMMAND_NONE; - reschedule_timeout(drive, "lock fdc", 0); - set_fdc(drive); - return 0; -} - -#define LOCK_FDC(drive,interruptible) \ -if (lock_fdc(drive,interruptible)) return -EINTR; - - -/* unlocks the driver */ -static inline void unlock_fdc(void) -{ - raw_cmd = 0; - if (!fdc_busy) - DPRINT("FDC access conflict!\n"); - - if (DEVICE_INTR) - DPRINT1("device interrupt still active at FDC release: %p!\n", - DEVICE_INTR); - command_status = FD_COMMAND_NONE; - del_timer(&fd_timeout); - cont = NULL; - fdc_busy = 0; - floppy_release_irq_and_dma(); - wake_up(&fdc_wait); -} - -/* switches the motor off after a given timeout */ -static void motor_off_callback(unsigned long nr) -{ - unsigned char mask = ~(0x10 << UNIT(nr)); - - set_dor(FDC(nr), mask, 0); -} - -static struct timer_list motor_off_timer[N_DRIVE] = { - { NULL, NULL, 0, 0, motor_off_callback }, - { NULL, NULL, 0, 1, motor_off_callback }, - { NULL, NULL, 0, 2, motor_off_callback }, - { NULL, NULL, 0, 3, motor_off_callback }, - { NULL, NULL, 0, 4, motor_off_callback }, - { NULL, NULL, 0, 5, motor_off_callback }, - { NULL, NULL, 0, 6, motor_off_callback }, - { NULL, NULL, 0, 7, motor_off_callback } -}; - -/* schedules motor off */ -static void floppy_off(unsigned int drive) -{ - unsigned long volatile delta; - register int fdc=FDC(drive); - - if (!(FDCS->dor & (0x10 << UNIT(drive)))) - return; - - del_timer(motor_off_timer+drive); - - /* make spindle stop in a position which minimizes spinup time - * next time */ - if (UDP->rps){ - delta = jiffies - UDRS->first_read_date + HZ - - UDP->spindown_offset; - delta = ((delta * UDP->rps) % HZ) / UDP->rps; - motor_off_timer[drive].expires = jiffies + UDP->spindown - delta; - } - add_timer(motor_off_timer+drive); -} - -/* - * cycle through all N_DRIVE floppy drives, for disk change testing. - * stopping at current drive. This is done before any long operation, to - * be sure to have up to date disk change information. - */ -static void scandrives(void) -{ - int i, drive, saved_drive; - - if (DP->select_delay) - return; - - saved_drive = current_drive; - for (i=0; i < N_DRIVE; i++){ - drive = (saved_drive + i + 1) % N_DRIVE; - if (UDRS->fd_ref == 0 || UDP->select_delay != 0) - continue; /* skip closed drives */ - set_fdc(drive); - if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) & - (0x10 << UNIT(drive)))) - /* switch the motor off again, if it was off to - * begin with */ - set_dor(fdc, ~(0x10 << UNIT(drive)), 0); - } - set_fdc(saved_drive); -} - -static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 }; - -/* this function makes sure that the disk stays in the drive during the - * transfer */ -static void fd_watchdog(void) -{ -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("calling disk change from watchdog\n"); - } -#endif - - if (disk_change(current_drive)){ - DPRINT("disk removed during i/o\n"); - floppy_shutdown(); - } else { - del_timer(&fd_timer); - fd_timer.function = (timeout_fn) fd_watchdog; - fd_timer.expires = jiffies + HZ / 10; - add_timer(&fd_timer); - } -} - -static void main_command_interrupt(void) -{ - del_timer(&fd_timer); - cont->interrupt(); -} - -/* waits for a delay (spinup or select) to pass */ -static int wait_for_completion(int delay, timeout_fn function) -{ - if (FDCS->reset){ - reset_fdc(); /* do the reset during sleep to win time - * if we don't need to sleep, it's a good - * occasion anyways */ - return 1; - } - - if (jiffies < delay){ - del_timer(&fd_timer); - fd_timer.function = function; - fd_timer.expires = delay; - add_timer(&fd_timer); - return 1; - } - return 0; -} - -static int hlt_disabled=0; -static void floppy_disable_hlt(void) -{ - unsigned long flags; - save_flags(flags); - cli(); - if (!hlt_disabled){ - hlt_disabled=1; -#ifdef HAVE_DISABLE_HLT - disable_hlt(); -#endif - } - restore_flags(flags); -} - -static void floppy_enable_hlt(void) -{ - unsigned long flags; - save_flags(flags); - cli(); - if (hlt_disabled){ - hlt_disabled=0; -#ifdef HAVE_DISABLE_HLT - enable_hlt(); -#endif - } - restore_flags(flags); -} - - -static void setup_DMA(void) -{ -#ifdef FLOPPY_SANITY_CHECK - if (raw_cmd->length == 0){ - int i; - - printk("zero dma transfer size:"); - for (i=0; i < raw_cmd->cmd_count; i++) - printk("%x,", raw_cmd->cmd[i]); - printk("\n"); - cont->done(0); - FDCS->reset = 1; - return; - } - if ((long) raw_cmd->kernel_data % 512){ - printk("non aligned address: %p\n", raw_cmd->kernel_data); - cont->done(0); - FDCS->reset=1; - return; - } - if (CROSS_64KB(raw_cmd->kernel_data, raw_cmd->length)) { - printk("DMA crossing 64-K boundary %p-%p\n", - raw_cmd->kernel_data, - raw_cmd->kernel_data + raw_cmd->length); - cont->done(0); - FDCS->reset=1; - return; - } -#endif - cli(); - fd_disable_dma(); - fd_clear_dma_ff(); - fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)? - DMA_MODE_READ : DMA_MODE_WRITE); - fd_set_dma_addr(virt_to_bus(raw_cmd->kernel_data)); - fd_set_dma_count(raw_cmd->length); - fd_enable_dma(); - sti(); - floppy_disable_hlt(); -} - -/* sends a command byte to the fdc */ -static int output_byte(char byte) -{ - int counter; - unsigned char status = 0; - unsigned char rstatus; - - if (FDCS->reset) - return -1; - for (counter = 0; counter < 10000 && !FDCS->reset; counter++) { - rstatus = fd_inb(FD_STATUS); - status = rstatus &(STATUS_READY|STATUS_DIR|STATUS_DMA); - if (!(status & STATUS_READY)) - continue; - if (status == STATUS_READY){ - fd_outb(byte,FD_DATA); - -#ifdef FLOPPY_SANITY_CHECK - output_log[output_log_pos].data = byte; - output_log[output_log_pos].status = rstatus; - output_log[output_log_pos].jiffies = jiffies; - output_log_pos = (output_log_pos + 1) % OLOGSIZE; -#endif - return 0; - } else - break; - } - FDCS->reset = 1; - if (!initialising) - DPRINT2("Unable to send byte %x to FDC. Status=%x\n", - byte, status); - return -1; -} -#define LAST_OUT(x) if (output_byte(x)){ reset_fdc();return;} - -/* gets the response from the fdc */ -static int result(void) -{ - int i = 0, counter, status = 0; - - if (FDCS->reset) - return -1; - for (counter = 0; counter < 10000 && !FDCS->reset; counter++) { - status = fd_inb(FD_STATUS)& - (STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA); - if (!(status & STATUS_READY)) - continue; - if (status == STATUS_READY){ -#ifdef FLOPPY_SANITY_CHECK - resultjiffies = jiffies; - resultsize = i; -#endif - return i; - } - if (status & STATUS_DMA) - break; - if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { - if (i >= MAX_REPLIES) { - DPRINT("floppy_stat reply overrun\n"); - break; - } - reply_buffer[i++] = fd_inb(FD_DATA); - } - } - FDCS->reset = 1; - if (!initialising) - DPRINT3("Getstatus times out (%x) on fdc %d [%d]\n", - status, fdc, i); - return -1; -} - -/* Set perpendicular mode as required, based on data rate, if supported. - * 82077 Now tested. 1Mbps data rate only possible with 82077-1. - */ -static inline void perpendicular_mode(void) -{ - unsigned char perp_mode; - - if (raw_cmd->rate & 0x40){ - switch(raw_cmd->rate & 3){ - case 0: - perp_mode=2; - break; - case 3: - perp_mode=3; - break; - default: - DPRINT("Invalid data rate for perpendicular mode!\n"); - cont->done(0); - FDCS->reset = 1; /* convenient way to return to - * redo without to much hassle (deep - * stack et al. */ - return; - } - } else - perp_mode = 0; - - if (FDCS->perp_mode == perp_mode) - return; - if (FDCS->version >= FDC_82077_ORIG && FDCS->has_fifo) { - output_byte(FD_PERPENDICULAR); - output_byte(perp_mode); - FDCS->perp_mode = perp_mode; - } else if (perp_mode) { - DPRINT("perpendicular mode not supported by this FDC.\n"); - } -} /* perpendicular_mode */ - -#define NOMINAL_DTR 500 - -/* Issue a "SPECIFY" command to set the step rate time, head unload time, - * head load time, and DMA disable flag to values needed by floppy. - * - * The value "dtr" is the data transfer rate in Kbps. It is needed - * to account for the data rate-based scaling done by the 82072 and 82077 - * FDC types. This parameter is ignored for other types of FDCs (i.e. - * 8272a). - * - * Note that changing the data transfer rate has a (probably deleterious) - * effect on the parameters subject to scaling for 82072/82077 FDCs, so - * fdc_specify is called again after each data transfer rate - * change. - * - * srt: 1000 to 16000 in microseconds - * hut: 16 to 240 milliseconds - * hlt: 2 to 254 milliseconds - * - * These values are rounded up to the next highest available delay time. - */ -static void fdc_specify(void) -{ - unsigned char spec1, spec2; - int srt, hlt, hut; - unsigned long dtr = NOMINAL_DTR; - unsigned long scale_dtr = NOMINAL_DTR; - int hlt_max_code = 0x7f; - int hut_max_code = 0xf; - - if (FDCS->need_configure && FDCS->has_fifo) { - if (FDCS->reset) - return; - /* Turn on FIFO for 82077-class FDC (improves performance) */ - /* TODO: lock this in via LOCK during initialization */ - output_byte(FD_CONFIGURE); - output_byte(0); - output_byte(0x2A); /* FIFO on, polling off, 10 byte threshold */ - output_byte(0); /* precompensation from track 0 upwards */ - if (FDCS->reset){ - FDCS->has_fifo=0; - return; - } - FDCS->need_configure = 0; - /*DPRINT("FIFO enabled\n");*/ - } - - switch (raw_cmd->rate & 0x03) { - case 3: - dtr = 1000; - break; - case 1: - dtr = 300; - break; - case 2: - dtr = 250; - break; - } - - if (FDCS->version >= FDC_82072) { - scale_dtr = dtr; - hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */ - hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */ - } - - /* Convert step rate from microseconds to milliseconds and 4 bits */ - srt = 16 - (DP->srt*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR; - SUPBOUND(srt, 0xf); - INFBOUND(srt, 0); - - hlt = (DP->hlt*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR; - if (hlt < 0x01) - hlt = 0x01; - else if (hlt > 0x7f) - hlt = hlt_max_code; - - hut = (DP->hut*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR; - if (hut < 0x1) - hut = 0x1; - else if (hut > 0xf) - hut = hut_max_code; - - spec1 = (srt << 4) | hut; - spec2 = (hlt << 1); - - /* If these parameters did not change, just return with success */ - if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) { - /* Go ahead and set spec1 and spec2 */ - output_byte(FD_SPECIFY); - output_byte(FDCS->spec1 = spec1); - output_byte(FDCS->spec2 = spec2); - } -} /* fdc_specify */ - -/* Set the FDC's data transfer rate on behalf of the specified drive. - * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue - * of the specify command (i.e. using the fdc_specify function). - */ -static int fdc_dtr(void) -{ - /* If data rate not already set to desired value, set it. */ - if ((raw_cmd->rate & 3) == FDCS->dtr) - return 0; - - /* Set dtr */ - fd_outb(raw_cmd->rate & 3, FD_DCR); - - /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB) - * need a stabilization period of several milliseconds to be - * enforced after data rate changes before R/W operations. - * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) - */ - FDCS->dtr = raw_cmd->rate & 3; - return(wait_for_completion(jiffies+2*HZ/100, - (timeout_fn) floppy_ready)); -} /* fdc_dtr */ - -static void tell_sector(void) -{ - printk(": track %d, head %d, sector %d, size %d", - R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE); -} /* tell_sector */ - - -/* - * Ok, this error interpreting routine is called after a - * DMA read/write has succeeded - * or failed, so we check the results, and copy any buffers. - * hhb: Added better error reporting. - * ak: Made this into a separate routine. - */ -static int interpret_errors(void) -{ - char bad; - - if (inr!=7) { - DPRINT("-- FDC reply error"); - FDCS->reset = 1; - return 1; - } - - /* check IC to find cause of interrupt */ - switch (ST0 & ST0_INTR) { - case 0x40: /* error occurred during command execution */ - bad = 1; - if (ST1 & ST1_WP) { - DPRINT("Drive is write protected\n"); - CLEARF(FD_DISK_WRITABLE); - cont->done(0); - bad = 2; - } else if (ST1 & ST1_ND) { - SETF(FD_NEED_TWADDLE); - } else if (ST1 & ST1_OR) { - if (DP->flags & FTD_MSG) - DPRINT("Over/Underrun - retrying\n"); - bad = 0; - }else if (*errors >= DP->max_errors.reporting){ - DPRINT(""); - if (ST0 & ST0_ECE) { - printk("Recalibrate failed!"); - } else if (ST2 & ST2_CRC) { - printk("data CRC error"); - tell_sector(); - } else if (ST1 & ST1_CRC) { - printk("CRC error"); - tell_sector(); - } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) { - if (!probing) { - printk("sector not found"); - tell_sector(); - } else - printk("probe failed..."); - } else if (ST2 & ST2_WC) { /* seek error */ - printk("wrong cylinder"); - } else if (ST2 & ST2_BC) { /* cylinder marked as bad */ - printk("bad cylinder"); - } else { - printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2); - tell_sector(); - } - printk("\n"); - - } - if (ST2 & ST2_WC || ST2 & ST2_BC) - /* wrong cylinder => recal */ - DRS->track = NEED_2_RECAL; - return bad; - case 0x80: /* invalid command given */ - DPRINT("Invalid FDC command given!\n"); - cont->done(0); - return 2; - case 0xc0: - DPRINT("Abnormal termination caused by polling\n"); - cont->error(); - return 2; - default: /* (0) Normal command termination */ - return 0; - } -} - -/* - * This routine is called when everything should be correctly set up - * for the transfer (ie floppy motor is on, the correct floppy is - * selected, and the head is sitting on the right track). - */ -static void setup_rw_floppy(void) -{ - int i,ready_date,r, flags,dflags; - timeout_fn function; - - flags = raw_cmd->flags; - if (flags & (FD_RAW_READ | FD_RAW_WRITE)) - flags |= FD_RAW_INTR; - - if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){ - ready_date = DRS->spinup_date + DP->spinup; - /* If spinup will take a long time, rerun scandrives - * again just before spinup completion. Beware that - * after scandrives, we must again wait for selection. - */ - if (ready_date > jiffies + DP->select_delay){ - ready_date -= DP->select_delay; - function = (timeout_fn) floppy_start; - } else - function = (timeout_fn) setup_rw_floppy; - - /* wait until the floppy is spinning fast enough */ - if (wait_for_completion(ready_date,function)) - return; - } - dflags = DRS->flags; - - if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE)) - setup_DMA(); - - if (flags & FD_RAW_INTR) - SET_INTR(main_command_interrupt); - - r=0; - for (i=0; i< raw_cmd->cmd_count; i++) - r|=output_byte(raw_cmd->cmd[i]); - -#ifdef DEBUGT - debugt("rw_command: "); -#endif - if (r){ - reset_fdc(); - return; - } - - if (!(flags & FD_RAW_INTR)){ - inr = result(); - cont->interrupt(); - } else if (flags & FD_RAW_NEED_DISK) - fd_watchdog(); -} - -static int blind_seek; - -/* - * This is the routine called after every seek (or recalibrate) interrupt - * from the floppy controller. - */ -static void seek_interrupt(void) -{ -#ifdef DEBUGT - debugt("seek interrupt:"); -#endif - if (inr != 2 || (ST0 & 0xF8) != 0x20) { - DPRINT("seek failed\n"); - DRS->track = NEED_2_RECAL; - cont->error(); - cont->redo(); - return; - } - if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){ -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("clearing NEWCHANGE flag because of effective seek\n"); - DPRINT1("jiffies=%ld\n", jiffies); - } -#endif - CLEARF(FD_DISK_NEWCHANGE); /* effective seek */ - DRS->select_date = jiffies; - } - DRS->track = ST1; - floppy_ready(); -} - -static void check_wp(void) -{ - if (TESTF(FD_VERIFY)) { - /* check write protection */ - output_byte(FD_GETSTATUS); - output_byte(UNIT(current_drive)); - if (result() != 1){ - FDCS->reset = 1; - return; - } - CLEARF(FD_VERIFY); - CLEARF(FD_NEED_TWADDLE); -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("checking whether disk is write protected\n"); - DPRINT1("wp=%x\n",ST3 & 0x40); - } -#endif - if (!(ST3 & 0x40)) - SETF(FD_DISK_WRITABLE); - else - CLEARF(FD_DISK_WRITABLE); - } -} - -static void seek_floppy(void) -{ - int track; - - blind_seek=0; - -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("calling disk change from seek\n"); - } -#endif - - if (!TESTF(FD_DISK_NEWCHANGE) && - disk_change(current_drive) && - (raw_cmd->flags & FD_RAW_NEED_DISK)){ - /* the media changed flag should be cleared after the seek. - * If it isn't, this means that there is really no disk in - * the drive. - */ - SETF(FD_DISK_CHANGED); - cont->done(0); - cont->redo(); - return; - } - if (DRS->track <= NEED_1_RECAL){ - recalibrate_floppy(); - return; - } else if (TESTF(FD_DISK_NEWCHANGE) && - (raw_cmd->flags & FD_RAW_NEED_DISK) && - (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) { - /* we seek to clear the media-changed condition. Does anybody - * know a more elegant way, which works on all drives? */ - if (raw_cmd->track) - track = raw_cmd->track - 1; - else { - if (DP->flags & FD_SILENT_DCL_CLEAR){ - set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0); - blind_seek = 1; - raw_cmd->flags |= FD_RAW_NEED_SEEK; - } - track = 1; - } - } else { - check_wp(); - if (raw_cmd->track != DRS->track && - (raw_cmd->flags & FD_RAW_NEED_SEEK)) - track = raw_cmd->track; - else { - setup_rw_floppy(); - return; - } - } - - SET_INTR(seek_interrupt); - output_byte(FD_SEEK); - output_byte(UNIT(current_drive)); - LAST_OUT(track); -#ifdef DEBUGT - debugt("seek command:"); -#endif -} - -static void recal_interrupt(void) -{ -#ifdef DEBUGT - debugt("recal interrupt:"); -#endif - if (inr !=2) - FDCS->reset = 1; - else if (ST0 & ST0_ECE) { - switch(DRS->track){ - case NEED_1_RECAL: -#ifdef DEBUGT - debugt("recal interrupt need 1 recal:"); -#endif - /* after a second recalibrate, we still haven't - * reached track 0. Probably no drive. Raise an - * error, as failing immediately might upset - * computers possessed by the Devil :-) */ - cont->error(); - cont->redo(); - return; - case NEED_2_RECAL: -#ifdef DEBUGT - debugt("recal interrupt need 2 recal:"); -#endif - /* If we already did a recalibrate, - * and we are not at track 0, this - * means we have moved. (The only way - * not to move at recalibration is to - * be already at track 0.) Clear the - * new change flag */ -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("clearing NEWCHANGE flag because of second recalibrate\n"); - } -#endif - - CLEARF(FD_DISK_NEWCHANGE); - DRS->select_date = jiffies; - /* fall through */ - default: -#ifdef DEBUGT - debugt("recal interrupt default:"); -#endif - /* Recalibrate moves the head by at - * most 80 steps. If after one - * recalibrate we don't have reached - * track 0, this might mean that we - * started beyond track 80. Try - * again. */ - DRS->track = NEED_1_RECAL; - break; - } - } else - DRS->track = ST1; - floppy_ready(); -} - -/* - * Unexpected interrupt - Print as much debugging info as we can... - * All bets are off... - */ -static void unexpected_floppy_interrupt(void) -{ - int i; - if (initialising) - return; - if (print_unex){ - DPRINT("unexpected interrupt\n"); - if (inr >= 0) - for (i=0; i<inr; i++) - printk("%d %x\n", i, reply_buffer[i]); - } - while(1){ - output_byte(FD_SENSEI); - inr=result(); - if (inr != 2) - break; - if (print_unex){ - printk("sensei\n"); - for (i=0; i<inr; i++) - printk("%d %x\n", i, reply_buffer[i]); - } - } - FDCS->reset = 1; -} - -static struct tq_struct floppy_tq = -{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 }; - -/* interrupt handler */ -static void floppy_interrupt(int irq, struct pt_regs * regs) -{ - void (*handler)(void) = DEVICE_INTR; - - lasthandler = handler; - interruptjiffies = jiffies; - - floppy_enable_hlt(); - CLEAR_INTR; - if (fdc >= N_FDC || FDCS->address == -1){ - /* we don't even know which FDC is the culprit */ - printk("DOR0=%x\n", fdc_state[0].dor); - printk("floppy interrupt on bizarre fdc %d\n",fdc); - printk("handler=%p\n", handler); - is_alive("bizarre fdc"); - return; - } - inr = result(); - if (!handler){ - unexpected_floppy_interrupt(); - is_alive("unexpected"); - return; - } - if (inr == 0){ - do { - output_byte(FD_SENSEI); - inr = result(); - } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2); - } - floppy_tq.routine = (void *)(void *) handler; - queue_task_irq(&floppy_tq, &tq_timer); - is_alive("normal interrupt end"); -} - -static void recalibrate_floppy(void) -{ -#ifdef DEBUGT - debugt("recalibrate floppy:"); -#endif - SET_INTR(recal_interrupt); - output_byte(FD_RECALIBRATE); - LAST_OUT(UNIT(current_drive)); -} - -/* - * Must do 4 FD_SENSEIs after reset because of ``drive polling''. - */ -static void reset_interrupt(void) -{ -#ifdef DEBUGT - debugt("reset interrupt:"); -#endif - /* fdc_specify(); reprogram fdc */ - result(); /* get the status ready for set_fdc */ - if (FDCS->reset) { - printk("reset set in interrupt, calling %p\n", cont->error); - cont->error(); /* a reset just after a reset. BAD! */ - } - cont->redo(); -} - -/* - * reset is done by pulling bit 2 of DOR low for a while (old FDC's), - * or by setting the self clearing bit 7 of STATUS (newer FDC's) - */ -static void reset_fdc(void) -{ - SET_INTR(reset_interrupt); - FDCS->reset = 0; - reset_fdc_info(0); - if (FDCS->version >= FDC_82077) - fd_outb(0x80 | (FDCS->dtr &3), FD_STATUS); - else { - fd_outb(FDCS->dor & ~0x04, FD_DOR); - udelay(FD_RESET_DELAY); - outb(FDCS->dor, FD_DOR); - } -} - -static void empty(void) -{ -} - -void show_floppy(void) -{ - int i; - - printk("\n"); - printk("floppy driver state\n"); - printk("-------------------\n"); - printk("now=%ld last interrupt=%d last called handler=%p\n", - jiffies, interruptjiffies, lasthandler); - - -#ifdef FLOPPY_SANITY_CHECK - printk("timeout_message=%s\n", timeout_message); - printk("last output bytes:\n"); - for (i=0; i < OLOGSIZE; i++) - printk("%2x %2x %ld\n", - output_log[(i+output_log_pos) % OLOGSIZE].data, - output_log[(i+output_log_pos) % OLOGSIZE].status, - output_log[(i+output_log_pos) % OLOGSIZE].jiffies); - printk("last result at %d\n", resultjiffies); - printk("last redo_fd_request at %d\n", lastredo); - for (i=0; i<resultsize; i++){ - printk("%2x ", reply_buffer[i]); - } - printk("\n"); -#endif - - printk("status=%x\n", fd_inb(FD_STATUS)); - printk("fdc_busy=%d\n", fdc_busy); - if (DEVICE_INTR) - printk("DEVICE_INTR=%p\n", DEVICE_INTR); - if (floppy_tq.sync) - printk("floppy_tq.routine=%p\n", floppy_tq.routine); - if (fd_timer.prev) - printk("fd_timer.function=%p\n", fd_timer.function); - if (fd_timeout.prev){ - printk("timer_table=%p\n",fd_timeout.function); - printk("expires=%ld\n",fd_timeout.expires-jiffies); - printk("now=%ld\n",jiffies); - } - printk("cont=%p\n", cont); - printk("CURRENT=%p\n", CURRENT); - printk("command_status=%d\n", command_status); - printk("\n"); -} - -static void floppy_shutdown(void) -{ - if (!initialising) - show_floppy(); - CLEAR_INTR; - floppy_tq.routine = (void *)(void *) empty; - del_timer(&fd_timer); - sti(); - - floppy_enable_hlt(); - fd_disable_dma(); - /* avoid dma going to a random drive after shutdown */ - - if (!initialising) - DPRINT("floppy timeout\n"); - FDCS->reset = 1; - if (cont){ - cont->done(0); - cont->redo(); /* this will recall reset when needed */ - } else { - printk("no cont in shutdown!\n"); - process_fd_request(); - } - is_alive("floppy shutdown"); -} -/*typedef void (*timeout_fn)(unsigned long);*/ - -/* start motor, check media-changed condition and write protection */ -static int start_motor(void (*function)(void) ) -{ - int mask, data; - - mask = 0xfc; - data = UNIT(current_drive); - if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)){ - if (!(FDCS->dor & (0x10 << UNIT(current_drive)))){ - set_debugt(); - /* no read since this drive is running */ - DRS->first_read_date = 0; - /* note motor start time if motor is not yet running */ - DRS->spinup_date = jiffies; - data |= (0x10 << UNIT(current_drive)); - } - } else - if (FDCS->dor & (0x10 << UNIT(current_drive))) - mask &= ~(0x10 << UNIT(current_drive)); - - /* starts motor and selects floppy */ - del_timer(motor_off_timer + current_drive); - set_dor(fdc, mask, data); - - /* wait_for_completion also schedules reset if needed. */ - return(wait_for_completion(DRS->select_date+DP->select_delay, - (timeout_fn) function)); -} - -static void floppy_ready(void) -{ - CHECK_RESET; - if (start_motor(floppy_ready)) return; - if (fdc_dtr()) return; - -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("calling disk change from floppy_ready\n"); - } -#endif - - if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) && - disk_change(current_drive) && - !DP->select_delay) - twaddle(); /* this clears the dcl on certain drive/controller - * combinations */ - - if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){ - perpendicular_mode(); - fdc_specify(); /* must be done here because of hut, hlt ... */ - seek_floppy(); - } else - setup_rw_floppy(); -} - -static void floppy_start(void) -{ - reschedule_timeout(CURRENTD, "floppy start", 0); - - scandrives(); -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("setting NEWCHANGE in floppy_start\n"); - } -#endif - SETF(FD_DISK_NEWCHANGE); - floppy_ready(); -} - -/* - * ======================================================================== - * here ends the bottom half. Exported routines are: - * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc, - * start_motor, reset_fdc, reset_fdc_info, interpret_errors. - * Initialisation also uses output_byte, result, set_dor, floppy_interrupt - * and set_dor. - * ======================================================================== - */ -/* - * General purpose continuations. - * ============================== - */ - -static void do_wakeup(void) -{ - reschedule_timeout(MAXTIMEOUT, "do wakeup", 0); - cont = 0; - command_status += 2; - wake_up(&command_done); -} - -static struct cont_t wakeup_cont={ - empty, - do_wakeup, - empty, - (done_f)empty -}; - -static int wait_til_done(void (*handler)(void), int interruptible) -{ - int ret; - - floppy_tq.routine = (void *)(void *) handler; - queue_task(&floppy_tq, &tq_timer); - - cli(); - while(command_status < 2 && NO_SIGNAL){ - is_alive("wait_til_done"); - if (interruptible) - interruptible_sleep_on(&command_done); - else - sleep_on(&command_done); - } - if (command_status < 2){ - floppy_shutdown(); - sti(); - process_fd_request(); - return -EINTR; - } - sti(); - - if (FDCS->reset) - command_status = FD_COMMAND_ERROR; - if (command_status == FD_COMMAND_OKAY) - ret=0; - else - ret=-EIO; - command_status = FD_COMMAND_NONE; - return ret; -} - -static void generic_done(int result) -{ - command_status = result; - cont = &wakeup_cont; -} - -static void generic_success(void) -{ - cont->done(1); -} - -static void generic_failure(void) -{ - cont->done(0); -} - -static void success_and_wakeup(void) -{ - generic_success(); - cont->redo(); -} - - -/* - * formatting and rw support. - * ========================== - */ - -static int next_valid_format(void) -{ - int probed_format; - - probed_format = DRS->probed_format; - while(1){ - if (probed_format >= 8 || - !DP->autodetect[probed_format]){ - DRS->probed_format = 0; - return 1; - } - if (floppy_type[DP->autodetect[probed_format]].sect){ - DRS->probed_format = probed_format; - return 0; - } - probed_format++; - } -} - -static void bad_flp_intr(void) -{ - if (probing){ - DRS->probed_format++; - if (!next_valid_format()) - return; - } - (*errors)++; - INFBOUND(DRWE->badness, *errors); - if (*errors > DP->max_errors.abort) - cont->done(0); - if (*errors > DP->max_errors.reset) - FDCS->reset = 1; - else if (*errors > DP->max_errors.recal) - DRS->track = NEED_2_RECAL; -} - -static void set_floppy(kdev_t device) -{ - if (TYPE(device)) - floppy = TYPE(device) + floppy_type; - else - floppy = current_type[ DRIVE(device) ]; -} - -/* - * formatting and support. - * ======================= - */ -static void format_interrupt(void) -{ - switch (interpret_errors()){ - case 1: - cont->error(); - case 2: - break; - case 0: - cont->done(1); - } - cont->redo(); -} - -#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2) -#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1)) -#define CT(x) ((x) | 0x40) -static void setup_format_params(int track) -{ - struct fparm { - unsigned char track,head,sect,size; - } *here = (struct fparm *)floppy_track_buffer; - int il,n; - int count,head_shift,track_shift; - - raw_cmd = &default_raw_cmd; - raw_cmd->track = track; - - raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN | - /*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK; - raw_cmd->rate = floppy->rate & 0x43; - raw_cmd->cmd_count = NR_F; - COMMAND = FM_MODE(floppy,FD_FORMAT); - DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,format_req.head); - F_SIZECODE = FD_SIZECODE(floppy); - F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE; - F_GAP = floppy->fmt_gap; - F_FILL = FD_FILL_BYTE; - - raw_cmd->kernel_data = floppy_track_buffer; - raw_cmd->length = 4 * F_SECT_PER_TRACK; - - /* allow for about 30ms for data transport per track */ - head_shift = (F_SECT_PER_TRACK + 5) / 6; - - /* a ``cylinder'' is two tracks plus a little stepping time */ - track_shift = 2 * head_shift + 3; - - /* position of logical sector 1 on this track */ - n = (track_shift * format_req.track + head_shift * format_req.head) - % F_SECT_PER_TRACK; - - /* determine interleave */ - il = 1; - if (floppy->sect > DP->interleave_sect && F_SIZECODE == 2) - il++; - - /* initialize field */ - for (count = 0; count < F_SECT_PER_TRACK; ++count) { - here[count].track = format_req.track; - here[count].head = format_req.head; - here[count].sect = 0; - here[count].size = F_SIZECODE; - } - /* place logical sectors */ - for (count = 1; count <= F_SECT_PER_TRACK; ++count) { - here[n].sect = count; - n = (n+il) % F_SECT_PER_TRACK; - if (here[n].sect) { /* sector busy, find next free sector */ - ++n; - if (n>= F_SECT_PER_TRACK) { - n-=F_SECT_PER_TRACK; - while (here[n].sect) ++n; - } - } - } -} - -static void redo_format(void) -{ - buffer_track = -1; - setup_format_params(format_req.track << STRETCH(floppy)); - floppy_start(); -#ifdef DEBUGT - debugt("queue format request"); -#endif -} - -static struct cont_t format_cont={ - format_interrupt, - redo_format, - bad_flp_intr, - generic_done }; - -static int do_format(kdev_t device, struct format_descr *tmp_format_req) -{ - int ret; - int drive=DRIVE(device); - - LOCK_FDC(drive,1); - set_floppy(device); - if (!floppy || - floppy->track > DP->tracks || - tmp_format_req->track >= floppy->track || - tmp_format_req->head >= floppy->head || - (floppy->sect << 2) % (1 << FD_SIZECODE(floppy)) || - !floppy->fmt_gap) { - process_fd_request(); - return -EINVAL; - } - format_req = *tmp_format_req; - format_errors = 0; - cont = &format_cont; - errors = &format_errors; - IWAIT(redo_format); - process_fd_request(); - return ret; -} - -/* - * Buffer read/write and support - * ============================= - */ - -/* new request_done. Can handle physical sectors which are smaller than a - * logical buffer */ -static void request_done(int uptodate) -{ - int block; - - probing = 0; - reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate); - - if (!CURRENT){ - DPRINT("request list destroyed in floppy request done\n"); - return; - } - if (uptodate){ - /* maintain values for invalidation on geometry - * change */ - block = current_count_sectors + CURRENT->sector; - INFBOUND(DRS->maxblock, block); - if (block > floppy->sect) - DRS->maxtrack = 1; - - /* unlock chained buffers */ - while (current_count_sectors && CURRENT && - current_count_sectors >= CURRENT->current_nr_sectors){ - current_count_sectors -= CURRENT->current_nr_sectors; - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; - end_request(1); - } - if (current_count_sectors && CURRENT){ - /* "unlock" last subsector */ - CURRENT->buffer += current_count_sectors <<9; - CURRENT->current_nr_sectors -= current_count_sectors; - CURRENT->nr_sectors -= current_count_sectors; - CURRENT->sector += current_count_sectors; - return; - } - - if (current_count_sectors && !CURRENT) - DPRINT("request list destroyed in floppy request done\n"); - - } else { - if (CURRENT->cmd == WRITE) { - /* record write error information */ - DRWE->write_errors++; - if (DRWE->write_errors == 1) { - DRWE->first_error_sector = CURRENT->sector; - DRWE->first_error_generation = DRS->generation; - } - DRWE->last_error_sector = CURRENT->sector; - DRWE->last_error_generation = DRS->generation; - } - end_request(0); - } -} - -/* Interrupt handler evaluating the result of the r/w operation */ -static void rw_interrupt(void) -{ - int nr_sectors, ssize; - - if (!DRS->first_read_date) - DRS->first_read_date = jiffies; - - nr_sectors = 0; - CODE2SIZE; - nr_sectors = ((R_TRACK-TRACK)*floppy->head+R_HEAD-HEAD) * - floppy->sect + ((R_SECTOR-SECTOR) << SIZECODE >> 2) - - (sector_t % floppy->sect) % ssize; - -#ifdef FLOPPY_SANITY_CHECK - if (nr_sectors > current_count_sectors + ssize - - (current_count_sectors + sector_t) % ssize + - sector_t % ssize){ - DPRINT2("long rw: %x instead of %lx\n", - nr_sectors, current_count_sectors); - printk("rs=%d s=%d\n", R_SECTOR, SECTOR); - printk("rh=%d h=%d\n", R_HEAD, HEAD); - printk("rt=%d t=%d\n", R_TRACK, TRACK); - printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, - sector_t, ssize); - } -#endif - INFBOUND(nr_sectors,0); - SUPBOUND(current_count_sectors, nr_sectors); - - switch (interpret_errors()){ - case 2: - cont->redo(); - return; - case 1: - if (!current_count_sectors){ - cont->error(); - cont->redo(); - return; - } - break; - case 0: - if (!current_count_sectors){ - cont->redo(); - return; - } - current_type[current_drive] = floppy; - floppy_sizes[TOMINOR(current_drive) ]= floppy->size>>1; - break; - } - - if (probing) { - if (DP->flags & FTD_MSG) - DPRINT2("Auto-detected floppy type %s in fd%d\n", - floppy->name,current_drive); - current_type[current_drive] = floppy; - floppy_sizes[TOMINOR(current_drive)] = floppy->size >> 1; - probing = 0; - } - - if (CT(COMMAND) != FD_READ || - raw_cmd->kernel_data == CURRENT->buffer){ - /* transfer directly from buffer */ - cont->done(1); - } else if (CT(COMMAND) == FD_READ){ - buffer_track = raw_cmd->track; - buffer_drive = current_drive; - INFBOUND(buffer_max, nr_sectors + sector_t); - } - cont->redo(); -} - -/* Compute maximal contiguous buffer size. */ -static int buffer_chain_size(void) -{ - struct buffer_head *bh; - int size; - char *base; - - base = CURRENT->buffer; - size = CURRENT->current_nr_sectors << 9; - bh = CURRENT->bh; - - if (bh){ - bh = bh->b_reqnext; - while (bh && bh->b_data == base + size){ - size += bh->b_size; - bh = bh->b_reqnext; - } - } - return size >> 9; -} - -/* Compute the maximal transfer size */ -static int transfer_size(int ssize, int max_sector, int max_size) -{ - SUPBOUND(max_sector, sector_t + max_size); - - /* alignment */ - max_sector -= (max_sector % floppy->sect) % ssize; - - /* transfer size, beginning not aligned */ - current_count_sectors = max_sector - sector_t ; - - return max_sector; -} - -/* - * Move data from/to the track buffer to/from the buffer cache. - */ -static void copy_buffer(int ssize, int max_sector, int max_sector_2) -{ - int remaining; /* number of transferred 512-byte sectors */ - struct buffer_head *bh; - char *buffer, *dma_buffer; - int size; - - max_sector = transfer_size(ssize, - minimum(max_sector, max_sector_2), - CURRENT->nr_sectors); - - if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE && - buffer_max > sector_t + CURRENT->nr_sectors) - current_count_sectors = minimum(buffer_max - sector_t, - CURRENT->nr_sectors); - - remaining = current_count_sectors << 9; -#ifdef FLOPPY_SANITY_CHECK - if ((remaining >> 9) > CURRENT->nr_sectors && - CT(COMMAND) == FD_WRITE){ - DPRINT("in copy buffer\n"); - printk("current_count_sectors=%ld\n", current_count_sectors); - printk("remaining=%d\n", remaining >> 9); - printk("CURRENT->nr_sectors=%ld\n",CURRENT->nr_sectors); - printk("CURRENT->current_nr_sectors=%ld\n", - CURRENT->current_nr_sectors); - printk("max_sector=%d\n", max_sector); - printk("ssize=%d\n", ssize); - } -#endif - - buffer_max = maximum(max_sector, buffer_max); - - dma_buffer = floppy_track_buffer + ((sector_t - buffer_min) << 9); - - bh = CURRENT->bh; - size = CURRENT->current_nr_sectors << 9; - buffer = CURRENT->buffer; - - while (remaining > 0){ - SUPBOUND(size, remaining); -#ifdef FLOPPY_SANITY_CHECK - if (dma_buffer + size > - floppy_track_buffer + (max_buffer_sectors << 10) || - dma_buffer < floppy_track_buffer){ - DPRINT1("buffer overrun in copy buffer %d\n", - (int) ((floppy_track_buffer - dma_buffer) >>9)); - printk("sector_t=%d buffer_min=%d\n", - sector_t, buffer_min); - printk("current_count_sectors=%ld\n", - current_count_sectors); - if (CT(COMMAND) == FD_READ) - printk("read\n"); - if (CT(COMMAND) == FD_READ) - printk("write\n"); - break; - } - if (((unsigned long)buffer) % 512) - DPRINT1("%p buffer not aligned\n", buffer); -#endif - if (CT(COMMAND) == FD_READ) { - fd_cacheflush(dma_buffer, size); - memcpy(buffer, dma_buffer, size); - } else { - memcpy(dma_buffer, buffer, size); - fd_cacheflush(dma_buffer, size); - } - remaining -= size; - if (!remaining) - break; - - dma_buffer += size; - bh = bh->b_reqnext; -#ifdef FLOPPY_SANITY_CHECK - if (!bh){ - DPRINT("bh=null in copy buffer after copy\n"); - break; - } -#endif - size = bh->b_size; - buffer = bh->b_data; - } -#ifdef FLOPPY_SANITY_CHECK - if (remaining){ - if (remaining > 0) - max_sector -= remaining >> 9; - DPRINT1("weirdness: remaining %d\n", remaining>>9); - } -#endif -} - -/* - * Formulate a read/write request. - * this routine decides where to load the data (directly to buffer, or to - * tmp floppy area), how much data to load (the size of the buffer, the whole - * track, or a single sector) - * All floppy_track_buffer handling goes in here. If we ever add track buffer - * allocation on the fly, it should be done here. No other part should need - * modification. - */ - -static int make_raw_rw_request(void) -{ - int aligned_sector_t; - int max_sector, max_size, tracksize, ssize; - - set_fdc(DRIVE(CURRENT->rq_dev)); - - raw_cmd = &default_raw_cmd; - raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK | - FD_RAW_NEED_SEEK; - raw_cmd->cmd_count = NR_RW; - if (CURRENT->cmd == READ){ - raw_cmd->flags |= FD_RAW_READ; - COMMAND = FM_MODE(floppy,FD_READ); - } else if (CURRENT->cmd == WRITE){ - raw_cmd->flags |= FD_RAW_WRITE; - COMMAND = FM_MODE(floppy,FD_WRITE); - } else { - DPRINT("make_raw_rw_request: unknown command\n"); - return 0; - } - - max_sector = floppy->sect * floppy->head; - - TRACK = CURRENT->sector / max_sector; - sector_t = CURRENT->sector % max_sector; - if (floppy->track && TRACK >= floppy->track) - return 0; - HEAD = sector_t / floppy->sect; - - if (((floppy->stretch & FD_SWAPSIDES) || TESTF(FD_NEED_TWADDLE)) && - sector_t < floppy->sect) - max_sector = floppy->sect; - - /* 2M disks have phantom sectors on the first track */ - if ((floppy->rate & FD_2M) && (!TRACK) && (!HEAD)){ - max_sector = 2 * floppy->sect / 3; - if (sector_t >= max_sector){ - current_count_sectors = minimum(floppy->sect - sector_t, - CURRENT->nr_sectors); - return 1; - } - SIZECODE = 2; - } else - SIZECODE = FD_SIZECODE(floppy); - raw_cmd->rate = floppy->rate & 0x43; - if ((floppy->rate & FD_2M) && - (TRACK || HEAD) && - raw_cmd->rate == 2) - raw_cmd->rate = 1; - - if (SIZECODE) - SIZECODE2 = 0xff; - else - SIZECODE2 = 0x80; - raw_cmd->track = TRACK << STRETCH(floppy); - DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,HEAD); - GAP = floppy->gap; - CODE2SIZE; - SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE; - SECTOR = ((sector_t % floppy->sect) << 2 >> SIZECODE) + 1; - tracksize = floppy->sect - floppy->sect % ssize; - if (tracksize < floppy->sect){ - SECT_PER_TRACK ++; - if (tracksize <= sector_t % floppy->sect) - SECTOR--; - while (tracksize <= sector_t % floppy->sect){ - while(tracksize + ssize > floppy->sect){ - SIZECODE--; - ssize >>= 1; - } - SECTOR++; SECT_PER_TRACK ++; - tracksize += ssize; - } - max_sector = HEAD * floppy->sect + tracksize; - } else if (!TRACK && !HEAD && !(floppy->rate & FD_2M) && probing) - max_sector = floppy->sect; - - aligned_sector_t = sector_t - (sector_t % floppy->sect) % ssize; - max_size = CURRENT->nr_sectors; - if ((raw_cmd->track == buffer_track) && - (current_drive == buffer_drive) && - (sector_t >= buffer_min) && (sector_t < buffer_max)) { - /* data already in track buffer */ - if (CT(COMMAND) == FD_READ) { - copy_buffer(1, max_sector, buffer_max); - return 1; - } - } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){ - if (CT(COMMAND) == FD_WRITE){ - if (sector_t + CURRENT->nr_sectors > ssize && - sector_t + CURRENT->nr_sectors < ssize + ssize) - max_size = ssize + ssize; - else - max_size = ssize; - } - raw_cmd->flags &= ~FD_RAW_WRITE; - raw_cmd->flags |= FD_RAW_READ; - COMMAND = FM_MODE(floppy,FD_READ); - } else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS) { - unsigned long dma_limit; - int direct, indirect; - - indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) - - sector_t; - - /* - * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide - * on a 64 bit machine! - */ - max_size = buffer_chain_size(); - dma_limit = (MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer)) >> 9; - if ((unsigned long) max_size > dma_limit) { - max_size = dma_limit; - } - /* 64 kb boundaries */ - if (CROSS_64KB(CURRENT->buffer, max_size << 9)) - max_size = (K_64 - ((long) CURRENT->buffer) % K_64)>>9; - direct = transfer_size(ssize,max_sector,max_size) - sector_t; - /* - * We try to read tracks, but if we get too many errors, we - * go back to reading just one sector at a time. - * - * This means we should be able to read a sector even if there - * are other bad sectors on this track. - */ - if (!direct || - (indirect * 2 > direct * 3 && - *errors < DP->max_errors.read_track && - /*!TESTF(FD_NEED_TWADDLE) &&*/ - ((!probing || (DP->read_track&(1<<DRS->probed_format)))))){ - max_size = CURRENT->nr_sectors; - } else { - raw_cmd->kernel_data = CURRENT->buffer; - raw_cmd->length = current_count_sectors << 9; - if (raw_cmd->length == 0){ - DPRINT("zero dma transfer attempted from make_raw_request\n"); - DPRINT3("indirect=%d direct=%d sector_t=%d", - indirect, direct, sector_t); - return 0; - } - return 2; - } - } - - if (CT(COMMAND) == FD_READ) - max_size = max_sector; /* unbounded */ - - /* claim buffer track if needed */ - if (buffer_track != raw_cmd->track || /* bad track */ - buffer_drive !=current_drive || /* bad drive */ - sector_t > buffer_max || - sector_t < buffer_min || - ((CT(COMMAND) == FD_READ || - (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize))&& - max_sector > 2 * max_buffer_sectors + buffer_min && - max_size + sector_t > 2 * max_buffer_sectors + buffer_min) - /* not enough space */){ - buffer_track = -1; - buffer_drive = current_drive; - buffer_max = buffer_min = aligned_sector_t; - } - raw_cmd->kernel_data = floppy_track_buffer + - ((aligned_sector_t-buffer_min)<<9); - - if (CT(COMMAND) == FD_WRITE){ - /* copy write buffer to track buffer. - * if we get here, we know that the write - * is either aligned or the data already in the buffer - * (buffer will be overwritten) */ -#ifdef FLOPPY_SANITY_CHECK - if (sector_t != aligned_sector_t && buffer_track == -1) - DPRINT("internal error offset !=0 on write\n"); -#endif - buffer_track = raw_cmd->track; - buffer_drive = current_drive; - copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min); - } else - transfer_size(ssize, max_sector, - 2*max_buffer_sectors+buffer_min-aligned_sector_t); - - /* round up current_count_sectors to get dma xfer size */ - raw_cmd->length = sector_t+current_count_sectors-aligned_sector_t; - raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1; - raw_cmd->length <<= 9; -#ifdef FLOPPY_SANITY_CHECK - if ((raw_cmd->length < current_count_sectors << 9) || - (raw_cmd->kernel_data != CURRENT->buffer && - CT(COMMAND) == FD_WRITE && - (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max || - aligned_sector_t < buffer_min)) || - raw_cmd->length % (128 << SIZECODE) || - raw_cmd->length <= 0 || current_count_sectors <= 0){ - DPRINT2("fractionary current count b=%lx s=%lx\n", - raw_cmd->length, current_count_sectors); - if (raw_cmd->kernel_data != CURRENT->buffer) - printk("addr=%d, length=%ld\n", - (int) ((raw_cmd->kernel_data - - floppy_track_buffer) >> 9), - current_count_sectors); - printk("st=%d ast=%d mse=%d msi=%d\n", - sector_t, aligned_sector_t, max_sector, max_size); - printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE); - printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n", - COMMAND, SECTOR, HEAD, TRACK); - printk("buffer drive=%d\n", buffer_drive); - printk("buffer track=%d\n", buffer_track); - printk("buffer_min=%d\n", buffer_min); - printk("buffer_max=%d\n", buffer_max); - return 0; - } - - if (raw_cmd->kernel_data != CURRENT->buffer){ - if (raw_cmd->kernel_data < floppy_track_buffer || - current_count_sectors < 0 || - raw_cmd->length < 0 || - raw_cmd->kernel_data + raw_cmd->length > - floppy_track_buffer + (max_buffer_sectors << 10)){ - DPRINT("buffer overrun in schedule dma\n"); - printk("sector_t=%d buffer_min=%d current_count=%ld\n", - sector_t, buffer_min, - raw_cmd->length >> 9); - printk("current_count_sectors=%ld\n", - current_count_sectors); - if (CT(COMMAND) == FD_READ) - printk("read\n"); - if (CT(COMMAND) == FD_READ) - printk("write\n"); - return 0; - } - } else if (raw_cmd->length > CURRENT->nr_sectors << 9 || - current_count_sectors > CURRENT->nr_sectors){ - DPRINT("buffer overrun in direct transfer\n"); - return 0; - } else if (raw_cmd->length < current_count_sectors << 9){ - DPRINT("more sectors than bytes\n"); - printk("bytes=%ld\n", raw_cmd->length >> 9); - printk("sectors=%ld\n", current_count_sectors); - } - if (raw_cmd->length == 0){ - DPRINT("zero dma transfer attempted from make_raw_request\n"); - return 0; - } -#endif - return 2; -} - -static void redo_fd_request(void) -{ -#define REPEAT {request_done(0); continue; } - kdev_t device; - int tmp; - - lastredo = jiffies; - if (current_drive < N_DRIVE) - floppy_off(current_drive); - - if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){ - DPRINT("current not active!\n"); - return; - } - - while(1){ - if (!CURRENT) { - CLEAR_INTR; - unlock_fdc(); - return; - } - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) - panic(DEVICE_NAME ": request list destroyed"); - if (CURRENT->bh && !buffer_locked(CURRENT->bh)) - panic(DEVICE_NAME ": block not locked"); - - device = CURRENT->rq_dev; - set_fdc(DRIVE(device)); - reschedule_timeout(CURRENTD, "redo fd request", 0); - - set_floppy(device); - raw_cmd = & default_raw_cmd; - raw_cmd->flags = 0; - if (start_motor(redo_fd_request)) return; - if (test_bit(current_drive, &fake_change) || - TESTF(FD_DISK_CHANGED)){ - DPRINT("disk absent or changed during operation\n"); - REPEAT; - } - if (!floppy) { /* Autodetection */ - if (!probing){ - DRS->probed_format = 0; - if (next_valid_format()){ - DPRINT("no autodetectable formats\n"); - floppy = NULL; - REPEAT; - } - } - probing = 1; - floppy = floppy_type+DP->autodetect[DRS->probed_format]; - } else - probing = 0; - errors = & (CURRENT->errors); - tmp = make_raw_rw_request(); - if (tmp < 2){ - request_done(tmp); - continue; - } - - if (TESTF(FD_NEED_TWADDLE)) - twaddle(); - floppy_tq.routine = (void *)(void *) floppy_start; - queue_task(&floppy_tq, &tq_timer); -#ifdef DEBUGT - debugt("queue fd request"); -#endif - return; - } -#undef REPEAT -} - -static struct cont_t rw_cont={ - rw_interrupt, - redo_fd_request, - bad_flp_intr, - request_done }; - -static struct tq_struct request_tq = -{ 0, 0, (void *) (void *) redo_fd_request, 0 }; - -static void process_fd_request(void) -{ - cont = &rw_cont; - queue_task(&request_tq, &tq_timer); -} - -static void do_fd_request(void) -{ - if (fdc_busy){ - /* fdc busy, this new request will be treated when the - current one is done */ - is_alive("do fd request, old request running"); - return; - } - lock_fdc(MAXTIMEOUT,0); - process_fd_request(); - is_alive("do fd request"); -} - -static struct cont_t poll_cont={ - success_and_wakeup, - floppy_ready, - generic_failure, - generic_done }; - -static int poll_drive(int interruptible, int flag) -{ - int ret; - /* no auto-sense, just clear dcl */ - raw_cmd = &default_raw_cmd; - raw_cmd->flags= flag; - raw_cmd->track=0; - raw_cmd->cmd_count=0; - cont = &poll_cont; -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("setting NEWCHANGE in poll_drive\n"); - } -#endif - SETF(FD_DISK_NEWCHANGE); - WAIT(floppy_ready); - return ret; -} - -/* - * User triggered reset - * ==================== - */ - -static void reset_intr(void) -{ - printk("weird, reset interrupt called\n"); -} - -static struct cont_t reset_cont={ - reset_intr, - success_and_wakeup, - generic_failure, - generic_done }; - -static int user_reset_fdc(int drive, int arg, int interruptible) -{ - int ret; - - ret=0; - LOCK_FDC(drive,interruptible); - if (arg == FD_RESET_ALWAYS) - FDCS->reset=1; - if (FDCS->reset){ - cont = &reset_cont; - WAIT(reset_fdc); - } - process_fd_request(); - return ret; -} - -/* - * Misc Ioctl's and support - * ======================== - */ -static int fd_copyout(void *param, const void *address, int size) -{ - int ret; - - ECALL(verify_area(VERIFY_WRITE,param,size)); - fd_cacheflush(address, size); /* is this necessary ??? */ - /* Ralf: Yes; only the l2 cache is completly chipset - controlled */ - memcpy_tofs(param,(void *) address, size); - return 0; -} - -static int fd_copyin(void *param, void *address, int size) -{ - int ret; - - ECALL(verify_area(VERIFY_READ,param,size)); - memcpy_fromfs((void *) address, param, size); - return 0; -} - -#define COPYOUT(x) ECALL(fd_copyout((void *)param, &(x), sizeof(x))) -#define COPYIN(x) ECALL(fd_copyin((void *)param, &(x), sizeof(x))) - -static inline const char *drive_name(int type, int drive) -{ - struct floppy_struct *floppy; - - if (type) - floppy = floppy_type + type; - else { - if (UDP->native_format) - floppy = floppy_type + UDP->native_format; - else - return "(null)"; - } - if (floppy->name) - return floppy->name; - else - return "(null)"; -} - - -/* raw commands */ -static void raw_cmd_done(int flag) -{ - int i; - - if (!flag) { - raw_cmd->flags = FD_RAW_FAILURE; - raw_cmd->flags |= FD_RAW_HARDFAILURE; - } else { - raw_cmd->reply_count = inr; - for (i=0; i< raw_cmd->reply_count; i++) - raw_cmd->reply[i] = reply_buffer[i]; - - if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) - raw_cmd->length = get_dma_residue(FLOPPY_DMA); - - if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) && - (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0))) - raw_cmd->flags |= FD_RAW_FAILURE; - - if (disk_change(current_drive)) - raw_cmd->flags |= FD_RAW_DISK_CHANGE; - else - raw_cmd->flags &= ~FD_RAW_DISK_CHANGE; - if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER) - motor_off_callback(current_drive); - - if (raw_cmd->next && - (!(raw_cmd->flags & FD_RAW_FAILURE) || - !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) && - ((raw_cmd->flags & FD_RAW_FAILURE) || - !(raw_cmd->flags &FD_RAW_STOP_IF_SUCCESS))) { - raw_cmd = raw_cmd->next; - return; - } - } - generic_done(flag); -} - - -static struct cont_t raw_cmd_cont={ - success_and_wakeup, - floppy_start, - generic_failure, - raw_cmd_done -}; - -static inline int raw_cmd_copyout(int cmd, char *param, - struct floppy_raw_cmd *ptr) -{ - struct old_floppy_raw_cmd old_raw_cmd; - int ret; - - while(ptr) { - if (cmd == OLDFDRAWCMD) { - old_raw_cmd.flags = ptr->flags; - old_raw_cmd.data = ptr->data; - old_raw_cmd.length = ptr->length; - old_raw_cmd.rate = ptr->rate; - old_raw_cmd.reply_count = ptr->reply_count; - memcpy(old_raw_cmd.reply, ptr->reply, 7); - COPYOUT(old_raw_cmd); - param += sizeof(old_raw_cmd); - } else { - COPYOUT(*ptr); - param += sizeof(struct floppy_raw_cmd); - } - - if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length){ - if (ptr->length>=0 && ptr->length<=ptr->buffer_length) - ECALL(fd_copyout(ptr->data, - ptr->kernel_data, - ptr->buffer_length - - ptr->length)); - } - ptr = ptr->next; - } - return 0; -} - - -static void raw_cmd_free(struct floppy_raw_cmd **ptr) -{ - struct floppy_raw_cmd *next,*this; - - this = *ptr; - *ptr = 0; - while(this) { - if (this->buffer_length) { - free_pages((unsigned long)this->kernel_data, - __get_order(this->buffer_length)); - this->buffer_length = 0; - } - next = this->next; - kfree(this); - this = next; - } -} - - -static inline int raw_cmd_copyin(int cmd, char *param, - struct floppy_raw_cmd **rcmd) -{ - struct floppy_raw_cmd *ptr; - struct old_floppy_raw_cmd old_raw_cmd; - int ret; - int i; - - *rcmd = 0; - while(1) { - ptr = (struct floppy_raw_cmd *) - kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER); - if (!ptr) - return -ENOMEM; - *rcmd = ptr; - if (cmd == OLDFDRAWCMD){ - COPYIN(old_raw_cmd); - ptr->flags = old_raw_cmd.flags; - ptr->data = old_raw_cmd.data; - ptr->length = old_raw_cmd.length; - ptr->rate = old_raw_cmd.rate; - ptr->cmd_count = old_raw_cmd.cmd_count; - ptr->track = old_raw_cmd.track; - ptr->phys_length = 0; - ptr->next = 0; - ptr->buffer_length = 0; - memcpy(ptr->cmd, old_raw_cmd.cmd, 9); - param += sizeof(struct old_floppy_raw_cmd); - if (ptr->cmd_count > 9) - return -EINVAL; - } else { - COPYIN(*ptr); - ptr->next = 0; - ptr->buffer_length = 0; - param += sizeof(struct floppy_raw_cmd); - if (ptr->cmd_count > 16) - return -EINVAL; - } - - for (i=0; i< 16; i++) - ptr->reply[i] = 0; - ptr->resultcode = 0; - ptr->kernel_data = 0; - - if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) { - if (ptr->length <= 0) - return -EINVAL; - ptr->kernel_data =(char*)dma_mem_alloc(ptr->length); - if (!ptr->kernel_data) - return -ENOMEM; - ptr->buffer_length = ptr->length; - } - if ( ptr->flags & FD_RAW_READ ) - ECALL( verify_area( VERIFY_WRITE, ptr->data, - ptr->length )); - if (ptr->flags & FD_RAW_WRITE) - ECALL(fd_copyin(ptr->data, ptr->kernel_data, - ptr->length)); - rcmd = & (ptr->next); - if (!(ptr->flags & FD_RAW_MORE)) - return 0; - ptr->rate &= 0x43; - } -} - - -static int raw_cmd_ioctl(int cmd, void *param) -{ - int drive, ret, ret2; - struct floppy_raw_cmd *my_raw_cmd; - - if (FDCS->rawcmd <= 1) - FDCS->rawcmd = 1; - for (drive= 0; drive < N_DRIVE; drive++){ - if (FDC(drive) != fdc) - continue; - if (drive == current_drive){ - if (UDRS->fd_ref > 1){ - FDCS->rawcmd = 2; - break; - } - } else if (UDRS->fd_ref){ - FDCS->rawcmd = 2; - break; - } - } - - if (FDCS->reset) - return -EIO; - - ret = raw_cmd_copyin(cmd, param, &my_raw_cmd); - if (ret) { - raw_cmd_free(&my_raw_cmd); - return ret; - } - - raw_cmd = my_raw_cmd; - cont = &raw_cmd_cont; - ret=wait_til_done(floppy_start,1); -#ifdef DCL_DEBUG - if (DP->flags & FD_DEBUG){ - DPRINT("calling disk change from raw_cmd ioctl\n"); - } -#endif - - if (ret != -EINTR && FDCS->reset) - ret = -EIO; - - DRS->track = NO_TRACK; - - ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd); - if (!ret) - ret = ret2; - raw_cmd_free(&my_raw_cmd); - return ret; -} - -static int invalidate_drive(kdev_t rdev) -{ - /* invalidate the buffer track to force a reread */ - set_bit(DRIVE(rdev), &fake_change); - process_fd_request(); - check_disk_change(rdev); - return 0; -} - - -static inline void clear_write_error(int drive) -{ - CLEARSTRUCT(UDRWE); -} - -static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, - int drive, int type, kdev_t device) -{ - int cnt; - - /* sanity checking for parameters.*/ - if (g->sect <= 0 || - g->head <= 0 || - g->track <= 0 || - g->track > UDP->tracks>>STRETCH(g) || - /* check if reserved bits are set */ - (g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0) - return -EINVAL; - if (type){ - if (!suser()) - return -EPERM; - LOCK_FDC(drive,1); - for (cnt = 0; cnt < N_DRIVE; cnt++){ - if (ITYPE(drive_state[cnt].fd_device) == type && - drive_state[cnt].fd_ref) - set_bit(drive, &fake_change); - } - floppy_type[type] = *g; - floppy_type[type].name="user format"; - for (cnt = type << 2; cnt < (type << 2) + 4; cnt++) - floppy_sizes[cnt]= floppy_sizes[cnt+0x80]= - floppy_type[type].size>>1; - process_fd_request(); - for (cnt = 0; cnt < N_DRIVE; cnt++){ - if (ITYPE(drive_state[cnt].fd_device) == type && - drive_state[cnt].fd_ref) - check_disk_change( - MKDEV(FLOPPY_MAJOR, - drive_state[cnt].fd_device)); - } - } else { - LOCK_FDC(drive,1); - if (cmd != FDDEFPRM) - /* notice a disk change immediately, else - * we loose our settings immediately*/ - CALL(poll_drive(1,0)); - user_params[drive] = *g; - if (buffer_drive == drive) - SUPBOUND(buffer_max, user_params[drive].sect); - current_type[drive] = &user_params[drive]; - floppy_sizes[drive] = user_params[drive].size >> 1; - if (cmd == FDDEFPRM) - DRS->keep_data = -1; - else - DRS->keep_data = 1; - /* invalidation. Invalidate only when needed, i.e. - * when there are already sectors in the buffer cache - * whose number will change. This is useful, because - * mtools often changes the geometry of the disk after - * looking at the boot block */ - if (DRS->maxblock > user_params[drive].sect || DRS->maxtrack) - invalidate_drive(device); - else - process_fd_request(); - } - return 0; -} - -/* handle obsolete ioctl's */ -static struct translation_entry { - int newcmd; - int oldcmd; - int oldsize; /* size of 0x00xx-style ioctl. Reflects old structures, thus - * use numeric values. NO SIZEOFS */ -} translation_table[]= { - {FDCLRPRM, 0, 0}, - {FDSETPRM, 1, 28}, - {FDDEFPRM, 2, 28}, - {FDGETPRM, 3, 28}, - {FDMSGON, 4, 0}, - {FDMSGOFF, 5, 0}, - {FDFMTBEG, 6, 0}, - {FDFMTTRK, 7, 12}, - {FDFMTEND, 8, 0}, - {FDSETEMSGTRESH, 10, 0}, - {FDFLUSH, 11, 0}, - {FDSETMAXERRS, 12, 20}, - {OLDFDRAWCMD, 30, 0}, - {FDGETMAXERRS, 14, 20}, - {FDGETDRVTYP, 16, 16}, - {FDSETDRVPRM, 20, 88}, - {FDGETDRVPRM, 21, 88}, - {FDGETDRVSTAT, 22, 52}, - {FDPOLLDRVSTAT, 23, 52}, - {FDRESET, 24, 0}, - {FDGETFDCSTAT, 25, 40}, - {FDWERRORCLR, 27, 0}, - {FDWERRORGET, 28, 24}, - {FDRAWCMD, 0, 0}, - {FDTWADDLE, 40, 0} }; - -static inline int normalize_0x02xx_ioctl(int *cmd, int *size) -{ - int i; - - for (i=0; i < ARRAY_SIZE(translation_table); i++) { - if ((*cmd & 0xffff) == (translation_table[i].newcmd & 0xffff)){ - *size = _IOC_SIZE(*cmd); - *cmd = translation_table[i].newcmd; - if (*size > _IOC_SIZE(*cmd)) { - printk("ioctl not yet supported\n"); - return -EFAULT; - } - return 0; - } - } - return -EINVAL; -} - -static inline int xlate_0x00xx_ioctl(int *cmd, int *size) -{ - int i; - /* old ioctls' for kernels <= 1.3.33 */ - /* When the next even release will come around, we'll start - * warning against these. - * When the next odd release will come around, we'll fail with - * -EINVAL */ - if(strcmp(system_utsname.version, "1.4.0") >= 0) - printk("obsolete floppy ioctl %x\n", *cmd); - if((system_utsname.version[0] == '1' && - strcmp(system_utsname.version, "1.5.0") >= 0) || - (system_utsname.version[0] >= '2' && - strcmp(system_utsname.version, "2.1.0") >= 0)) - return -EINVAL; - for (i=0; i < ARRAY_SIZE(translation_table); i++) { - if (*cmd == translation_table[i].oldcmd) { - *size = translation_table[i].oldsize; - *cmd = translation_table[i].newcmd; - return 0; - } - } - return -EINVAL; -} - -static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long param) -{ -#define IOCTL_MODE_BIT 8 -#define OPEN_WRITE_BIT 16 -#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) -#define OUT(c,x) case c: outparam = (const char *) (x); break -#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0 - - int i,drive,type; - kdev_t device; - int ret; - int size; - union inparam { - struct floppy_struct g; /* geometry */ - struct format_descr f; - struct floppy_max_errors max_errors; - struct floppy_drive_params dp; - } inparam; /* parameters coming from user space */ - const char *outparam; /* parameters passed back to user space */ - - device = inode->i_rdev; - switch (cmd) { - RO_IOCTLS(device,param); - } - type = TYPE(device); - drive = DRIVE(device); - - /* convert the old style command into a new style command */ - if ((cmd & 0xff00) == 0x0200) { - ECALL(normalize_0x02xx_ioctl(&cmd, &size)); - } else if ((cmd & 0xff00) == 0x0000) { - ECALL(xlate_0x00xx_ioctl(&cmd, &size)); - } else - return -EINVAL; - - /* permission checks */ - if (((cmd & 0x80) && !suser()) || - ((cmd & 0x40) && !IOCTL_ALLOWED)) - return -EPERM; - - /* verify writability of result, and fail early */ - if (_IOC_DIR(cmd) & _IOC_READ) - ECALL(verify_area(VERIFY_WRITE,(void *) param, size)); - - /* copyin */ - CLEARSTRUCT(&inparam); - if (_IOC_DIR(cmd) & _IOC_WRITE) - ECALL(fd_copyin((void *)param, &inparam, size)) - - switch (cmd) { - case FDCLRPRM: - LOCK_FDC(drive,1); - current_type[drive] = NULL; - floppy_sizes[drive] = MAX_DISK_SIZE; - UDRS->keep_data = 0; - return invalidate_drive(device); - case FDSETPRM: - case FDDEFPRM: - return set_geometry(cmd, & inparam.g, - drive, type, device); - case FDGETPRM: - if (type) - outparam = (char *) &floppy_type[type]; - else - outparam = (char *) current_type[drive]; - if(!outparam) - return -ENODEV; - break; - - case FDMSGON: - UDP->flags |= FTD_MSG; - return 0; - case FDMSGOFF: - UDP->flags &= ~FTD_MSG; - return 0; - - case FDFMTBEG: - LOCK_FDC(drive,1); - CALL(poll_drive(1, FD_RAW_NEED_DISK)); - ret = UDRS->flags; - process_fd_request(); - if(ret & FD_VERIFY) - return -ENODEV; - if(!(ret & FD_DISK_WRITABLE)) - return -EROFS; - return 0; - case FDFMTTRK: - if (UDRS->fd_ref != 1) - return -EBUSY; - return do_format(device, &inparam.f); - case FDFMTEND: - case FDFLUSH: - LOCK_FDC(drive,1); - return invalidate_drive(device); - - case FDSETEMSGTRESH: - UDP->max_errors.reporting = - (unsigned short) (param & 0x0f); - return 0; - OUT(FDGETMAXERRS, &UDP->max_errors); - IN(FDSETMAXERRS, &UDP->max_errors, max_errors); - - case FDGETDRVTYP: - outparam = drive_name(type,drive); - SUPBOUND(size,strlen(outparam)+1); - break; - - IN(FDSETDRVPRM, UDP, dp); - OUT(FDGETDRVPRM, UDP); - - case FDPOLLDRVSTAT: - LOCK_FDC(drive,1); - CALL(poll_drive(1, FD_RAW_NEED_DISK)); - process_fd_request(); - /* fall through */ - OUT(FDGETDRVSTAT, UDRS); - - case FDRESET: - return user_reset_fdc(drive, (int)param, 1); - - OUT(FDGETFDCSTAT,UFDCS); - - case FDWERRORCLR: - CLEARSTRUCT(UDRWE); - return 0; - OUT(FDWERRORGET,UDRWE); - - case OLDFDRAWCMD: - case FDRAWCMD: - if (type) - return -EINVAL; - LOCK_FDC(drive,1); - set_floppy(device); - CALL(i = raw_cmd_ioctl(cmd,(void *) param)); - process_fd_request(); - return i; - - case FDTWADDLE: - LOCK_FDC(drive,1); - twaddle(); - process_fd_request(); - return 0; - - default: - return -EINVAL; - } - - if (_IOC_DIR(cmd) & _IOC_READ) - return fd_copyout((void *)param, outparam, size); - else - return 0; -#undef IOCTL_ALLOWED -#undef OUT -#undef IN -} - -static void config_types(void) -{ - int first=1; - int drive; - - /* read drive info out of physical cmos */ - drive=0; - if (!UDP->cmos) - UDP->cmos= FLOPPY0_TYPE; - drive=1; - if (!UDP->cmos && FLOPPY1_TYPE) - UDP->cmos = FLOPPY1_TYPE; - - /* XXX */ - /* additional physical CMOS drive detection should go here */ - - for (drive=0; drive < N_DRIVE; drive++){ - if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params)) - memcpy((char *) UDP, - (char *) (&default_drive_params[(int)UDP->cmos].params), - sizeof(struct floppy_drive_params)); - if (UDP->cmos){ - if (first) - printk("Floppy drive(s): "); - else - printk(", "); - first=0; - if (UDP->cmos > 0){ - allowed_drive_mask |= 1 << drive; - printk("fd%d is %s", drive, - default_drive_params[(int)UDP->cmos].name); - } else - printk("fd%d is unknown type %d",drive, - UDP->cmos); - } - } - if (!first) - printk("\n"); -} - -static int floppy_read(struct inode * inode, struct file * filp, - char * buf, int count) -{ - int drive = DRIVE(inode->i_rdev); - - check_disk_change(inode->i_rdev); - if (UTESTF(FD_DISK_CHANGED)) - return -ENXIO; - return block_read(inode, filp, buf, count); -} - -static int floppy_write(struct inode * inode, struct file * filp, - const char * buf, int count) -{ - int block; - int ret; - int drive = DRIVE(inode->i_rdev); - - if (!UDRS->maxblock) - UDRS->maxblock=1;/* make change detectable */ - check_disk_change(inode->i_rdev); - if (UTESTF(FD_DISK_CHANGED)) - return -ENXIO; - if (!UTESTF(FD_DISK_WRITABLE)) - return -EROFS; - block = (filp->f_pos + count) >> 9; - INFBOUND(UDRS->maxblock, block); - ret= block_write(inode, filp, buf, count); - return ret; -} - -static void floppy_release(struct inode * inode, struct file * filp) -{ - int drive; - - drive = DRIVE(inode->i_rdev); - - if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) - /* if the file is mounted OR (writable now AND writable at - * open time) Linus: Does this cover all cases? */ - block_fsync(inode,filp); - - if (UDRS->fd_ref < 0) - UDRS->fd_ref=0; - else if (!UDRS->fd_ref--) { - DPRINT("floppy_release with fd_ref == 0"); - UDRS->fd_ref = 0; - } - floppy_release_irq_and_dma(); -} - -/* - * floppy_open check for aliasing (/dev/fd0 can be the same as - * /dev/PS0 etc), and disallows simultaneous access to the same - * drive with different device numbers. - */ -#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0) - -static int floppy_open(struct inode * inode, struct file * filp) -{ - int drive; - int old_dev; - int try; - char *tmp; - - if (!filp) { - DPRINT("Weird, open called with filp=0\n"); - return -EIO; - } - - drive = DRIVE(inode->i_rdev); - if (drive >= N_DRIVE || - !(allowed_drive_mask & (1 << drive)) || - fdc_state[FDC(drive)].version == FDC_NONE) - return -ENXIO; - - if (TYPE(inode->i_rdev) >= NUMBER(floppy_type)) - return -ENXIO; - old_dev = UDRS->fd_device; - if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev)) - return -EBUSY; - - if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){ - USETF(FD_DISK_CHANGED); - USETF(FD_VERIFY); - } - - if (UDRS->fd_ref == -1 || - (UDRS->fd_ref && (filp->f_flags & O_EXCL))) - return -EBUSY; - - if (floppy_grab_irq_and_dma()) - return -EBUSY; - - if (filp->f_flags & O_EXCL) - UDRS->fd_ref = -1; - else - UDRS->fd_ref++; - - if (!floppy_track_buffer){ - /* if opening an ED drive, reserve a big buffer, - * else reserve a small one */ - if ((UDP->cmos == 6) || (UDP->cmos == 5)) - try = 64; /* Only 48 actually useful */ - else - try = 32; /* Only 24 actually useful */ - - tmp=(char *)dma_mem_alloc(1024 * try); - if (!tmp) { - try >>= 1; /* buffer only one side */ - INFBOUND(try, 16); - tmp= (char *)dma_mem_alloc(1024*try); - } - if (!tmp) { - DPRINT("Unable to allocate DMA memory\n"); - RETERR(ENXIO); - } - if (floppy_track_buffer){ - free_pages((unsigned long)tmp,__get_order(try*1024)); - }else { - buffer_min = buffer_max = -1; - floppy_track_buffer = tmp; - max_buffer_sectors = try; - } - } - - UDRS->fd_device = MINOR(inode->i_rdev); - if (old_dev != -1 && old_dev != MINOR(inode->i_rdev)) { - if (buffer_drive == drive) - buffer_track = -1; - invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev)); - } - - /* Allow ioctls if we have write-permissions even if read-only open */ - if ((filp->f_mode & 2) || (permission(inode,2) == 0)) - filp->f_mode |= IOCTL_MODE_BIT; - if (filp->f_mode & 2) - filp->f_mode |= OPEN_WRITE_BIT; - - if (UFDCS->rawcmd == 1) - UFDCS->rawcmd = 2; - - if (filp->f_flags & O_NDELAY) - return 0; - if (filp->f_mode & 3) { - UDRS->last_checked = 0; - check_disk_change(inode->i_rdev); - if (UTESTF(FD_DISK_CHANGED)) - RETERR(ENXIO); - } - if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE))) - RETERR(EROFS); - return 0; -#undef RETERR -} - -/* - * Check if the disk has been changed or if a change has been faked. - */ -static int check_floppy_change(kdev_t dev) -{ - int drive = DRIVE(dev); - - if (MAJOR(dev) != MAJOR_NR) { - DPRINT("floppy_changed: not a floppy\n"); - return 0; - } - - if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) - return 1; - - if (UDRS->last_checked + UDP->checkfreq < jiffies){ - lock_fdc(drive,0); - poll_drive(0,0); - process_fd_request(); - } - - if (UTESTF(FD_DISK_CHANGED) || - UTESTF(FD_VERIFY) || - test_bit(drive, &fake_change) || - (!TYPE(dev) && !current_type[drive])) - return 1; - return 0; -} - -/* revalidate the floppy disk, i.e. trigger format autodetection by reading - * the bootblock (block 0). "Autodetection" is also needed to check whether - * there is a disk in the drive at all... Thus we also do it for fixed - * geometry formats */ -static int floppy_revalidate(kdev_t dev) -{ -#define NO_GEOM (!current_type[drive] && !TYPE(dev)) - struct buffer_head * bh; - int drive=DRIVE(dev); - int cf; - - if (UTESTF(FD_DISK_CHANGED) || - UTESTF(FD_VERIFY) || - test_bit(drive, &fake_change) || - NO_GEOM){ - lock_fdc(drive,0); - cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY); - if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)){ - process_fd_request(); /*already done by another thread*/ - return 0; - } - UDRS->maxblock = 0; - UDRS->maxtrack = 0; - if (buffer_drive == drive) - buffer_track = -1; - clear_bit(drive, &fake_change); - UCLEARF(FD_DISK_CHANGED); - if (cf) - UDRS->generation++; - if (NO_GEOM){ - /* auto-sensing */ - int size = floppy_blocksizes[MINOR(dev)]; - if (!size) - size = 1024; - if (!(bh = getblk(dev,0,size))){ - process_fd_request(); - return 1; - } - if (bh && !buffer_uptodate(bh)) - ll_rw_block(READ, 1, &bh); - process_fd_request(); - wait_on_buffer(bh); - brelse(bh); - return 0; - } - if (cf) - poll_drive(0, FD_RAW_NEED_DISK); - process_fd_request(); - } - return 0; -} - -static struct file_operations floppy_fops = { - NULL, /* lseek - default */ - floppy_read, /* read - general block-dev read */ - floppy_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - fd_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - check_floppy_change, /* media_change */ - floppy_revalidate, /* revalidate */ -}; - -/* - * Floppy Driver initialisation - * ============================= - */ - -/* Determine the floppy disk controller type */ -/* This routine was written by David C. Niemi */ -static char get_fdc_version(void) -{ - int r; - - output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */ - if (FDCS->reset) - return FDC_NONE; - if ((r = result()) <= 0x00) - return FDC_NONE; /* No FDC present ??? */ - if ((r==1) && (reply_buffer[0] == 0x80)){ - printk("FDC %d is a 8272A\n",fdc); - return FDC_8272A; /* 8272a/765 don't know DUMPREGS */ - } - if (r != 10) { - printk("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } - output_byte(FD_VERSION); - r = result(); - if ((r == 1) && (reply_buffer[0] == 0x80)){ - printk("FDC %d is a 82072\n",fdc); - return FDC_82072; /* 82072 doesn't know VERSION */ - } - if ((r != 1) || (reply_buffer[0] != 0x90)) { - printk("FDC %d init: VERSION: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } - output_byte(FD_UNLOCK); - r = result(); - if ((r == 1) && (reply_buffer[0] == 0x80)){ - printk("FDC %d is a pre-1991 82077\n", fdc); - return FDC_82077_ORIG; /* Pre-1991 82077 doesn't know LOCK/UNLOCK */ - } - if ((r != 1) || (reply_buffer[0] != 0x00)) { - printk("FDC %d init: UNLOCK: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } - output_byte(FD_PARTID); - r = result(); - if (r != 1) { - printk("FDC %d init: PARTID: unexpected return of %d bytes.\n", - fdc, r); - return FDC_UNKNOWN; - } - if (reply_buffer[0] == 0x80) { - printk("FDC %d is a post-1991 82077\n",fdc); - return FDC_82077; /* Revised 82077AA passes all the tests */ - } - switch (reply_buffer[0] >> 5) { - case 0x0: - output_byte(FD_SAVE); - r = result(); - if (r != 16) { - printk("FDC %d init: SAVE: unexpected return of %d bytes.\n", fdc, r); - return FDC_UNKNOWN; - } - if (!(reply_buffer[0] & 0x40)) { - printk("FDC %d is a 3Volt 82078SL.\n",fdc); - return FDC_82078; - } - /* Either a 82078-1 or a 82078SL running at 5Volt */ - printk("FDC %d is a 82078-1.\n",fdc); - return FDC_82078_1; - case 0x1: - printk("FDC %d is a 44pin 82078\n",fdc); - return FDC_82078; - case 0x2: - printk("FDC %d is a S82078B\n", fdc); - return FDC_S82078B; - case 0x3: - printk("FDC %d is a National Semiconductor PC87306\n", fdc); - return FDC_87306; - default: - printk("FDC %d init: 82077 variant with PARTID=%d.\n", - fdc, reply_buffer[0] >> 5); - return FDC_82077_UNKN; - } -} /* get_fdc_version */ - -/* lilo configuration */ - -/* we make the invert_dcl function global. One day, somebody might - * want to centralize all thinkpad related options into one lilo option, - * there are just so many thinkpad related quirks! */ -void floppy_invert_dcl(int *ints,int param) -{ - int i; - - for (i=0; i < ARRAY_SIZE(default_drive_params); i++){ - if (param) - default_drive_params[i].params.flags |= 0x80; - else - default_drive_params[i].params.flags &= ~0x80; - } - DPRINT("Configuring drives for inverted dcl\n"); -} - -static void daring(int *ints,int param) -{ - int i; - - for (i=0; i < ARRAY_SIZE(default_drive_params); i++){ - if (param){ - default_drive_params[i].params.select_delay = 0; - default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR; - } else { - default_drive_params[i].params.select_delay = 2*HZ/100; - default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR; - } - } - DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken"); -} - -static void allow_drives(int *ints, int param) -{ - allowed_drive_mask=param; - DPRINT1("setting allowed_drive_mask to 0x%x\n", param); -} - -static void fdc2_adr(int *ints, int param) -{ - FDC2 = param; - if (param) - DPRINT1("enabling second fdc at address 0x%3x\n", FDC2); - else - DPRINT("disabling second fdc\n"); -} - -static void unex(int *ints,int param) -{ - print_unex = param; - DPRINT1("%sprinting messages for unexpected interrupts\n", - param ? "" : "not "); -} - -static void set_cmos(int *ints, int dummy) -{ - int current_drive=0; - - if (ints[0] != 2){ - DPRINT("wrong number of parameter for cmos\n"); - return; - } - current_drive = ints[1]; - if (current_drive < 0 || current_drive >= 8){ - DPRINT("bad drive for set_cmos\n"); - return; - } - if (current_drive >= 4 && !FDC2) - fdc2_adr(0, 0x370); - if (ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){ - DPRINT1("bad cmos code %d\n", ints[2]); - return; - } - DP->cmos = ints[2]; - DPRINT1("setting cmos code to %d\n", ints[2]); -} - -static struct param_table { - const char *name; - void (*fn)(int *ints, int param); - int def_param; -} config_params[]={ - { "allowed_drive_mask", allow_drives, 0xff }, - { "all_drives", allow_drives, 0xff }, - { "asus_pci", allow_drives, 0x33 }, - - { "daring", daring, 1}, - - { "two_fdc", fdc2_adr, 0x370 }, - { "one_fdc", fdc2_adr, 0 }, - - { "thinkpad", floppy_invert_dcl, 1 }, - - { "cmos", set_cmos, 0 }, - - { "unexpected_interrupts", unex, 1 }, - { "no_unexpected_interrupts", unex, 0 }, - { "L40SX", unex, 0 } }; - -#define FLOPPY_SETUP -void floppy_setup(char *str, int *ints) -{ - int i; - int param; - if (str) - for (i=0; i< ARRAY_SIZE(config_params); i++){ - if (strcmp(str,config_params[i].name) == 0){ - if (ints[0]) - param = ints[1]; - else - param = config_params[i].def_param; - config_params[i].fn(ints,param); - return; - } - } - if (str) { - DPRINT1("unknown floppy option [%s]\n", str); - - DPRINT("allowed options are:"); - for (i=0; i< ARRAY_SIZE(config_params); i++) - printk(" %s",config_params[i].name); - printk("\n"); - } else - DPRINT("botched floppy option\n"); - DPRINT("Read linux/drivers/block/README.fd\n"); -} - -int floppy_init(void) -{ - int i,unit,drive; - int have_no_fdc= -EIO; - - raw_cmd = 0; - - sti(); - - if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { - printk("Unable to get major %d for floppy\n",MAJOR_NR); - return -EBUSY; - } - - for (i=0; i<256; i++) - if (ITYPE(i)) - floppy_sizes[i] = floppy_type[ITYPE(i)].size >> 1; - else - floppy_sizes[i] = MAX_DISK_SIZE; - - blk_size[MAJOR_NR] = floppy_sizes; - blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT); - config_types(); - - for (i = 0; i < N_FDC; i++) { - fdc = i; - CLEARSTRUCT(FDCS); - FDCS->dtr = -1; - FDCS->dor = 0x4; - } - - fdc_state[0].address = FDC1; -#if N_FDC > 1 - fdc_state[1].address = FDC2; -#endif - - if (floppy_grab_irq_and_dma()){ - unregister_blkdev(MAJOR_NR,"fd"); - return -EBUSY; - } - - /* initialise drive state */ - for (drive = 0; drive < N_DRIVE; drive++) { - CLEARSTRUCT(UDRS); - CLEARSTRUCT(UDRWE); - UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED; - UDRS->fd_device = -1; - floppy_track_buffer = NULL; - max_buffer_sectors = 0; - } - - for (i = 0; i < N_FDC; i++) { - fdc = i; - FDCS->driver_version = FD_DRIVER_VERSION; - for (unit=0; unit<4; unit++) - FDCS->track[unit] = 0; - if (FDCS->address == -1) - continue; - FDCS->rawcmd = 2; - if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){ - FDCS->address = -1; - continue; - } - /* Try to determine the floppy controller type */ - FDCS->version = get_fdc_version(); - if (FDCS->version == FDC_NONE){ - FDCS->address = -1; - continue; - } - - request_region(FDCS->address, 6, "floppy"); - request_region(FDCS->address+7, 1, "floppy DIR"); - /* address + 6 is reserved, and may be taken by IDE. - * Unfortunately, Adaptec doesn't know this :-(, */ - - have_no_fdc = 0; - /* Not all FDCs seem to be able to handle the version command - * properly, so force a reset for the standard FDC clones, - * to avoid interrupt garbage. - */ - FDCS->has_fifo = FDCS->version >= FDC_82077_ORIG; - user_reset_fdc(-1,FD_RESET_ALWAYS,0); - } - fdc=0; - del_timer(&fd_timeout); - current_drive = 0; - floppy_release_irq_and_dma(); - initialising=0; - if (have_no_fdc) { - DPRINT("no floppy controllers found\n"); - unregister_blkdev(MAJOR_NR,"fd"); - } else - virtual_dma_init(); - return have_no_fdc; -} - -static int floppy_grab_irq_and_dma(void) -{ - int i; - cli(); - if (usage_count++){ - sti(); - return 0; - } - sti(); - MOD_INC_USE_COUNT; - for (i=0; i< N_FDC; i++){ - if (FDCS->address != -1){ - fdc = i; - reset_fdc_info(1); - fd_outb(FDCS->dor, FD_DOR); - } - } - set_dor(0, ~0, 8); /* avoid immediate interrupt */ - - if (fd_request_irq()) { - DPRINT1("Unable to grab IRQ%d for the floppy driver\n", - FLOPPY_IRQ); - return -1; - } - if (fd_request_dma()) { - DPRINT1("Unable to grab DMA%d for the floppy driver\n", - FLOPPY_DMA); - fd_free_irq(); - return -1; - } - for (fdc = 0; fdc < N_FDC; fdc++) - if (FDCS->address != -1) - fd_outb(FDCS->dor, FD_DOR); - fdc = 0; - fd_enable_irq(); - return 0; -} - -static void floppy_release_irq_and_dma(void) -{ -#ifdef FLOPPY_SANITY_CHECK - int drive; -#endif - long tmpsize; - void *tmpaddr; - - cli(); - if (--usage_count){ - sti(); - return; - } - sti(); - MOD_DEC_USE_COUNT; - fd_disable_dma(); - fd_free_dma(); - fd_disable_irq(); - fd_free_irq(); - - set_dor(0, ~0, 8); -#if N_FDC > 1 - set_dor(1, ~8, 0); -#endif - floppy_enable_hlt(); - - if (floppy_track_buffer && max_buffer_sectors) { - tmpsize = max_buffer_sectors*1024; - tmpaddr = (void *)floppy_track_buffer; - floppy_track_buffer = 0; - max_buffer_sectors = 0; - buffer_min = buffer_max = -1; - free_pages((unsigned long)tmpaddr, __get_order(tmpsize)); - } - -#ifdef FLOPPY_SANITY_CHECK - for (drive=0; drive < N_FDC * 4; drive++) - if (motor_off_timer[drive].next) - printk("motor off timer %d still active\n", drive); - - if (fd_timeout.next) - printk("floppy timer still active:%s\n", timeout_message); - if (fd_timer.next) - printk("auxiliary floppy timer still active\n"); - if (floppy_tq.sync) - printk("task queue still active\n"); -#endif -} - - -#ifdef MODULE - -extern char *get_options(char *str, int *ints); - -static void mod_setup(char *pattern, void (*setup)(char *, int *)) -{ - int i; - char c; - int j; - int match; - char buffer[100]; - int ints[11]; - int length = strlen(pattern)+1; - - match=0; - j=1; - - for (i=current->mm->env_start; i< current->mm->env_end; i ++){ - c= get_fs_byte(i); - if (match){ - if (j==99) - c='\0'; - buffer[j] = c; - if (!c || c == ' ' || c == '\t'){ - if (j){ - buffer[j] = '\0'; - setup(get_options(buffer,ints),ints); - } - j=0; - } else - j++; - if (!c) - break; - continue; - } - if ((!j && !c) || (j && c == pattern[j-1])) - j++; - else - j=0; - if (j==length){ - match=1; - j=0; - } - } -} - - -#ifdef __cplusplus -extern "C" { -#endif -int init_module(void) -{ - printk("inserting floppy driver for %s\n", kernel_version); - - mod_setup("floppy=", floppy_setup); - - return floppy_init(); -} - -void cleanup_module(void) -{ - int fdc; - - for (fdc=0; fdc<2; fdc++) - if (FDCS->address != -1){ - release_region(FDCS->address, 6); - release_region(FDCS->address+7, 1); - } - - unregister_blkdev(MAJOR_NR, "fd"); - - blk_dev[MAJOR_NR].request_fn = 0; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/i386/i386at/gpl/linux/block/genhd.c b/i386/i386at/gpl/linux/block/genhd.c deleted file mode 100644 index cebc7ea..0000000 --- a/i386/i386at/gpl/linux/block/genhd.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Code extracted from - * linux/kernel/hd.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * - * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * in the early extended-partition checks and added DM partitions - * - * Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca) - * with information provided by OnTrack. This now works for linux fdisk - * and LILO, as well as loadlin and bootln. Note that disks other than - * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). - * - * More flexible handling of extended partitions - aeb, 950831 - * - * Check partition table on IDE disks for common CHS translations - */ - -#include <linux/config.h> -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> - -#include <asm/system.h> - -#ifdef __alpha__ -/* - * On the Alpha, we get unaligned access exceptions on - * p->nr_sects and p->start_sect, when the partition table - * is not on a 4-byte boundary, which is frequently the case. - * This code uses unaligned load instructions to prevent - * such exceptions. - */ -#include <asm/unaligned.h> -#define NR_SECTS(p) ldl_u(&p->nr_sects) -#define START_SECT(p) ldl_u(&p->start_sect) -#else /* __alpha__ */ -#define NR_SECTS(p) p->nr_sects -#define START_SECT(p) p->start_sect -#endif /* __alpha__ */ - -#ifdef MACH -#include <i386/ipl.h> -#endif - -struct gendisk *gendisk_head = NULL; - -static int current_minor = 0; -extern int *blk_size[]; -extern void rd_load(void); - -extern int chr_dev_init(void); -extern int blk_dev_init(void); -extern int scsi_dev_init(void); -extern int net_dev_init(void); - -static void print_minor_name (struct gendisk *hd, int minor) -{ - unsigned int unit = minor >> hd->minor_shift; - unsigned int part = minor & ((1 << hd->minor_shift) - 1); - -#ifdef CONFIG_BLK_DEV_IDE - /* - * IDE devices use multiple major numbers, but the drives - * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. - * This requires some creative handling here to find the - * correct name to use, with some help from ide.c - */ - if (!strcmp(hd->major_name,"ide")) { - char name[16]; /* more than large enough */ - strcpy(name, hd->real_devices); /* courtesy ide.c */ - name[strlen(name)-1] += unit; - printk(" %s", name); - } else -#endif - printk(" %s%c", hd->major_name, 'a' + unit); - if (part) - printk("%d", part); - else - printk(":"); -} - -static void add_partition (struct gendisk *hd, int minor, int start, int size) -{ - hd->part[minor].start_sect = start; - hd->part[minor].nr_sects = size; - /* print_minor_name(hd, minor);*/ -} - -static inline int is_extended_partition(struct partition *p) -{ - return (p->sys_ind == DOS_EXTENDED_PARTITION || - p->sys_ind == LINUX_EXTENDED_PARTITION); -} - -#ifdef CONFIG_MSDOS_PARTITION -/* - * Create devices for each logical partition in an extended partition. - * The logical partitions form a linked list, with each entry being - * a partition table with two entries. The first entry - * is the real data partition (with a start relative to the partition - * table start). The second is a pointer to the next logical partition - * (with a start relative to the entire extended partition). - * We do not create a Linux partition for the partition tables, but - * only for the actual data partitions. - */ - -static void extended_partition(struct gendisk *hd, kdev_t dev) -{ - struct buffer_head *bh; - struct partition *p; - unsigned long first_sector, first_size, this_sector, this_size; - int mask = (1 << hd->minor_shift) - 1; - int i; - - first_sector = hd->part[MINOR(dev)].start_sect; - first_size = hd->part[MINOR(dev)].nr_sects; - this_sector = first_sector; - - while (1) { - if ((current_minor & mask) == 0) - return; - if (!(bh = bread(dev,0,1024))) - return; - /* - * This block is from a device that we're about to stomp on. - * So make sure nobody thinks this block is usable. - */ - bh->b_state = 0; - - if (*(unsigned short *) (bh->b_data+510) != 0xAA55) - goto done; - - p = (struct partition *) (0x1BE + bh->b_data); - - this_size = hd->part[MINOR(dev)].nr_sects; - - /* - * Usually, the first entry is the real data partition, - * the 2nd entry is the next extended partition, or empty, - * and the 3rd and 4th entries are unused. - * However, DRDOS sometimes has the extended partition as - * the first entry (when the data partition is empty), - * and OS/2 seems to use all four entries. - */ - - /* - * First process the data partition(s) - */ - for (i=0; i<4; i++, p++) { - if (!NR_SECTS(p) || is_extended_partition(p)) - continue; - - /* Check the 3rd and 4th entries - - these sometimes contain random garbage */ - if (i >= 2 - && START_SECT(p) + NR_SECTS(p) > this_size - && (this_sector + START_SECT(p) < first_sector || - this_sector + START_SECT(p) + NR_SECTS(p) > - first_sector + first_size)) - continue; - - add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p)); - current_minor++; - if ((current_minor & mask) == 0) - goto done; - } - /* - * Next, process the (first) extended partition, if present. - * (So far, there seems to be no reason to make - * extended_partition() recursive and allow a tree - * of extended partitions.) - * It should be a link to the next logical partition. - * Create a minor for this just long enough to get the next - * partition table. The minor will be reused for the next - * data partition. - */ - p -= 4; - for (i=0; i<4; i++, p++) - if(NR_SECTS(p) && is_extended_partition(p)) - break; - if (i == 4) - goto done; /* nothing left to do */ - - hd->part[current_minor].nr_sects = NR_SECTS(p); - hd->part[current_minor].start_sect = first_sector + START_SECT(p); - this_sector = first_sector + START_SECT(p); - dev = MKDEV(hd->major, current_minor); - brelse(bh); - } -done: - brelse(bh); -} - -static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) -{ - int i, minor = current_minor; - struct buffer_head *bh; - struct partition *p; - unsigned char *data; - int mask = (1 << hd->minor_shift) - 1; -#ifdef CONFIG_BLK_DEV_IDE - int tested_for_xlate = 0; - -read_mbr: -#endif - if (!(bh = bread(dev,0,1024))) { - printk(" unable to read partition table\n"); - return -1; - } - data = bh->b_data; - /* In some cases we modify the geometry */ - /* of the drive (below), so ensure that */ - /* nobody else tries to re-use this data. */ - bh->b_state = 0; -#ifdef CONFIG_BLK_DEV_IDE -check_table: -#endif - if (*(unsigned short *) (0x1fe + data) != 0xAA55) { - brelse(bh); - return 0; - } - p = (struct partition *) (0x1be + data); - -#ifdef CONFIG_BLK_DEV_IDE - if (!tested_for_xlate++) { /* Do this only once per disk */ - /* - * Look for various forms of IDE disk geometry translation - */ - extern int ide_xlate_1024(kdev_t, int, const char *); - unsigned int sig = *(unsigned short *)(data + 2); - if (p->sys_ind == EZD_PARTITION) { - /* - * The remainder of the disk must be accessed using - * a translated geometry that reduces the number of - * apparent cylinders to less than 1024 if possible. - * - * ide_xlate_1024() will take care of the necessary - * adjustments to fool fdisk/LILO and partition check. - */ - if (ide_xlate_1024(dev, -1, " [EZD]")) { - data += 512; - goto check_table; - } - } else if (p->sys_ind == DM6_PARTITION) { - - /* - * Everything on the disk is offset by 63 sectors, - * including a "new" MBR with its own partition table, - * and the remainder of the disk must be accessed using - * a translated geometry that reduces the number of - * apparent cylinders to less than 1024 if possible. - * - * ide_xlate_1024() will take care of the necessary - * adjustments to fool fdisk/LILO and partition check. - */ - if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) { - brelse(bh); - goto read_mbr; /* start over with new MBR */ - } - } else if (sig <= 0x1ae && *(unsigned short *)(data + sig) == 0x55AA - && (1 & *(unsigned char *)(data + sig + 2)) ) - { - /* - * DM6 signature in MBR, courtesy of OnTrack - */ - (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]"); - } else if (p->sys_ind == DM6_AUX1PARTITION || p->sys_ind == DM6_AUX3PARTITION) { - /* - * DM6 on other than the first (boot) drive - */ - (void) ide_xlate_1024(dev, 0, " [DM6:AUX]"); - } else { - /* - * Examine the partition table for common translations. - * This is necessary for drives for situations where - * the translated geometry is unavailable from the BIOS. - */ - for (i = 0; i < 4 ; i++) { - struct partition *q = &p[i]; - if (NR_SECTS(q) && q->sector == 1 && q->end_sector == 63) { - unsigned int heads = q->end_head + 1; - if (heads == 32 || heads == 64 || heads == 128) { - - (void) ide_xlate_1024(dev, heads, " [PTBL]"); - break; - } - } - } - } - } -#endif /* CONFIG_BLK_DEV_IDE */ - - current_minor += 4; /* first "extra" minor (for extended partitions) */ - for (i=1 ; i<=4 ; minor++,i++,p++) { - if (!NR_SECTS(p)) - continue; - add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p)); - if (is_extended_partition(p)) { - /* printk(" <");*/ - /* - * If we are rereading the partition table, we need - * to set the size of the partition so that we will - * be able to bread the block containing the extended - * partition info. - */ - hd->sizes[minor] = hd->part[minor].nr_sects - >> (BLOCK_SIZE_BITS - 9); - extended_partition(hd, MKDEV(hd->major, minor)); - /* printk(" >");*/ - /* prevent someone doing mkfs or mkswap on an - extended partition, but leave room for LILO */ - if (hd->part[minor].nr_sects > 2) - hd->part[minor].nr_sects = 2; - } - } - /* - * Check for old-style Disk Manager partition table - */ - if (*(unsigned short *) (data+0xfc) == 0x55AA) { - p = (struct partition *) (0x1be + data); - for (i = 4 ; i < 16 ; i++, current_minor++) { - p--; - if ((current_minor & mask) == 0) - break; - if (!(START_SECT(p) && NR_SECTS(p))) - continue; - add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); - } - } - /* printk("\n");*/ - brelse(bh); - return 1; -} - -#endif /* CONFIG_MSDOS_PARTITION */ - -#ifdef CONFIG_OSF_PARTITION - -static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) -{ - int i; - int mask = (1 << hd->minor_shift) - 1; - struct buffer_head *bh; - struct disklabel { - u32 d_magic; - u16 d_type,d_subtype; - u8 d_typename[16]; - u8 d_packname[16]; - u32 d_secsize; - u32 d_nsectors; - u32 d_ntracks; - u32 d_ncylinders; - u32 d_secpercyl; - u32 d_secprtunit; - u16 d_sparespertrack; - u16 d_sparespercyl; - u32 d_acylinders; - u16 d_rpm, d_interleave, d_trackskew, d_cylskew; - u32 d_headswitch, d_trkseek, d_flags; - u32 d_drivedata[5]; - u32 d_spare[5]; - u32 d_magic2; - u16 d_checksum; - u16 d_npartitions; - u32 d_bbsize, d_sbsize; - struct d_partition { - u32 p_size; - u32 p_offset; - u32 p_fsize; - u8 p_fstype; - u8 p_frag; - u16 p_cpg; - } d_partitions[8]; - } * label; - struct d_partition * partition; -#define DISKLABELMAGIC (0x82564557UL) - - if (!(bh = bread(dev,0,1024))) { - printk("unable to read partition table\n"); - return -1; - } - label = (struct disklabel *) (bh->b_data+64); - partition = label->d_partitions; - if (label->d_magic != DISKLABELMAGIC) { - printk("magic: %08x\n", label->d_magic); - brelse(bh); - return 0; - } - if (label->d_magic2 != DISKLABELMAGIC) { - printk("magic2: %08x\n", label->d_magic2); - brelse(bh); - return 0; - } - for (i = 0 ; i < label->d_npartitions; i++, partition++) { - if ((current_minor & mask) == 0) - break; - if (partition->p_size) - add_partition(hd, current_minor, - first_sector+partition->p_offset, - partition->p_size); - current_minor++; - } - /* printk("\n");*/ - brelse(bh); - return 1; -} - -#endif /* CONFIG_OSF_PARTITION */ - -#ifdef CONFIG_SUN_PARTITION - -static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) -{ - int i, csum; - unsigned short *ush; - struct buffer_head *bh; - struct sun_disklabel { - unsigned char info[128]; /* Informative text string */ - unsigned char spare[292]; /* Boot information etc. */ - unsigned short rspeed; /* Disk rotational speed */ - unsigned short pcylcount; /* Physical cylinder count */ - unsigned short sparecyl; /* extra sects per cylinder */ - unsigned char spare2[4]; /* More magic... */ - unsigned short ilfact; /* Interleave factor */ - unsigned short ncyl; /* Data cylinder count */ - unsigned short nacyl; /* Alt. cylinder count */ - unsigned short ntrks; /* Tracks per cylinder */ - unsigned short nsect; /* Sectors per track */ - unsigned char spare3[4]; /* Even more magic... */ - struct sun_partition { - unsigned long start_cylinder; - unsigned long num_sectors; - } partitions[8]; - unsigned short magic; /* Magic number */ - unsigned short csum; /* Label xor'd checksum */ - } * label; - struct sun_partition *p; - unsigned long spc; -#define SUN_LABEL_MAGIC 0xDABE - - if(!(bh = bread(dev, 0, 1024))) { - printk("Dev %d: unable to read partition table\n", dev); - return -1; - } - label = (struct sun_disklabel *) bh->b_data; - p = label->partitions; - if(label->magic != SUN_LABEL_MAGIC) { - printk("Dev %d Sun disklabel: bad magic %08x\n", dev, label->magic); - brelse(bh); - return 0; - } - /* Look at the checksum */ - ush = ((unsigned short *) (label+1)) - 1; - for(csum = 0; ush >= ((unsigned short *) label);) - csum ^= *ush--; - if(csum) { - printk("Dev %d Sun disklabel: Csum bad, label corrupted\n", dev); - brelse(bh); - return 0; - } - /* All Sun disks have 8 partition entries */ - spc = (label->ntrks * label->nsect); - for(i=0; i < 8; i++, p++) { - unsigned long st_sector; - - /* We register all partitions, even if zero size, so that - * the minor numbers end up ok as per SunOS interpretation. - */ - st_sector = first_sector + (p->start_cylinder * spc); - add_partition(hd, current_minor, st_sector, p->num_sectors); - current_minor++; - } - /* printk("\n");*/ - brelse(bh); - return 1; -} - -#endif /* CONFIG_SUN_PARTITION */ - -static void check_partition(struct gendisk *hd, kdev_t dev) -{ - static int first_time = 1; - unsigned long first_sector; - - /* if (first_time) - printk("Partition check:\n");*/ - first_time = 0; - first_sector = hd->part[MINOR(dev)].start_sect; - - /* - * This is a kludge to allow the partition check to be - * skipped for specific drives (e.g. IDE cd-rom drives) - */ - if ((int)first_sector == -1) { - hd->part[MINOR(dev)].start_sect = 0; - return; - } - - /* printk(" "); - print_minor_name(hd, MINOR(dev));*/ -#ifdef CONFIG_MSDOS_PARTITION - if (msdos_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_OSF_PARTITION - if (osf_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_SUN_PARTITION - if(sun_partition(hd, dev, first_sector)) - return; -#endif - printk(" unknown partition table\n"); -} - -/* This function is used to re-read partition tables for removable disks. - Much of the cleanup from the old partition tables should have already been - done */ - -/* This function will re-read the partition tables for a given device, -and set things back up again. There are some important caveats, -however. You must ensure that no one is using the device, and no one -can start using the device while this function is being executed. */ - -void resetup_one_dev(struct gendisk *dev, int drive) -{ - int i; - int first_minor = drive << dev->minor_shift; - int end_minor = first_minor + dev->max_p; - - blk_size[dev->major] = NULL; - current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); - - /* - * We need to set the sizes array before we will be able to access - * any of the partitions on this device. - */ - if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = first_minor; i < end_minor; i++) - dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); - blk_size[dev->major] = dev->sizes; - } -} - -static void setup_dev(struct gendisk *dev) -{ - int i, drive; - int end_minor = dev->max_nr * dev->max_p; - - blk_size[dev->major] = NULL; - for (i = 0 ; i < end_minor; i++) { - dev->part[i].start_sect = 0; - dev->part[i].nr_sects = 0; - } - dev->init(dev); - for (drive = 0 ; drive < dev->nr_real ; drive++) { - int first_minor = drive << dev->minor_shift; - current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); - } - if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = 0; i < end_minor; i++) - dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); - blk_size[dev->major] = dev->sizes; - } -} - -void device_setup(void) -{ - extern void console_map_init(void); - struct gendisk *p; - int nr=0; -#ifdef MACH - extern int linux_intr_pri; - - linux_intr_pri = SPL5; -#endif - -#ifndef MACH - chr_dev_init(); -#endif - blk_dev_init(); - sti(); -#ifdef CONFIG_SCSI - scsi_dev_init(); -#endif -#ifdef CONFIG_INET -#ifdef MACH - linux_intr_pri = SPL6; -#endif - net_dev_init(); -#endif -#ifndef MACH - console_map_init(); -#endif - - for (p = gendisk_head ; p ; p=p->next) { - setup_dev(p); - nr += p->nr_real; - } -#ifdef CONFIG_BLK_DEV_RAM - rd_load(); -#endif -} diff --git a/i386/i386at/gpl/linux/block/ide-cd.c b/i386/i386at/gpl/linux/block/ide-cd.c deleted file mode 100644 index 6dc9380..0000000 --- a/i386/i386at/gpl/linux/block/ide-cd.c +++ /dev/null @@ -1,2770 +0,0 @@ -/* - * linux/drivers/block/ide-cd.c - * - * 1.00 Oct 31, 1994 -- Initial version. - * 1.01 Nov 2, 1994 -- Fixed problem with starting request in - * cdrom_check_status. - * 1.03 Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks) - * (from mlord) -- minor changes to cdrom_setup() - * -- renamed ide_dev_s to ide_drive_t, enable irq on command - * 2.00 Nov 27, 1994 -- Generalize packet command interface; - * add audio ioctls. - * 2.01 Dec 3, 1994 -- Rework packet command interface to handle devices - * which send an interrupt when ready for a command. - * 2.02 Dec 11, 1994 -- Cache the TOC in the driver. - * Don't use SCMD_PLAYAUDIO_TI; it's not included - * in the current version of ATAPI. - * Try to use LBA instead of track or MSF addressing - * when possible. - * Don't wait for READY_STAT. - * 2.03 Jan 10, 1995 -- Rewrite block read routines to handle block sizes - * other than 2k and to move multiple sectors in a - * single transaction. - * 2.04 Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives. - * Thanks to Nick Saw <cwsaw@pts7.pts.mot.com> for - * help in figuring this out. Ditto for Acer and - * Aztech drives, which seem to have the same problem. - * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml - * 2.05 Jun 8, 1995 -- Don't attempt to retry after an illegal request - * or data protect error. - * Use HWIF and DEV_HWIF macros as in ide.c. - * Always try to do a request_sense after - * a failed command. - * Include an option to give textual descriptions - * of ATAPI errors. - * Fix a bug in handling the sector cache which - * showed up if the drive returned data in 512 byte - * blocks (like Pioneer drives). Thanks to - * Richard Hirst <srh@gpt.co.uk> for diagnosing this. - * Properly supply the page number field in the - * MODE_SELECT command. - * PLAYAUDIO12 is broken on the Aztech; work around it. - * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c - * (my apologies to Scott, but now ide-cd.c is independent) - * 3.00 Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl. - * Implement CDROMREADAUDIO ioctl (UNTESTED). - * Use input_ide_data() and output_ide_data(). - * Add door locking. - * Fix usage count leak in cdrom_open, which happened - * when a read-write mount was attempted. - * Try to load the disk on open. - * Implement CDROMEJECT_SW ioctl (off by default). - * Read total cdrom capacity during open. - * Rearrange logic in cdrom_decode_status. Issue - * request sense commands for failed packet commands - * from here instead of from cdrom_queue_packet_command. - * Fix a race condition in retrieving error information. - * Suppress printing normal unit attention errors and - * some drive not ready errors. - * Implement CDROMVOLREAD ioctl. - * Implement CDROMREADMODE1/2 ioctls. - * Fix race condition in setting up interrupt handlers - * when the `serialize' option is used. - * 3.01 Sep 2, 1995 -- Fix ordering of reenabling interrupts in - * cdrom_queue_request. - * Another try at using ide_[input,output]_data. - * 3.02 Sep 16, 1995 -- Stick total disk capacity in partition table as well. - * Make VERBOSE_IDE_CD_ERRORS dump failed command again. - * Dump out more information for ILLEGAL REQUEST errs. - * Fix handling of errors occuring before the - * packet command is transferred. - * Fix transfers with odd bytelengths. - * 3.03 Oct 27, 1995 -- Some Creative drives have an id of just `CD'. - * `DCI-2S10' drives are broken too. - * 3.04 Nov 20, 1995 -- So are Vertos drives. - * 3.05 Dec 1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c - * 3.06 Dec 16, 1995 -- Add support needed for partitions. - * More workarounds for Vertos bugs (based on patches - * from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>). - * Try to eliminate byteorder assumptions. - * Use atapi_cdrom_subchnl struct definition. - * Add STANDARD_ATAPI compilation option. - * 3.07 Jan 29, 1996 -- More twiddling for broken drives: Sony 55D, - * Vertos 300. - * Add NO_DOOR_LOCKING configuration option. - * Handle drive_cmd requests w/NULL args (for hdparm -t). - * Work around sporadic Sony55e audio play problem. - * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix - * problem with "hde=cdrom" with no drive present. -ml - * - * NOTE: Direct audio reads will only work on some types of drive. - * So far, i've received reports of success for Sony and Toshiba drives. - * - * ATAPI cd-rom driver. To be used with ide.c. - * - * Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov> - * May be copied or modified under the terms of the GNU General Public License - * (../../COPYING). - */ - - -/***************************************************************************/ - -#include <linux/types.h> -#include <linux/kernel.h> -#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> -#include <asm/byteorder.h> -#include <asm/segment.h> -#ifdef __alpha__ -# include <asm/unaligned.h> -#endif - -#include "ide.h" - - - -/* Turn this on to have the driver print out the meanings of the - ATAPI error codes. This will use up additional kernel-space - memory, though. */ - -#ifndef VERBOSE_IDE_CD_ERRORS -#define VERBOSE_IDE_CD_ERRORS 0 -#endif - - -/* Turning this on will remove code to work around various nonstandard - ATAPI implementations. If you know your drive follows the standard, - this will give you a slightly smaller kernel. */ - -#ifndef STANDARD_ATAPI -#define STANDARD_ATAPI 0 -#endif - - -/* Turning this on will disable the door-locking functionality. - This is apparently needed for supermount. */ - -#ifndef NO_DOOR_LOCKING -#define NO_DOOR_LOCKING 0 -#endif - - -/************************************************************************/ - -#define SECTOR_SIZE 512 -#define SECTOR_BITS 9 -#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -/* special command codes for strategy routine. */ -#define PACKET_COMMAND 4315 -#define REQUEST_SENSE_COMMAND 4316 -#define RESET_DRIVE_COMMAND 4317 - -/* Some ATAPI command opcodes (just like SCSI). - (Some other cdrom-specific codes are in cdrom.h.) */ -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define START_STOP 0x1b -#define ALLOW_MEDIUM_REMOVAL 0x1e -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define MODE_SENSE_10 0x5a -#define MODE_SELECT_10 0x55 -#define READ_CD 0xbe - - -/* ATAPI sense keys (mostly copied from scsi.h). */ - -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define ABORTED_COMMAND 0x0b -#define MISCOMPARE 0x0e - -/* We want some additional flags for cd-rom drives. - To save space in the ide_drive_t struct, use some fields which - doesn't make sense for cd-roms -- `bios_sect' and `bios_head'. */ - -/* Configuration flags. These describe the capabilities of the drive. - They generally do not change after initialization, unless we learn - more about the drive from stuff failing. */ -struct ide_cd_config_flags { - __u8 drq_interrupt : 1; /* Device sends an interrupt when ready - for a packet command. */ - __u8 no_doorlock : 1; /* Drive cannot lock the door. */ -#if ! STANDARD_ATAPI - __u8 no_playaudio12: 1; /* The PLAYAUDIO12 command is not supported. */ - - __u8 no_lba_toc : 1; /* Drive cannot return TOC info in LBA format. */ - __u8 playmsf_uses_bcd : 1; /* Drive uses BCD in PLAYAUDIO_MSF. */ - __u8 old_readcd : 1; /* Drive uses old READ CD opcode. */ - __u8 vertos_lossage: 1; /* Drive is a Vertos 300, - and likes to speak BCD. */ -#endif /* not STANDARD_ATAPI */ - __u8 reserved : 1; -}; -#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_sect)) - - -/* State flags. These give information about the current state of the - drive, and will change during normal operation. */ -struct ide_cd_state_flags { - __u8 media_changed : 1; /* Driver has noticed a media change. */ - __u8 toc_valid : 1; /* Saved TOC information is current. */ - __u8 door_locked : 1; /* We think that the drive door is locked. */ - __u8 eject_on_close: 1; /* Drive should eject when device is closed. */ - __u8 reserved : 4; -}; -#define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head)) - - -#define SECTOR_BUFFER_SIZE CD_FRAMESIZE - - - -/**************************************************************************** - * Routines to read and write data from/to the drive, using - * the routines input_ide_data() and output_ide_data() from ide.c. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ - - -static inline -void cdrom_in_bytes (ide_drive_t *drive, void *buffer, uint bytecount) -{ - ++bytecount; - ide_input_data (drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - { - insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); - } -} - - -static inline -void cdrom_out_bytes (ide_drive_t *drive, void *buffer, uint bytecount) -{ - ++bytecount; - ide_output_data (drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - { - outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); - } -} - - - -/**************************************************************************** - * Descriptions of ATAPI error codes. - */ - -#define ARY_LEN(a) ((sizeof(a) / sizeof(a[0]))) - -#if VERBOSE_IDE_CD_ERRORS - -/* From Table 124 of the ATAPI 1.2 spec. */ - -char *sense_key_texts[16] = { - "No sense data", - "Recovered error", - "Not ready", - "Medium error", - "Hardware error", - "Illegal request", - "Unit attention", - "Data protect", - "(reserved)", - "(reserved)", - "(reserved)", - "Aborted command", - "(reserved)", - "(reserved)", - "Miscompare", - "(reserved)", -}; - - -/* From Table 125 of the ATAPI 1.2 spec. */ - -struct { - short asc_ascq; - char *text; -} sense_data_texts[] = { - { 0x0000, "No additional sense information" }, - { 0x0011, "Audio play operation in progress" }, - { 0x0012, "Audio play operation paused" }, - { 0x0013, "Audio play operation successfully completed" }, - { 0x0014, "Audio play operation stopped due to error" }, - { 0x0015, "No current audio status to return" }, - - { 0x0200, "No seek complete" }, - - { 0x0400, "Logical unit not ready - cause not reportable" }, - { 0x0401, "Logical unit not ready - in progress (sic) of becoming ready" }, - { 0x0402, "Logical unit not ready - initializing command required" }, - { 0x0403, "Logical unit not ready - manual intervention required" }, - - { 0x0600, "No reference position found" }, - - { 0x0900, "Track following error" }, - { 0x0901, "Tracking servo failure" }, - { 0x0902, "Focus servo failure" }, - { 0x0903, "Spindle servo failure" }, - - { 0x1100, "Unrecovered read error" }, - { 0x1106, "CIRC unrecovered error" }, - - { 0x1500, "Random positioning error" }, - { 0x1501, "Mechanical positioning error" }, - { 0x1502, "Positioning error detected by read of medium" }, - - { 0x1700, "Recovered data with no error correction applied" }, - { 0x1701, "Recovered data with retries" }, - { 0x1702, "Recovered data with positive head offset" }, - { 0x1703, "Recovered data with negative head offset" }, - { 0x1704, "Recovered data with retries and/or CIRC applied" }, - { 0x1705, "Recovered data using previous sector ID" }, - - { 0x1800, "Recovered data with error correction applied" }, - { 0x1801, "Recovered data with error correction and retries applied" }, - { 0x1802, "Recovered data - the data was auto-reallocated" }, - { 0x1803, "Recovered data with CIRC" }, - { 0x1804, "Recovered data with L-EC" }, - { 0x1805, "Recovered data - recommend reassignment" }, - { 0x1806, "Recovered data - recommend rewrite" }, - - { 0x1a00, "Parameter list length error" }, - - { 0x2000, "Invalid command operation code" }, - - { 0x2100, "Logical block address out of range" }, - - { 0x2400, "Invalid field in command packet" }, - - { 0x2600, "Invalid field in parameter list" }, - { 0x2601, "Parameter not supported" }, - { 0x2602, "Parameter value invalid" }, - { 0x2603, "Threshold parameters not supported" }, - - { 0x2800, "Not ready to ready transition, medium may have changed" }, - - { 0x2900, "Power on, reset or bus device reset occurred" }, - - { 0x2a00, "Parameters changed" }, - { 0x2a01, "Mode parameters changed" }, - - { 0x3000, "Incompatible medium installed" }, - { 0x3001, "Cannot read medium - unknown format" }, - { 0x3002, "Cannot read medium - incompatible format" }, - - { 0x3700, "Rounded parameter" }, - - { 0x3900, "Saving parameters not supported" }, - - { 0x3a00, "Medium not present" }, - - { 0x3f00, "ATAPI CD-ROM drive operating conditions have changed" }, - { 0x3f01, "Microcode has been changed" }, - { 0x3f02, "Changed operating definition" }, - { 0x3f03, "Inquiry data has changed" }, - - { 0x4000, "Diagnostic failure on component (ASCQ)" }, - - { 0x4400, "Internal ATAPI CD-ROM drive failure" }, - - { 0x4e00, "Overlapped commands attempted" }, - - { 0x5300, "Media load or eject failed" }, - { 0x5302, "Medium removal prevented" }, - - { 0x5700, "Unable to recover table of contents" }, - - { 0x5a00, "Operator request or state change input (unspecified)" }, - { 0x5a01, "Operator medium removal request" }, - - { 0x5b00, "Threshold condition met" }, - - { 0x5c00, "Status change" }, - - { 0x6300, "End of user area encountered on this track" }, - - { 0x6400, "Illegal mode for this track" }, - - { 0xbf00, "Loss of streaming" }, -}; -#endif - - - -/**************************************************************************** - * Generic packet command support and error handling routines. - */ - - -static -void cdrom_analyze_sense_data (ide_drive_t *drive, - struct atapi_request_sense *reqbuf, - struct packet_command *failed_command) -{ - /* Don't print not ready or unit attention errors for READ_SUBCHANNEL. - Workman (and probably other programs) uses this command to poll - the drive, and we don't want to fill the syslog with useless errors. */ - if (failed_command && - failed_command->c[0] == SCMD_READ_SUBCHANNEL && - (reqbuf->sense_key == NOT_READY || reqbuf->sense_key == UNIT_ATTENTION)) - return; - -#if VERBOSE_IDE_CD_ERRORS - { - int i; - char *s; - char buf[80]; - - printk ("ATAPI device %s:\n", drive->name); - - printk (" Error code: 0x%02x\n", reqbuf->error_code); - - if (reqbuf->sense_key >= 0 && - reqbuf->sense_key < ARY_LEN (sense_key_texts)) - s = sense_key_texts[reqbuf->sense_key]; - else - s = "(bad sense key)"; - - printk (" Sense key: 0x%02x - %s\n", reqbuf->sense_key, s); - - if (reqbuf->asc == 0x40) { - sprintf (buf, "Diagnostic failure on component 0x%02x", reqbuf->ascq); - s = buf; - } - - else { - int lo, hi; - int key = (reqbuf->asc << 8); - if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) - key |= reqbuf->ascq; - - lo = 0; - hi = ARY_LEN (sense_data_texts); - s = NULL; - - while (hi > lo) { - int mid = (lo + hi) / 2; - if (sense_data_texts[mid].asc_ascq == key) { - s = sense_data_texts[mid].text; - break; - } - else if (sense_data_texts[mid].asc_ascq > key) - hi = mid; - else - lo = mid+1; - } - } - - if (s == NULL) { - if (reqbuf->asc > 0x80) - s = "(vendor-specific error)"; - else - s = "(reserved error code)"; - } - - printk (" Additional sense data: 0x%02x, 0x%02x - %s\n", - reqbuf->asc, reqbuf->ascq, s); - - if (failed_command != NULL) { - printk (" Failed packet command: "); - for (i=0; i<sizeof (failed_command->c); i++) - printk ("%02x ", failed_command->c[i]); - printk ("\n"); - } - - if (reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->sense_key_specific[0] & 0x80) != 0) - { - printk (" Error in %s byte %d", - (reqbuf->sense_key_specific[0] & 0x40) != 0 - ? "command packet" - : "command data", - (reqbuf->sense_key_specific[1] << 8) + - reqbuf->sense_key_specific[2]); - - if ((reqbuf->sense_key_specific[0] & 0x40) != 0) - { - printk (" bit %d", reqbuf->sense_key_specific[0] & 0x07); - } - - printk ("\n"); - } - } - -#else - - /* Suppress printing unit attention and `in progress of becoming ready' - errors when we're not being verbose. */ - - if (reqbuf->sense_key == UNIT_ATTENTION || - (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 || - reqbuf->asc == 0x3a))) - return; - - printk ("%s: code: 0x%02x key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", - drive->name, - reqbuf->error_code, reqbuf->sense_key, reqbuf->asc, reqbuf->ascq); -#endif -} - - -/* Fix up a possibly partially-processed request so that we can - start it over entirely, or even put it back on the request queue. */ -static void restore_request (struct request *rq) -{ - if (rq->buffer != rq->bh->b_data) - { - int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; - rq->buffer = rq->bh->b_data; - rq->nr_sectors += n; - rq->sector -= n; - } - rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; -} - - -static void cdrom_queue_request_sense (ide_drive_t *drive, - struct semaphore *sem, - struct atapi_request_sense *reqbuf, - struct packet_command *failed_command) -{ - struct request *rq; - struct packet_command *pc; - int len; - - /* If the request didn't explicitly specify where to put the sense data, - use the statically allocated structure. */ - if (reqbuf == NULL) - reqbuf = &drive->cdrom_info.sense_data; - - /* Make up a new request to retrieve sense information. */ - - pc = &HWIF(drive)->request_sense_pc; - memset (pc, 0, sizeof (*pc)); - - /* The request_sense structure has an odd number of (16-bit) words, - which won't work well with 32-bit transfers. However, we don't care - about the last two bytes, so just truncate the structure down - to an even length. */ - len = sizeof (*reqbuf) / 4; - len *= 4; - - pc->c[0] = REQUEST_SENSE; - pc->c[4] = len; - pc->buffer = (char *)reqbuf; - pc->buflen = len; - pc->sense_data = (struct atapi_request_sense *)failed_command; - - /* stuff the sense request in front of our current request */ - - rq = &HWIF(drive)->request_sense_request; - ide_init_drive_cmd (rq); - rq->cmd = REQUEST_SENSE_COMMAND; - rq->buffer = (char *)pc; - rq->sem = sem; - (void) ide_do_drive_cmd (drive, rq, ide_preempt); -} - - -static void cdrom_end_request (int uptodate, ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - - /* The code in blk.h can screw us up on error recovery if the block - size is larger than 1k. Fix that up here. */ - if (!uptodate && rq->bh != 0) - { - int adj = rq->current_nr_sectors - 1; - rq->current_nr_sectors -= adj; - rq->sector += adj; - } - - if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) - { - struct packet_command *pc = (struct packet_command *)rq->buffer; - cdrom_analyze_sense_data (drive, - (struct atapi_request_sense *)(pc->buffer - pc->c[4]), - (struct packet_command *)pc->sense_data); - } - - ide_end_request (uptodate, HWGROUP(drive)); -} - - -/* Mark that we've seen a media change, and invalidate our internal - buffers. */ -static void cdrom_saw_media_change (ide_drive_t *drive) -{ - CDROM_STATE_FLAGS (drive)->media_changed = 1; - CDROM_STATE_FLAGS (drive)->toc_valid = 0; - drive->cdrom_info.nsectors_buffered = 0; -} - - -/* Returns 0 if the request should be continued. - Returns 1 if the request was ended. */ -static int cdrom_decode_status (ide_drive_t *drive, int good_stat, int *stat_ret) -{ - struct request *rq = HWGROUP(drive)->rq; - int stat, err, sense_key, cmd; - - /* Check for errors. */ - stat = GET_STAT(); - *stat_ret = stat; - - if (OK_STAT (stat, good_stat, BAD_R_STAT)) - return 0; - - /* Got an error. */ - err = IN_BYTE (IDE_ERROR_REG); - sense_key = err >> 4; - - if (rq == NULL) - printk ("%s : missing request in cdrom_decode_status\n", drive->name); - else - { - cmd = rq->cmd; - - if (cmd == REQUEST_SENSE_COMMAND) - { - /* We got an error trying to get sense info from the drive - (probably while trying to recover from a former error). - Just give up. */ - - struct packet_command *pc = (struct packet_command *)rq->buffer; - pc->stat = 1; - cdrom_end_request (1, drive); - ide_error (drive, "request sense failure", stat); - return 1; - } - - else if (cmd == PACKET_COMMAND) - { - /* All other functions, except for READ. */ - - struct packet_command *pc = (struct packet_command *)rq->buffer; - struct semaphore *sem = NULL; - - /* Check for tray open. */ - if (sense_key == NOT_READY) - { - cdrom_saw_media_change (drive); - - /* Print an error message to the syslog. - Exception: don't print anything if this is a read subchannel - command. This is 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) - printk ("%s : tray open or drive not ready\n", drive->name); - } - - /* Check for media change. */ - else if (sense_key == UNIT_ATTENTION) - { - cdrom_saw_media_change (drive); - printk ("%s: media changed\n", drive->name); - } - - /* Otherwise, print an error. */ - else - { - ide_dump_status (drive, "packet command error", stat); - } - - /* Set the error flag and complete the request. - Then, if we have a CHECK CONDITION status, queue a request - sense command. We must be careful, though: we don't want - the thread in cdrom_queue_packet_command to wake up until - the request sense has completed. We do this by transferring - the semaphore from the packet command request to the - request sense request. */ - - if ((stat & ERR_STAT) != 0) - { - sem = rq->sem; - rq->sem = NULL; - } - - pc->stat = 1; - cdrom_end_request (1, drive); - - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, sem, pc->sense_data, pc); - } - - else - { - /* Handle errors from READ requests. */ - - /* Check for tray open. */ - if (sense_key == NOT_READY) - { - cdrom_saw_media_change (drive); - - /* Fail the request. */ - printk ("%s : tray open\n", drive->name); - cdrom_end_request (0, drive); - } - - /* Check for media change. */ - else if (sense_key == UNIT_ATTENTION) - { - cdrom_saw_media_change (drive); - - /* Arrange to retry the request. - But be sure to give up if we've retried too many times. */ - if (++rq->errors > ERROR_MAX) - { - cdrom_end_request (0, drive); - } - } - /* No point in retrying after an illegal request or - data protect error.*/ - else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT) - { - ide_dump_status (drive, "command error", stat); - cdrom_end_request (0, drive); - } - - /* If there were other errors, go to the default handler. */ - else if ((err & ~ABRT_ERR) != 0) - { - ide_error (drive, "cdrom_decode_status", stat); - return 1; - } - - /* Else, abort if we've racked up too many retries. */ - else if ((++rq->errors > ERROR_MAX)) - { - cdrom_end_request (0, drive); - } - - /* If we got a CHECK_CONDITION status, queue a request sense - command. */ - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, NULL, NULL, NULL); - } - } - - /* Retry, or handle the next request. */ - return 1; -} - - -/* Set up the device registers for transferring a packet command on DEV, - expecting to later transfer XFERLEN bytes. HANDLER is the routine - which actually transfers the command to the drive. If this is a - drq_interrupt device, this routine will arrange for HANDLER to be - called when the interrupt from the drive arrives. Otherwise, HANDLER - will be called immediately after the drive is prepared for the transfer. */ - -static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, - ide_handler_t *handler) -{ - /* Wait for the controller to be idle. */ - if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1; - - /* Set up the controller registers. */ - OUT_BYTE (0, IDE_FEATURE_REG); - OUT_BYTE (0, IDE_NSECTOR_REG); - OUT_BYTE (0, IDE_SECTOR_REG); - - OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG); - OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG); - OUT_BYTE (drive->ctl, IDE_CONTROL_REG); - - if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) - { - ide_set_handler (drive, handler, WAIT_CMD); - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ - } - else - { - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ - (*handler) (drive); - } - - return 0; -} - - -/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. - The device registers must have already been prepared - by cdrom_start_packet_command. - HANDLER is the interrupt handler to call when the command completes - or there's data ready. */ -static int cdrom_transfer_packet_command (ide_drive_t *drive, - char *cmd_buf, int cmd_len, - ide_handler_t *handler) -{ - if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) - { - /* Here we should have been called after receiving an interrupt - from the device. DRQ should how be set. */ - int stat_dum; - - /* Check for errors. */ - 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)) return 1; - } - - /* Arm the interrupt handler. */ - ide_set_handler (drive, handler, WAIT_CMD); - - /* Send the command to the device. */ - cdrom_out_bytes (drive, cmd_buf, cmd_len); - - return 0; -} - - - -/**************************************************************************** - * Block read functions. - */ - -/* - * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector - * buffer. Once the first sector is added, any subsequent sectors are - * assumed to be continuous (until the buffer is cleared). For the first - * sector added, SECTOR is its sector number. (SECTOR is then ignored until - * the buffer is cleared.) - */ -static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector, - int sectors_to_transfer) -{ - struct cdrom_info *info = &drive->cdrom_info; - - /* Number of sectors to read into the buffer. */ - int sectors_to_buffer = MIN (sectors_to_transfer, - (SECTOR_BUFFER_SIZE >> SECTOR_BITS) - - info->nsectors_buffered); - - char *dest; - - /* If we don't yet have a sector buffer, try to allocate one. - If we can't get one atomically, it's not fatal -- we'll just throw - the data away rather than caching it. */ - if (info->sector_buffer == NULL) - { - info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE, GFP_ATOMIC); - - /* If we couldn't get a buffer, don't try to buffer anything... */ - if (info->sector_buffer == NULL) - sectors_to_buffer = 0; - } - - /* If this is the first sector in the buffer, remember its number. */ - if (info->nsectors_buffered == 0) - info->sector_buffered = sector; - - /* Read the data into the buffer. */ - dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE; - while (sectors_to_buffer > 0) - { - cdrom_in_bytes (drive, dest, SECTOR_SIZE); - --sectors_to_buffer; - --sectors_to_transfer; - ++info->nsectors_buffered; - dest += SECTOR_SIZE; - } - - /* Throw away any remaining data. */ - while (sectors_to_transfer > 0) - { - char dum[SECTOR_SIZE]; - cdrom_in_bytes (drive, dum, sizeof (dum)); - --sectors_to_transfer; - } -} - - -/* - * Check the contents of the interrupt reason register from the cdrom - * and attempt to recover if there are problems. Returns 0 if everything's - * ok; nonzero if the request has been terminated. - */ -static inline -int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason) -{ - ireason &= 3; - if (ireason == 2) return 0; - - if (ireason == 0) - { - /* Whoops... The drive is expecting to receive data from us! */ - printk ("%s: cdrom_read_intr: " - "Drive wants to transfer data the wrong way!\n", - drive->name); - - /* Throw some data at the drive so it doesn't hang - and quit this request. */ - while (len > 0) - { - int dum = 0; - cdrom_out_bytes (drive, &dum, sizeof (dum)); - len -= sizeof (dum); - } - } - - else - { - /* Drive wants a command packet, or invalid ireason... */ - printk ("%s: cdrom_read_intr: bad interrupt reason %d\n", - drive->name, ireason); - } - - cdrom_end_request (0, drive); - return -1; -} - - -/* - * Interrupt routine. Called when a read request has completed. - */ -static void cdrom_read_intr (ide_drive_t *drive) -{ - int stat; - int ireason, len, sectors_to_transfer, nskip; - - struct request *rq = HWGROUP(drive)->rq; - - /* Check for errors. */ - if (cdrom_decode_status (drive, 0, &stat)) 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); - - /* If DRQ is clear, the command has completed. */ - if ((stat & DRQ_STAT) == 0) - { - /* If we're not done filling the current buffer, complain. - Otherwise, complete the command normally. */ - if (rq->current_nr_sectors > 0) - { - printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n", - drive->name, rq->current_nr_sectors); - cdrom_end_request (0, drive); - } - else - cdrom_end_request (1, drive); - - return; - } - - /* Check that the drive is expecting to do the same thing that we are. */ - if (cdrom_read_check_ireason (drive, len, ireason)) return; - - /* Assume that the drive will always provide data in multiples of at least - SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */ - if ((len % SECTOR_SIZE) != 0) - { - printk ("%s: cdrom_read_intr: Bad transfer size %d\n", - drive->name, len); - printk (" This drive is not supported by this version of the driver\n"); - cdrom_end_request (0, drive); - return; - } - - /* The number of sectors we need to read from the drive. */ - sectors_to_transfer = len / SECTOR_SIZE; - - /* First, figure out if we need to bit-bucket any of the leading sectors. */ - nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)), - sectors_to_transfer); - - while (nskip > 0) - { - /* We need to throw away a sector. */ - char dum[SECTOR_SIZE]; - cdrom_in_bytes (drive, dum, sizeof (dum)); - - --rq->current_nr_sectors; - --nskip; - --sectors_to_transfer; - } - - /* Now loop while we still have data to read from the drive. */ - while (sectors_to_transfer > 0) - { - int this_transfer; - - /* If we've filled the present buffer but there's another chained - buffer after it, move on. */ - if (rq->current_nr_sectors == 0 && - rq->nr_sectors > 0) - cdrom_end_request (1, drive); - - /* If the buffers are full, cache the rest of the data in our - internal buffer. */ - if (rq->current_nr_sectors == 0) - { - cdrom_buffer_sectors (drive, rq->sector, sectors_to_transfer); - sectors_to_transfer = 0; - } - else - { - /* Transfer data to the buffers. - Figure out how many sectors we can transfer - to the current buffer. */ - this_transfer = MIN (sectors_to_transfer, - rq->current_nr_sectors); - - /* Read this_transfer sectors into the current buffer. */ - while (this_transfer > 0) - { - cdrom_in_bytes (drive, rq->buffer, SECTOR_SIZE); - rq->buffer += SECTOR_SIZE; - --rq->nr_sectors; - --rq->current_nr_sectors; - ++rq->sector; - --this_transfer; - --sectors_to_transfer; - } - } - } - - /* Done moving data! - Wait for another interrupt. */ - ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD); -} - - -/* - * Try to satisfy some of the current read request from our cached data. - * Returns nonzero if the request has been completed, zero otherwise. - */ -static int cdrom_read_from_buffer (ide_drive_t *drive) -{ - struct cdrom_info *info = &drive->cdrom_info; - struct request *rq = HWGROUP(drive)->rq; - - /* Can't do anything if there's no buffer. */ - if (info->sector_buffer == NULL) return 0; - - /* Loop while this request needs data and the next block is present - in our cache. */ - while (rq->nr_sectors > 0 && - rq->sector >= info->sector_buffered && - rq->sector < info->sector_buffered + info->nsectors_buffered) - { - if (rq->current_nr_sectors == 0) - cdrom_end_request (1, drive); - - memcpy (rq->buffer, - info->sector_buffer + - (rq->sector - info->sector_buffered) * SECTOR_SIZE, - SECTOR_SIZE); - rq->buffer += SECTOR_SIZE; - --rq->current_nr_sectors; - --rq->nr_sectors; - ++rq->sector; - } - - /* If we've satisfied the current request, terminate it successfully. */ - if (rq->nr_sectors == 0) - { - cdrom_end_request (1, drive); - return -1; - } - - /* Move on to the next buffer if needed. */ - if (rq->current_nr_sectors == 0) - cdrom_end_request (1, drive); - - /* If this condition does not hold, then the kluge i use to - represent the number of sectors to skip at the start of a transfer - will fail. I think that this will never happen, but let's be - paranoid and check. */ - if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) && - (rq->sector % SECTORS_PER_FRAME) != 0) - { - printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", - drive->name, rq->sector); - cdrom_end_request (0, drive); - return -1; - } - - return 0; -} - - - -/* - * Routine to send a read packet command to the drive. - * This is usually called directly from cdrom_start_read. - * However, for drq_interrupt devices, it is called from an interrupt - * when the drive is ready to accept the command. - */ -static void cdrom_start_read_continuation (ide_drive_t *drive) -{ - struct packet_command pc; - struct request *rq = HWGROUP(drive)->rq; - - int nsect, sector, nframes, frame, nskip; - - /* Number of sectors to transfer. */ - nsect = rq->nr_sectors; - - /* Starting sector. */ - sector = rq->sector; - - /* If the requested sector doesn't start on a cdrom block boundary, - we must adjust the start of the transfer so that it does, - and remember to skip the first few sectors. If the CURRENT_NR_SECTORS - field is larger than the size of the buffer, it will mean that - we're to skip a number of sectors equal to the amount by which - CURRENT_NR_SECTORS is larger than the buffer size. */ - nskip = (sector % SECTORS_PER_FRAME); - if (nskip > 0) - { - /* Sanity check... */ - if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS)) - { - printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n", - drive->name, rq->current_nr_sectors); - cdrom_end_request (0, drive); - return; - } - - sector -= nskip; - nsect += nskip; - rq->current_nr_sectors += nskip; - } - - /* Convert from sectors to cdrom blocks, rounding up the transfer - length if needed. */ - nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME; - frame = sector / SECTORS_PER_FRAME; - - /* Largest number of frames was can transfer at once is 64k-1. */ - nframes = MIN (nframes, 65535); - - /* Set up the command */ - memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = READ_10; - pc.c[7] = (nframes >> 8); - pc.c[8] = (nframes & 0xff); -#ifdef __alpha__ - stl_u (htonl (frame), (unsigned int *) &pc.c[2]); -#else - *(int *)(&pc.c[2]) = htonl (frame); -#endif - - /* Send the command to the drive and return. */ - (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), - &cdrom_read_intr); -} - - -/* - * Start a read request from the CD-ROM. - */ -static void cdrom_start_read (ide_drive_t *drive, unsigned int block) -{ - struct request *rq = HWGROUP(drive)->rq; - int minor = MINOR (rq->rq_dev); - - /* If the request is relative to a partition, fix it up to refer to the - absolute address. */ - if ((minor & PARTN_MASK) != 0) { - rq->sector = block; - minor &= ~PARTN_MASK; - rq->rq_dev = MKDEV (MAJOR(rq->rq_dev), minor); - } - - /* We may be retrying this request after an error. - Fix up any weirdness which might be present in the request packet. */ - restore_request (rq); - - /* Satisfy whatever we can of this request from our cached sector. */ - if (cdrom_read_from_buffer (drive)) - return; - - /* Clear the local sector buffer. */ - drive->cdrom_info.nsectors_buffered = 0; - - /* Start sending the read request to the drive. */ - cdrom_start_packet_command (drive, 32768, cdrom_start_read_continuation); -} - - - - -/**************************************************************************** - * Execute all other packet commands. - */ - -/* Forward declarations. */ -static int -cdrom_lockdoor (ide_drive_t *drive, int lockflag, - struct atapi_request_sense *reqbuf); - - - -/* Interrupt routine for packet command completion. */ -static void cdrom_pc_intr (ide_drive_t *drive) -{ - int ireason, len, stat, thislen; - struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; - - /* Check for errors. */ - if (cdrom_decode_status (drive, 0, &stat)) 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); - - /* If DRQ is clear, the command has completed. - Complain if we still have data left to transfer. */ - if ((stat & DRQ_STAT) == 0) - { - /* Some of the trailing request sense fields are optional, and - some drives don't send them. Sigh. */ - if (pc->c[0] == REQUEST_SENSE && pc->buflen > 0 && pc->buflen <= 5) { - while (pc->buflen > 0) { - *pc->buffer++ = 0; - --pc->buflen; - } - } - - if (pc->buflen == 0) - cdrom_end_request (1, drive); - else - { - printk ("%s: cdrom_pc_intr: data underrun %d\n", - drive->name, pc->buflen); - pc->stat = 1; - cdrom_end_request (1, drive); - } - return; - } - - /* Figure out how much data to transfer. */ - thislen = pc->buflen; - if (thislen < 0) thislen = -thislen; - if (thislen > len) thislen = len; - - /* The drive wants to be written to. */ - if ((ireason & 3) == 0) - { - /* Check that we want to write. */ - if (pc->buflen > 0) - { - printk ("%s: cdrom_pc_intr: Drive wants to transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } - - /* Transfer the data. */ - cdrom_out_bytes (drive, pc->buffer, thislen); - - /* If we haven't moved enough data to satisfy the drive, - add some padding. */ - while (len > thislen) - { - int dum = 0; - cdrom_out_bytes (drive, &dum, sizeof (dum)); - len -= sizeof (dum); - } - - /* Keep count of how much data we've moved. */ - pc->buffer += thislen; - pc->buflen += thislen; - } - - /* Same drill for reading. */ - else if ((ireason & 3) == 2) - { - /* Check that we want to read. */ - if (pc->buflen < 0) - { - printk ("%s: cdrom_pc_intr: Drive wants to transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } - - /* Transfer the data. */ - cdrom_in_bytes (drive, pc->buffer, thislen); - - /* If we haven't moved enough data to satisfy the drive, - add some padding. */ - while (len > thislen) - { - int dum = 0; - cdrom_in_bytes (drive, &dum, sizeof (dum)); - len -= sizeof (dum); - } - - /* Keep count of how much data we've moved. */ - pc->buffer += thislen; - pc->buflen -= thislen; - } - - else - { - printk ("%s: cdrom_pc_intr: The drive appears confused (ireason = 0x%2x)\n", - drive->name, ireason); - pc->stat = 1; - } - - /* Now we wait for another interrupt. */ - ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD); -} - - -static void cdrom_do_pc_continuation (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; - - /* Send the command to the drive and return. */ - cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c), &cdrom_pc_intr); -} - - -static void cdrom_do_packet_command (ide_drive_t *drive) -{ - int len; - struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; - - len = pc->buflen; - if (len < 0) len = -len; - - pc->stat = 0; - - /* Start sending the command to the drive. */ - cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); -} - -#ifndef MACH -/* Sleep for TIME jiffies. - Not to be called from an interrupt handler. */ -static -void cdrom_sleep (int time) -{ - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + time; - schedule (); -} -#endif - -static -int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) -{ - struct atapi_request_sense my_reqbuf; - int retries = 10; - struct request req; - - /* If our caller has not provided a place to stick any sense data, - use our own area. */ - if (pc->sense_data == NULL) - pc->sense_data = &my_reqbuf; - pc->sense_data->sense_key = 0; - - /* Start of retry loop. */ - do { - ide_init_drive_cmd (&req); - req.cmd = PACKET_COMMAND; - req.buffer = (char *)pc; - (void) ide_do_drive_cmd (drive, &req, ide_wait); - - if (pc->stat != 0) - { - /* The request failed. Retry if it was due to a unit attention status - (usually means media was changed). */ - struct atapi_request_sense *reqbuf = pc->sense_data; - - if (reqbuf->sense_key == UNIT_ATTENTION) - ; - - /* Also retry if the drive is in the process of loading a disk. - This time, however, wait a little between retries to give - the drive time. */ - else if (reqbuf->sense_key == NOT_READY && reqbuf->asc == 4) - { - cdrom_sleep (HZ); - } - - /* Otherwise, don't retry. */ - else - retries = 0; - - --retries; - } - - /* End of retry loop. */ - } while (pc->stat != 0 && retries >= 0); - - - /* Return an error if the command failed. */ - if (pc->stat != 0) - return -EIO; - - else - { - /* The command succeeded. If it was anything other than a request sense, - eject, or door lock command, and we think that the door is presently - unlocked, lock it again. (The door was probably unlocked via - an explicit CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && - (pc->c[0] != REQUEST_SENSE && - pc->c[0] != ALLOW_MEDIUM_REMOVAL && - pc->c[0] != START_STOP)) - { - (void) cdrom_lockdoor (drive, 1, NULL); - } - return 0; - } -} - - - -/**************************************************************************** - * drive_cmd handling. - * - * Most of the functions accessed via drive_cmd are not valid for ATAPI - * devices. Only attempt to execute those which actually should be valid. - */ - -static -void cdrom_do_drive_cmd (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - byte *args = rq->buffer; - - if (args) - { -#if 0 /* This bit isn't done yet... */ - if (args[0] == WIN_SETFEATURES && - (args[2] == 0x66 || args[2] == 0xcc || args[2] == 0x02 || - args[2] == 0xdd || args[2] == 0x5d)) - { - OUT_BYTE (args[2], io_base + IDE_FEATURE_OFFSET); - <send cmd> - } - else -#endif - { - printk ("%s: Unsupported drive command %02x %02x %02x\n", - drive->name, args[0], args[1], args[2]); - rq->errors = 1; - } - } - - cdrom_end_request (1, drive); -} - - - -/**************************************************************************** - * cdrom driver request routine. - */ - -void ide_do_rw_cdrom (ide_drive_t *drive, unsigned long block) -{ - struct request *rq = HWGROUP(drive)->rq; - - if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND) - cdrom_do_packet_command (drive); - - else if (rq -> cmd == RESET_DRIVE_COMMAND) - { - cdrom_end_request (1, drive); - ide_do_reset (drive); - return; - } - - else if (rq -> cmd == IDE_DRIVE_CMD) - cdrom_do_drive_cmd (drive); - - else if (rq -> cmd != READ) - { - printk ("ide-cd: bad cmd %d\n", rq -> cmd); - cdrom_end_request (0, drive); - } - else - cdrom_start_read (drive, block); -} - - - -/**************************************************************************** - * Ioctl handling. - * - * Routines which queue packet commands take as a final argument a pointer - * to an atapi_request_sense struct. If execution of the command results - * in an error with a CHECK CONDITION status, this structure will be filled - * with the results of the subsequent request sense command. The pointer - * can also be NULL, in which case no sense information is returned. - */ - -#if ! STANDARD_ATAPI -static -int bin2bcd (int x) -{ - return (x%10) | ((x/10) << 4); -} - - -static -int bcd2bin (int x) -{ - return (x >> 4) * 10 + (x & 0x0f); -} -#endif /* not STANDARD_ATAPI */ - - -static inline -void lba_to_msf (int lba, byte *m, byte *s, byte *f) -{ - lba += CD_BLOCK_OFFSET; - lba &= 0xffffff; /* negative lbas use only 24 bits */ - *m = lba / (CD_SECS * CD_FRAMES); - lba %= (CD_SECS * CD_FRAMES); - *s = lba / CD_FRAMES; - *f = lba % CD_FRAMES; -} - - -static inline -int msf_to_lba (byte m, byte s, byte f) -{ - return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_BLOCK_OFFSET; -} - - -static int -cdrom_check_status (ide_drive_t *drive, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - - pc.sense_data = reqbuf; - pc.c[0] = TEST_UNIT_READY; - - return cdrom_queue_packet_command (drive, &pc); -} - - -/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ -static int -cdrom_lockdoor (ide_drive_t *drive, int lockflag, - struct atapi_request_sense *reqbuf) -{ - struct atapi_request_sense my_reqbuf; - int stat; - struct packet_command pc; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - /* If the drive cannot lock the door, just pretend. */ - if (CDROM_CONFIG_FLAGS (drive)->no_doorlock) - stat = 0; - else - { - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = ALLOW_MEDIUM_REMOVAL; - pc.c[4] = (lockflag != 0); - stat = cdrom_queue_packet_command (drive, &pc); - } - - if (stat == 0) - CDROM_STATE_FLAGS (drive)->door_locked = lockflag; - else - { - /* If we got an illegal field error, the drive - probably cannot lock the door. */ - if (reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x24) - { - printk ("%s: door locking not supported\n", drive->name); - CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; - stat = 0; - CDROM_STATE_FLAGS (drive)->door_locked = lockflag; - } - } - return stat; -} - - -/* Eject the disk if EJECTFLAG is 0. - If EJECTFLAG is 1, try to reload the disk. */ -static int -cdrom_eject (ide_drive_t *drive, int ejectflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = START_STOP; - pc.c[4] = 2 + (ejectflag != 0); - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_pause (ide_drive_t *drive, int pauseflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PAUSE_RESUME; - pc.c[8] = !pauseflag; - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_startstop (ide_drive_t *drive, int startflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = START_STOP; - pc.c[1] = 1; - pc.c[4] = startflag; - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, - struct atapi_request_sense *reqbuf) -{ - struct { - unsigned lba; - unsigned blocklen; - } capbuf; - - int stat; - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = READ_CAPACITY; - pc.buffer = (char *)&capbuf; - pc.buflen = sizeof (capbuf); - - stat = cdrom_queue_packet_command (drive, &pc); - if (stat == 0) - { - *capacity = ntohl (capbuf.lba); - } - - return stat; -} - - -static int -cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, - int format, char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - pc.c[0] = SCMD_READ_TOC; - pc.c[6] = trackno; - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - pc.c[9] = (format << 6); - if (msf_flag) pc.c[1] = 2; - return cdrom_queue_packet_command (drive, &pc); -} - - -/* Try to read the entire TOC for the disk into our internal buffer. */ -static int -cdrom_read_toc (ide_drive_t *drive, - struct atapi_request_sense *reqbuf) -{ - int msf_flag; - int stat, ntracks, i; - struct atapi_toc *toc = drive->cdrom_info.toc; - struct { - struct atapi_toc_header hdr; - struct atapi_toc_entry ent; - } ms_tmp; - - if (toc == NULL) - { - /* Try to allocate space. */ - toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), - GFP_KERNEL); - drive->cdrom_info.toc = toc; - } - - if (toc == NULL) - { - printk ("%s: No cdrom TOC buffer!\n", drive->name); - return -EIO; - } - - /* Check to see if the existing data is still valid. - If it is, just return. */ - if (CDROM_STATE_FLAGS (drive)->toc_valid) - (void) cdrom_check_status (drive, NULL); - - if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0; - -#if STANDARD_ATAPI - msf_flag = 0; -#else /* not STANDARD_ATAPI */ - /* Some drives can't return TOC data in LBA format. */ - msf_flag = (CDROM_CONFIG_FLAGS (drive)->no_lba_toc); -#endif /* not STANDARD_ATAPI */ - - /* First read just the header, so we know how long the TOC is. */ - stat = cdrom_read_tocentry (drive, 0, msf_flag, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + - sizeof (struct atapi_toc_entry), - reqbuf); - if (stat) return stat; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->vertos_lossage) - { - toc->hdr.first_track = bcd2bin (toc->hdr.first_track); - toc->hdr.last_track = bcd2bin (toc->hdr.last_track); - /* hopefully the length is not BCD, too ;-| */ - } -#endif /* not STANDARD_ATAPI */ - - ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; - if (ntracks <= 0) return -EIO; - if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; - - /* Now read the whole schmeer. */ - stat = cdrom_read_tocentry (drive, 0, msf_flag, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + - (ntracks+1) * sizeof (struct atapi_toc_entry), - reqbuf); - if (stat) return stat; - toc->hdr.toc_length = ntohs (toc->hdr.toc_length); - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->vertos_lossage) - { - toc->hdr.first_track = bcd2bin (toc->hdr.first_track); - toc->hdr.last_track = bcd2bin (toc->hdr.last_track); - /* hopefully the length is not BCD, too ;-| */ - } -#endif /* not STANDARD_ATAPI */ - - for (i=0; i<=ntracks; i++) - { -#if ! STANDARD_ATAPI - if (msf_flag) - { - if (CDROM_CONFIG_FLAGS (drive)->vertos_lossage) - { - toc->ent[i].track = bcd2bin (toc->ent[i].track); - toc->ent[i].addr.msf.m = bcd2bin (toc->ent[i].addr.msf.m); - toc->ent[i].addr.msf.s = bcd2bin (toc->ent[i].addr.msf.s); - toc->ent[i].addr.msf.f = bcd2bin (toc->ent[i].addr.msf.f); - } - toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.m, - toc->ent[i].addr.msf.s, - toc->ent[i].addr.msf.f); - } - else -#endif /* not STANDARD_ATAPI */ - toc->ent[i].addr.lba = ntohl (toc->ent[i].addr.lba); - } - - /* Read the multisession information. */ - stat = cdrom_read_tocentry (drive, 0, msf_flag, 1, - (char *)&ms_tmp, sizeof (ms_tmp), - reqbuf); - if (stat) return stat; -#if ! STANDARD_ATAPI - if (msf_flag) - toc->last_session_lba = msf_to_lba (ms_tmp.ent.addr.msf.m, - ms_tmp.ent.addr.msf.s, - ms_tmp.ent.addr.msf.f); - else -#endif /* not STANDARD_ATAPI */ - toc->last_session_lba = ntohl (ms_tmp.ent.addr.lba); - - toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); - - /* Now try to get the total cdrom capacity. */ - stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); - if (stat) toc->capacity = 0x1fffff; - - HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] - = toc->capacity * SECTORS_PER_FRAME; - drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; - - /* Remember that we've read this stuff. */ - CDROM_STATE_FLAGS (drive)->toc_valid = 1; - - return 0; -} - - -static int -cdrom_read_subchannel (ide_drive_t *drive, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - pc.c[0] = SCMD_READ_SUBCHANNEL; - pc.c[2] = 0x40; /* request subQ data */ - pc.c[3] = 0x01; /* Format 1: current position */ - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - - -/* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */ -static int -cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - pc.c[0] = MODE_SENSE_10; - pc.c[2] = pageno | (modeflag << 6); - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = - buflen; - pc.c[0] = MODE_SELECT_10; - pc.c[1] = 0x10; - pc.c[2] = pageno; - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_play_lba_range_play12 (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PLAYAUDIO12; -#ifdef __alpha__ - stq_u(((long) htonl (lba_end - lba_start) << 32) | htonl(lba_start), - (unsigned long *) &pc.c[2]); -#else - *(int *)(&pc.c[2]) = htonl (lba_start); - *(int *)(&pc.c[6]) = htonl (lba_end - lba_start); -#endif - - return cdrom_queue_packet_command (drive, &pc); -} - - -#if ! STANDARD_ATAPI -static int -cdrom_play_lba_range_msf (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PLAYAUDIO_MSF; - lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); - lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); - - if (CDROM_CONFIG_FLAGS (drive)->playmsf_uses_bcd) - { - pc.c[3] = bin2bcd (pc.c[3]); - pc.c[4] = bin2bcd (pc.c[4]); - pc.c[5] = bin2bcd (pc.c[5]); - pc.c[6] = bin2bcd (pc.c[6]); - pc.c[7] = bin2bcd (pc.c[7]); - pc.c[8] = bin2bcd (pc.c[8]); - } - - return cdrom_queue_packet_command (drive, &pc); -} -#endif /* not STANDARD_ATAPI */ - - -static int -cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - /* This is rather annoying. - My NEC-260 won't recognize group 5 commands such as PLAYAUDIO12; - the only way to get it to play more than 64k of blocks at once - seems to be the PLAYAUDIO_MSF command. However, the parameters - the NEC 260 wants for the PLAYMSF command are incompatible with - the new version of the spec. - - So what i'll try is this. First try for PLAYAUDIO12. If it works, - great. Otherwise, if the drive reports an illegal command code, - try PLAYAUDIO_MSF using the NEC 260-style bcd parameters. */ - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->no_playaudio12) - return cdrom_play_lba_range_msf (drive, lba_start, lba_end, reqbuf); - else -#endif /* not STANDARD_ATAPI */ - { - int stat; - struct atapi_request_sense my_reqbuf; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - stat = cdrom_play_lba_range_play12 (drive, lba_start, lba_end, reqbuf); - if (stat == 0) return 0; - -#if ! STANDARD_ATAPI - /* It failed. Try to find out why. */ - if (reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x20) - { - /* The drive didn't recognize the command. - Retry with the MSF variant. */ - printk ("%s: Drive does not support PLAYAUDIO12; " - "trying PLAYAUDIO_MSF\n", drive->name); - CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1; - CDROM_CONFIG_FLAGS (drive)->playmsf_uses_bcd = 1; - return cdrom_play_lba_range_msf (drive, lba_start, lba_end, reqbuf); - } -#endif /* not STANDARD_ATAPI */ - - /* Failed for some other reason. Give up. */ - return stat; - } -} - - -/* Play audio starting at LBA LBA_START and finishing with the - LBA before LBA_END. */ -static int -cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - int i, stat; - struct atapi_request_sense my_reqbuf; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - /* Some drives, will, for certain audio cds, - give an error if you ask them to play the entire cd using the - values which are returned in the TOC. The play will succeed, however, - if the ending address is adjusted downwards by a few frames. */ - for (i=0; i<75; i++) - { - stat = cdrom_play_lba_range_1 (drive, lba_start, lba_end, reqbuf); - - if (stat == 0 || - !(reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x24)) - return stat; - - --lba_end; - if (lba_end <= lba_start) break; - } - - return stat; -} - - -static -int cdrom_get_toc_entry (ide_drive_t *drive, int track, - struct atapi_toc_entry **ent, - struct atapi_request_sense *reqbuf) -{ - int stat, ntracks; - struct atapi_toc *toc; - - /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, reqbuf); - if (stat) return stat; - - toc = drive->cdrom_info.toc; - - /* Check validity of requested track number. */ - ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; - if (track == CDROM_LEADOUT) - *ent = &toc->ent[ntracks]; - else if (track < toc->hdr.first_track || - track > toc->hdr.last_track) - return -EINVAL; - else - *ent = &toc->ent[track - toc->hdr.first_track]; - - return 0; -} - - -static int -cdrom_read_block (ide_drive_t *drive, int format, int lba, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - struct atapi_request_sense my_reqbuf; - int stat; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->old_readcd) - pc.c[0] = 0xd4; - else -#endif /* not STANDARD_ATAPI */ - pc.c[0] = READ_CD; - - pc.c[1] = (format << 2); -#ifdef __alpha__ - stl_u(htonl (lba), (unsigned int *) &pc.c[2]); -#else - *(int *)(&pc.c[2]) = htonl (lba); -#endif - pc.c[8] = 1; /* one block */ - pc.c[9] = 0x10; - - stat = cdrom_queue_packet_command (drive, &pc); - -#if ! STANDARD_ATAPI - /* If the drive doesn't recognize the READ CD opcode, retry the command - with an older opcode for that command. */ - if (stat && reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x20 && - CDROM_CONFIG_FLAGS (drive)->old_readcd == 0) - { - printk ("%s: Drive does not recognize READ_CD; trying opcode 0xd4\n", - drive->name); - CDROM_CONFIG_FLAGS (drive)->old_readcd = 1; - return cdrom_read_block (drive, format, lba, buf, buflen, reqbuf); - } -#endif /* not STANDARD_ATAPI */ - - return stat; -} - - -int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode, - struct file *file, unsigned int cmd, unsigned long arg) -{ - switch (cmd) - { - case CDROMEJECT: - { - int stat; - - if (drive->usage > 1) - return -EBUSY; - - stat = cdrom_lockdoor (drive, 0, NULL); - if (stat) return stat; - - return cdrom_eject (drive, 0, NULL); - } - - case CDROMEJECT_SW: - { - CDROM_STATE_FLAGS (drive)->eject_on_close = arg; - return 0; - } - - case CDROMPAUSE: - return cdrom_pause (drive, 1, NULL); - - case CDROMRESUME: - return cdrom_pause (drive, 0, NULL); - - case CDROMSTART: - return cdrom_startstop (drive, 1, NULL); - - case CDROMSTOP: - { - int stat; - - stat = cdrom_startstop (drive, 0, NULL); - if (stat) return stat; - /* pit says the Dolphin needs this. */ - return cdrom_eject (drive, 1, NULL); - } - - case CDROMPLAYMSF: - { - struct cdrom_msf msf; - int stat, lba_start, lba_end; - - stat = verify_area (VERIFY_READ, (void *)arg, sizeof (msf)); - if (stat) return stat; - - memcpy_fromfs (&msf, (void *) arg, sizeof(msf)); - - lba_start = msf_to_lba (msf.cdmsf_min0, msf.cdmsf_sec0, - msf.cdmsf_frame0); - lba_end = msf_to_lba (msf.cdmsf_min1, msf.cdmsf_sec1, - msf.cdmsf_frame1) + 1; - - if (lba_end <= lba_start) return -EINVAL; - - return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); - } - - /* Like just about every other Linux cdrom driver, we ignore the - index part of the request here. */ - case CDROMPLAYTRKIND: - { - int stat, lba_start, lba_end; - struct cdrom_ti ti; - struct atapi_toc_entry *first_toc, *last_toc; - - stat = verify_area (VERIFY_READ, (void *)arg, sizeof (ti)); - if (stat) return stat; - - memcpy_fromfs (&ti, (void *) arg, sizeof(ti)); - - stat = cdrom_get_toc_entry (drive, ti.cdti_trk0, &first_toc, NULL); - if (stat) return stat; - stat = cdrom_get_toc_entry (drive, ti.cdti_trk1, &last_toc, NULL); - if (stat) return stat; - - if (ti.cdti_trk1 != CDROM_LEADOUT) ++last_toc; - lba_start = first_toc->addr.lba; - lba_end = last_toc->addr.lba; - - if (lba_end <= lba_start) return -EINVAL; - - return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); - } - - case CDROMREADTOCHDR: - { - int stat; - struct cdrom_tochdr tochdr; - struct atapi_toc *toc; - - stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (tochdr)); - if (stat) return stat; - - /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = drive->cdrom_info.toc; - tochdr.cdth_trk0 = toc->hdr.first_track; - tochdr.cdth_trk1 = toc->hdr.last_track; - - memcpy_tofs ((void *) arg, &tochdr, sizeof (tochdr)); - - return stat; - } - - case CDROMREADTOCENTRY: - { - int stat; - struct cdrom_tocentry tocentry; - struct atapi_toc_entry *toce; - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (tocentry)); - if (stat) return stat; - stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (tocentry)); - if (stat) return stat; - - memcpy_fromfs (&tocentry, (void *) arg, sizeof (tocentry)); - - stat = cdrom_get_toc_entry (drive, tocentry.cdte_track, &toce, NULL); - if (stat) return stat; - - tocentry.cdte_ctrl = toce->control; - tocentry.cdte_adr = toce->adr; - - if (tocentry.cdte_format == CDROM_MSF) - { - /* convert to MSF */ - lba_to_msf (toce->addr.lba, - &tocentry.cdte_addr.msf.minute, - &tocentry.cdte_addr.msf.second, - &tocentry.cdte_addr.msf.frame); - } - else - tocentry.cdte_addr.lba = toce->addr.lba; - - memcpy_tofs ((void *) arg, &tocentry, sizeof (tocentry)); - - return stat; - } - - case CDROMSUBCHNL: - { - struct atapi_cdrom_subchnl scbuf; - int stat, abs_lba, rel_lba; - struct cdrom_subchnl subchnl; - - stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (subchnl)); - if (stat) return stat; - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (subchnl)); - if (stat) return stat; - - memcpy_fromfs (&subchnl, (void *) arg, sizeof (subchnl)); - - stat = cdrom_read_subchannel (drive, (char *)&scbuf, sizeof (scbuf), - NULL); - if (stat) return stat; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->vertos_lossage) - { - abs_lba = msf_to_lba (bcd2bin (scbuf.acdsc_absaddr.msf.minute), - bcd2bin (scbuf.acdsc_absaddr.msf.second), - bcd2bin (scbuf.acdsc_absaddr.msf.frame)); - rel_lba = msf_to_lba (bcd2bin (scbuf.acdsc_reladdr.msf.minute), - bcd2bin (scbuf.acdsc_reladdr.msf.second), - bcd2bin (scbuf.acdsc_reladdr.msf.frame)); - scbuf.acdsc_trk = bcd2bin (scbuf.acdsc_trk); - } - else -#endif /* not STANDARD_ATAPI */ - { - abs_lba = ntohl (scbuf.acdsc_absaddr.lba); - rel_lba = ntohl (scbuf.acdsc_reladdr.lba); - } - - if (subchnl.cdsc_format == CDROM_MSF) - { - lba_to_msf (abs_lba, - &subchnl.cdsc_absaddr.msf.minute, - &subchnl.cdsc_absaddr.msf.second, - &subchnl.cdsc_absaddr.msf.frame); - lba_to_msf (rel_lba, - &subchnl.cdsc_reladdr.msf.minute, - &subchnl.cdsc_reladdr.msf.second, - &subchnl.cdsc_reladdr.msf.frame); - } - else - { - subchnl.cdsc_absaddr.lba = abs_lba; - subchnl.cdsc_reladdr.lba = rel_lba; - } - - subchnl.cdsc_audiostatus = scbuf.acdsc_audiostatus; - subchnl.cdsc_ctrl = scbuf.acdsc_ctrl; - subchnl.cdsc_trk = scbuf.acdsc_trk; - subchnl.cdsc_ind = scbuf.acdsc_ind; - - memcpy_tofs ((void *) arg, &subchnl, sizeof (subchnl)); - - return stat; - } - - case CDROMVOLCTRL: - { - struct cdrom_volctrl volctrl; - char buffer[24], mask[24]; - int stat; - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (volctrl)); - if (stat) return stat; - memcpy_fromfs (&volctrl, (void *) arg, sizeof (volctrl)); - - stat = cdrom_mode_sense (drive, 0x0e, 0, buffer, sizeof (buffer),NULL); - if (stat) return stat; - stat = cdrom_mode_sense (drive, 0x0e, 1, mask , sizeof (buffer),NULL); - if (stat) return stat; - - buffer[1] = buffer[2] = 0; - - buffer[17] = volctrl.channel0 & mask[17]; - buffer[19] = volctrl.channel1 & mask[19]; - buffer[21] = volctrl.channel2 & mask[21]; - buffer[23] = volctrl.channel3 & mask[23]; - - return cdrom_mode_select (drive, 0x0e, buffer, sizeof (buffer), NULL); - } - - case CDROMVOLREAD: - { - struct cdrom_volctrl volctrl; - char buffer[24]; - int stat; - - stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (volctrl)); - if (stat) return stat; - - stat = cdrom_mode_sense (drive, 0x0e, 0, buffer, sizeof (buffer), NULL); - if (stat) return stat; - - volctrl.channel0 = buffer[17]; - volctrl.channel1 = buffer[19]; - volctrl.channel2 = buffer[21]; - volctrl.channel3 = buffer[23]; - - memcpy_tofs ((void *) arg, &volctrl, sizeof (volctrl)); - - return 0; - } - - case CDROMMULTISESSION: - { - struct cdrom_multisession ms_info; - struct atapi_toc *toc; - int stat; - - stat = verify_area (VERIFY_READ, (void *)arg, sizeof (ms_info)); - if (stat) return stat; - stat = verify_area (VERIFY_WRITE, (void *)arg, sizeof (ms_info)); - if (stat) return stat; - - memcpy_fromfs (&ms_info, (void *)arg, sizeof (ms_info)); - - /* Make sure the TOC information is valid. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = drive->cdrom_info.toc; - - if (ms_info.addr_format == CDROM_MSF) - lba_to_msf (toc->last_session_lba, - &ms_info.addr.msf.minute, - &ms_info.addr.msf.second, - &ms_info.addr.msf.frame); - - else if (ms_info.addr_format == CDROM_LBA) - ms_info.addr.lba = toc->last_session_lba; - - else - return -EINVAL; - - ms_info.xa_flag = toc->xa_flag; - - memcpy_tofs ((void *)arg, &ms_info, sizeof (ms_info)); - - return 0; - } - - /* Read 2352 byte blocks from audio tracks. */ - case CDROMREADAUDIO: - { - int stat, lba; - struct atapi_toc *toc; - struct cdrom_read_audio ra; - char buf[CD_FRAMESIZE_RAW]; - - /* Make sure the TOC is up to date. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = drive->cdrom_info.toc; - - stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra)); - if (stat) return stat; - - memcpy_fromfs (&ra, (void *)arg, sizeof (ra)); - - if (ra.nframes < 0 || ra.nframes > toc->capacity) - return -EINVAL; - else if (ra.nframes == 0) - return 0; - - stat = verify_area (VERIFY_WRITE, (char *)ra.buf, - ra.nframes * CD_FRAMESIZE_RAW); - if (stat) return stat; - - if (ra.addr_format == CDROM_MSF) - lba = msf_to_lba (ra.addr.msf.minute, ra.addr.msf.second, - ra.addr.msf.frame); - - else if (ra.addr_format == CDROM_LBA) - lba = ra.addr.lba; - - else - return -EINVAL; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - - while (ra.nframes > 0) - { - stat = cdrom_read_block (drive, 1, lba, buf, - CD_FRAMESIZE_RAW, NULL); - if (stat) return stat; - memcpy_tofs (ra.buf, buf, CD_FRAMESIZE_RAW); - ra.buf += CD_FRAMESIZE_RAW; - --ra.nframes; - ++lba; - } - - return 0; - } - - case CDROMREADMODE1: - case CDROMREADMODE2: - { - struct cdrom_msf msf; - int blocksize, format, stat, lba; - struct atapi_toc *toc; - char buf[CD_FRAMESIZE_RAW0]; - - if (cmd == CDROMREADMODE1) - { - blocksize = CD_FRAMESIZE; - format = 2; - } - else - { - blocksize = CD_FRAMESIZE_RAW0; - format = 3; - } - - stat = verify_area (VERIFY_READ, (char *)arg, sizeof (msf)); - if (stat) return stat; - stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize); - if (stat) return stat; - - memcpy_fromfs (&msf, (void *)arg, sizeof (msf)); - - lba = msf_to_lba (msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0); - - /* Make sure the TOC is up to date. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = drive->cdrom_info.toc; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - - stat = cdrom_read_block (drive, format, lba, buf, blocksize, NULL); - if (stat) return stat; - - memcpy_tofs ((char *)arg, buf, blocksize); - return 0; - } - -#if 0 /* Doesn't work reliably yet. */ - case CDROMRESET: - { - struct request req; - ide_init_drive_cmd (&req); - req.cmd = RESET_DRIVE_COMMAND; - return ide_do_drive_cmd (drive, &req, ide_wait); - } -#endif - - -#ifdef TEST - case 0x1234: - { - int stat; - struct packet_command pc; - int len, lena; - - memset (&pc, 0, sizeof (pc)); - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c)); - if (stat) return stat; - memcpy_fromfs (&pc.c, (void *) arg, sizeof (pc.c)); - arg += sizeof (pc.c); - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len)); - if (stat) return stat; - memcpy_fromfs (&len, (void *) arg , sizeof (len)); - arg += sizeof (len); - - if (len > 0) { - stat = verify_area (VERIFY_WRITE, (void *) arg, len); - if (stat) return stat; - } - - lena = len; - if (lena < 0) lena = 0; - - { - char buf[lena]; - if (len > 0) { - pc.buflen = len; - pc.buffer = buf; - } - - stat = cdrom_queue_packet_command (drive, &pc); - - if (len > 0) - memcpy_tofs ((void *)arg, buf, len); - } - - return stat; - } -#endif - - default: - return -EPERM; - } - -} - - - -/**************************************************************************** - * Other driver requests (open, close, check media change). - */ - -int ide_cdrom_check_media_change (ide_drive_t *drive) -{ - int retval; - - (void) cdrom_check_status (drive, NULL); - - retval = CDROM_STATE_FLAGS (drive)->media_changed; - CDROM_STATE_FLAGS (drive)->media_changed = 0; - - return retval; -} - - -int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive) -{ - /* no write access */ - if (fp->f_mode & 2) - { - --drive->usage; - return -EROFS; - } - - /* If this is the first open, check the drive status. */ - if (drive->usage == 1) - { - int stat; - struct atapi_request_sense my_reqbuf; - my_reqbuf.sense_key = 0; - - /* Get the drive status. */ - stat = cdrom_check_status (drive, &my_reqbuf); - - /* If the tray is open, try to close it. */ - if (stat && my_reqbuf.sense_key == NOT_READY) - { - cdrom_eject (drive, 1, &my_reqbuf); - stat = cdrom_check_status (drive, &my_reqbuf); - } - - /* Return an error if there are still problems. */ - if (stat && my_reqbuf.sense_key != UNIT_ATTENTION) - { - --drive->usage; - return -ENXIO; - } - - /* Now lock the door. */ - (void) cdrom_lockdoor (drive, 1, &my_reqbuf); - - /* And try to read the TOC information now. */ - (void) cdrom_read_toc (drive, &my_reqbuf); - } - - return 0; -} - - -/* - * Close down the device. Invalidate all cached blocks. - */ - -void ide_cdrom_release (struct inode *inode, struct file *file, ide_drive_t *drive) -{ - if (drive->usage == 0) - { - invalidate_buffers (inode->i_rdev); - - /* Unlock the door. */ - (void) cdrom_lockdoor (drive, 0, NULL); - - /* Do an eject if we were requested to do so. */ - if (CDROM_STATE_FLAGS (drive)->eject_on_close) - (void) cdrom_eject (drive, 0, NULL); - } -} - - - -/**************************************************************************** - * Device initialization. - */ - -void ide_cdrom_setup (ide_drive_t *drive) -{ - blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] = CD_FRAMESIZE; - - drive->special.all = 0; - drive->ready_stat = 0; - - CDROM_STATE_FLAGS (drive)->media_changed = 0; - CDROM_STATE_FLAGS (drive)->toc_valid = 0; - CDROM_STATE_FLAGS (drive)->door_locked = 0; - - /* Turn this off by default, since many people don't like it. */ - CDROM_STATE_FLAGS (drive)->eject_on_close= 0; - -#if NO_DOOR_LOCKING - CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; -#else - CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0; -#endif - - if (drive->id != NULL) { - CDROM_CONFIG_FLAGS (drive)->drq_interrupt = - ((drive->id->config & 0x0060) == 0x20); - } else { - CDROM_CONFIG_FLAGS (drive)->drq_interrupt = 0; - } - -#if ! STANDARD_ATAPI - CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 0; - CDROM_CONFIG_FLAGS (drive)->old_readcd = 0; - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 0; - CDROM_CONFIG_FLAGS (drive)->playmsf_uses_bcd = 0; - CDROM_CONFIG_FLAGS (drive)->vertos_lossage = 0; - - if (drive->id != NULL) { - /* Accommodate some broken drives... */ - if (strcmp (drive->id->model, "CD220E") == 0 || - strcmp (drive->id->model, "CD") == 0) /* Creative Labs */ - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - - else if (strcmp (drive->id->model, "TO-ICSLYAL") == 0 || /* Acer CD525E */ - strcmp (drive->id->model, "OTI-SCYLLA") == 0) - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - - /* I don't know who makes this. - Francesco Messineo <sidera@ccii.unipi.it> says this one's broken too. */ - else if (strcmp (drive->id->model, "DCI-2S10") == 0) - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - - else if (strcmp (drive->id->model, "CDA26803I SE") == 0) /* Aztech */ - { - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - - /* This drive _also_ does not implement PLAYAUDIO12 correctly. */ - CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1; - } - - /* Vertos 300. - There seem to be at least two different, incompatible versions - of this drive floating around. Luckily, they appear to return their - id strings with different byte orderings. */ - else if (strcmp (drive->id->model, "V003S0DS") == 0) - { - CDROM_CONFIG_FLAGS (drive)->vertos_lossage = 1; - CDROM_CONFIG_FLAGS (drive)->playmsf_uses_bcd = 1; - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - } - else if (strcmp (drive->id->model, "0V300SSD") == 0 || - strcmp (drive->id->model, "V003M0DP") == 0) - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - - /* Vertos 400. */ - else if (strcmp (drive->id->model, "V004E0DT") == 0 || - strcmp (drive->id->model, "0V400ETD") == 0) - CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; - - else if ( strcmp (drive->id->model, "CD-ROM CDU55D") == 0) /*sony cdu55d */ - CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1; - - else if (strcmp (drive->id->model, "CD-ROM CDU55E") == 0) - CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1; - } /* drive-id != NULL */ -#endif /* not STANDARD_ATAPI */ - - drive->cdrom_info.toc = NULL; - drive->cdrom_info.sector_buffer = NULL; - drive->cdrom_info.sector_buffered = 0; - drive->cdrom_info.nsectors_buffered = 0; -} - - - -/* - * TODO: - * CDROM_GET_UPC - * CDROMRESET - * Lock the door when a read request completes successfully and the - * door is not already locked. Also try to reorganize to reduce - * duplicated functionality between read and ioctl paths? - * Establish interfaces for an IDE port driver, and break out the cdrom - * code into a loadable module. - * Support changers. - * Write some real documentation. - */ diff --git a/i386/i386at/gpl/linux/block/ide.c b/i386/i386at/gpl/linux/block/ide.c deleted file mode 100644 index 4b7c5e9..0000000 --- a/i386/i386at/gpl/linux/block/ide.c +++ /dev/null @@ -1,3087 +0,0 @@ -/* - * linux/drivers/block/ide.c Version 5.28 Feb 11, 1996 - * - * Copyright (C) 1994-1996 Linus Torvalds & authors (see below) - */ -#define _IDE_C /* needed by <linux/blk.h> */ - -/* - * 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. - * - * Primary i/f: ide0: major=3; (hda) minor=0; (hdb) minor=64 - * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64 - * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 - * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 - * - * It is easy to extend ide.c to handle more than four interfaces: - * - * Change the MAX_HWIFS constant in ide.h. - * - * Define some new major numbers (in major.h), and insert them into - * the ide_hwif_to_major table in ide.c. - * - * Fill in the extra values for the new interfaces into the two tables - * inside ide.c: default_io_base[] and default_irqs[]. - * - * Create the new request handlers by cloning "do_ide3_request()" - * for each new interface, and add them to the switch statement - * in the ide_init() function in ide.c. - * - * Recompile, create the new /dev/ entries, and it will probably work. - * - * 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@bnr.ca). - * - * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: - * - * Mark Lord (mlord@bnr.ca) (IDE Perf.Pkg) - * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2") - * Petri Mattila (ptjmatti@kruuna.helsinki.fi) (EIDE stuff) - * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) - * - * Maintained by Mark Lord (mlord@bnr.ca): ide.c, ide.h, triton.c, hd.c, .. - * - * 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.0 ALPHA initial code, primary i/f working okay - * Version 1.3 BETA dual i/f on shared irq tested & working! - * Version 1.4 BETA added auto probing for irq(s) - * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms, - * ... - * Version 3.5 correct the bios_cyl field if it's too small - * (linux 1.1.76) (to help fdisk with brain-dead BIOSs) - * Version 3.6 cosmetic corrections to comments and stuff - * (linux 1.1.77) reorganise probing code to make it understandable - * added halfway retry to probing for drive identification - * added "hdx=noprobe" command line option - * allow setting multmode even when identification fails - * Version 3.7 move set_geometry=1 from do_identify() to ide_init() - * increase DRQ_WAIT to eliminate nuisance messages - * wait for DRQ_STAT instead of DATA_READY during probing - * (courtesy of Gary Thomas gary@efland.UU.NET) - * Version 3.8 fixed byte-swapping for confused Mitsumi cdrom drives - * update of ide-cd.c from Scott, allows blocksize=1024 - * cdrom probe fixes, inspired by jprang@uni-duisburg.de - * Version 3.9 don't use LBA if lba_capacity looks funny - * correct the drive capacity calculations - * fix probing for old Seagates without IDE_ALTSTATUS_REG - * fix byte-ordering for some NEC cdrom drives - * Version 3.10 disable multiple mode by default; was causing trouble - * Version 3.11 fix mis-identification of old WD disks as cdroms - * Version 3,12 simplify logic for selecting initial mult_count - * (fixes problems with buggy WD drives) - * Version 3.13 remove excess "multiple mode disabled" messages - * Version 3.14 fix ide_error() handling of BUSY_STAT - * fix byte-swapped cdrom strings (again.. arghh!) - * ignore INDEX bit when checking the ALTSTATUS reg - * Version 3.15 add SINGLE_THREADED flag for use with dual-CMD i/f - * ignore WRERR_STAT for non-write operations - * added vlb_sync support for DC-2000A & others, - * (incl. some Promise chips), courtesy of Frank Gockel - * Version 3.16 convert vlb_32bit and vlb_sync into runtime flags - * add ioctls to get/set VLB flags (HDIO_[SG]ET_CHIPSET) - * rename SINGLE_THREADED to SUPPORT_SERIALIZE, - * add boot flag to "serialize" operation for CMD i/f - * add optional support for DTC2278 interfaces, - * courtesy of andy@cercle.cts.com (Dyan Wile). - * add boot flag to enable "dtc2278" probe - * add probe to avoid EATA (SCSI) interfaces, - * courtesy of neuffer@goofy.zdv.uni-mainz.de. - * Version 4.00 tidy up verify_area() calls - heiko@colossus.escape.de - * add flag to ignore WRERR_STAT for some drives - * courtesy of David.H.West@um.cc.umich.edu - * assembly syntax tweak to vlb_sync - * removeable drive support from scuba@cs.tu-berlin.de - * add transparent support for DiskManager-6.0x "Dynamic - * Disk Overlay" (DDO), most of this is in genhd.c - * eliminate "multiple mode turned off" message at boot - * Version 4.10 fix bug in ioctl for "hdparm -c3" - * fix DM6:DDO support -- now works with LILO, fdisk, ... - * don't treat some naughty WD drives as removeable - * Version 4.11 updated DM6 support using info provided by OnTrack - * Version 5.00 major overhaul, multmode setting fixed, vlb_sync fixed - * added support for 3rd/4th/alternative IDE ports - * created ide.h; ide-cd.c now compiles separate from ide.c - * hopefully fixed infinite "unexpected_intr" from cdroms - * zillions of other changes and restructuring - * somehow reduced overall memory usage by several kB - * probably slowed things down slightly, but worth it - * Version 5.01 AT LAST!! Finally understood why "unexpected_intr" - * was happening at various times/places: whenever the - * ide-interface's ctl_port was used to "mask" the irq, - * it also would trigger an edge in the process of masking - * which would result in a self-inflicted interrupt!! - * (such a stupid way to build a hardware interrupt mask). - * This is now fixed (after a year of head-scratching). - * Version 5.02 got rid of need for {enable,disable}_irq_list() - * Version 5.03 tune-ups, comments, remove "busy wait" from drive resets - * removed PROBE_FOR_IRQS option -- no longer needed - * OOOPS! fixed "bad access" bug for 2nd drive on an i/f - * Version 5.04 changed "ira %d" to "irq %d" in DEBUG message - * added more comments, cleaned up unexpected_intr() - * OOOPS! fixed null pointer problem in ide reset code - * added autodetect for Triton chipset -- no effect yet - * Version 5.05 OOOPS! fixed bug in revalidate_disk() - * OOOPS! fixed bug in ide_do_request() - * added ATAPI reset sequence for cdroms - * Version 5.10 added Bus-Mastered DMA support for Triton Chipset - * some (mostly) cosmetic changes - * Version 5.11 added ht6560b support by malafoss@snakemail.hut.fi - * reworked PCI scanning code - * added automatic RZ1000 detection/support - * added automatic PCI CMD640 detection/support - * added option for VLB CMD640 support - * tweaked probe to find cdrom on hdb with disks on hda,hdc - * Version 5.12 some performance tuning - * added message to alert user to bad /dev/hd[cd] entries - * OOOPS! fixed bug in atapi reset - * driver now forces "serialize" again for all cmd640 chips - * noticed REALLY_SLOW_IO had no effect, moved it to ide.c - * made do_drive_cmd() into public ide_do_drive_cmd() - * Version 5.13 fixed typo ('B'), thanks to houston@boyd.geog.mcgill.ca - * fixed ht6560b support - * Version 5.13b (sss) fix problem in calling ide_cdrom_setup() - * don't bother invalidating nonexistent partitions - * Version 5.14 fixes to cmd640 support.. maybe it works now(?) - * added & tested full EZ-DRIVE support -- don't use LILO! - * don't enable 2nd CMD640 PCI port during init - conflict - * Version 5.15 bug fix in init_cmd640_vlb() - * bug fix in interrupt sharing code - * Version 5.16 ugh.. fix "serialize" support, broken in 5.15 - * remove "Huh?" from cmd640 code - * added qd6580 interface speed select from Colten Edwards - * Version 5.17 kludge around bug in BIOS32 on Intel triton motherboards - * Version 5.18 new CMD640 code, moved to cmd640.c, #include'd for now - * new UMC8672 code, moved to umc8672.c, #include'd for now - * disallow turning on DMA when h/w not capable of DMA - * Version 5.19 fix potential infinite timeout on resets - * extend reset poll into a general purpose polling scheme - * add atapi tape drive support from Gadi Oxman - * simplify exit from _intr routines -- no IDE_DO_REQUEST - * Version 5.20 leave current rq on blkdev request list during I/O - * generalized ide_do_drive_cmd() for tape/cdrom driver use - * Version 5.21 fix nasty cdrom/tape bug (ide_preempt was messed up) - * Version 5.22 fix ide_xlate_1024() to work with/without drive->id - * Version 5.23 miscellaneous touch-ups - * Version 5.24 fix #if's for SUPPORT_CMD640 - * Version 5.25 more touch-ups, fix cdrom resets, ... - * cmd640.c now configs/compiles separate from ide.c - * Version 5.26 keep_settings now maintains the using_dma flag - * fix [EZD] remap message to only output at boot time - * fix "bad /dev/ entry" message to say hdc, not hdc0 - * fix ide_xlate_1024() to respect user specified CHS - * use CHS from partn table if it looks translated - * re-merged flags chipset,vlb_32bit,vlb_sync into io_32bit - * keep track of interface chipset type, when known - * add generic PIO mode "tuneproc" mechanism - * fix cmd640_vlb option - * fix ht6560b support (was completely broken) - * umc8672.c now configures/compiles separate from ide.c - * move dtc2278 support to dtc2278.c - * move ht6560b support to ht6560b.c - * move qd6580 support to qd6580.c - * add ali14xx support in ali14xx.c - * Version 5.27 add [no]autotune parameters to help cmd640 - * move rz1000 support to rz1000.c - * Version 5.28 #include "ide_modes.h" - * fix disallow_unmask: now per-interface "no_unmask" bit - * force io_32bit to be the same on drive pairs of dtc2278 - * improved IDE tape error handling, and tape DMA support - * bugfix in ide_do_drive_cmd() for cdroms + serialize - * - * Some additional driver compile-time options are in ide.h - * - * To do, in likely order of completion: - * - add Promise DC4030VL support from peterd@pnd-pc.demon.co.uk - * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f -*/ - -#if defined (MACH) && !defined (LINUX_IDE_DEBUG) -#undef DEBUG -#endif - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/kernel.h> -#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> - -#include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/segment.h> -#include <asm/io.h> - -#ifdef CONFIG_PCI -#include <linux/bios32.h> -#include <linux/pci.h> -#endif /* CONFIG_PCI */ - -#include "ide.h" -#include "ide_modes.h" - -static ide_hwgroup_t *irq_to_hwgroup [NR_IRQS]; -static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; - -static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168}; -static const byte default_irqs[MAX_HWIFS] = {14, 15, 11, 10}; - -#if (DISK_RECOVERY_TIME > 0) -/* - * For really screwy hardware (hey, at least it *can* be used with Linux) - * we can enforce a minimum delay time between successive operations. - */ -static unsigned long read_timer(void) -{ - unsigned long t, flags; - int i; - - save_flags(flags); - cli(); - t = jiffies * 11932; - outb_p(0, 0x43); - i = inb_p(0x40); - i |= inb(0x40) << 8; - restore_flags(flags); - return (t - i); -} - -static void set_recovery_timer (ide_hwif_t *hwif) -{ - hwif->last_time = read_timer(); -} -#define SET_RECOVERY_TIMER(drive) set_recovery_timer (drive) - -#else - -#define SET_RECOVERY_TIMER(drive) - -#endif /* DISK_RECOVERY_TIME */ - -/* - * init_ide_data() sets reasonable default values into all fields - * of all instances of the hwifs and drives, but only on the first call. - * Subsequent calls have no effect (they don't wipe out anything). - * - * This routine is normally called at driver initialization time, - * but may also be called MUCH earlier during kernel "command-line" - * parameter processing. As such, we cannot depend on any other parts - * of the kernel (such as memory allocation) to be functioning yet. - * - * This is too bad, as otherwise we could dynamically allocate the - * ide_drive_t structs as needed, rather than always consuming memory - * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. - */ -#define MAGIC_COOKIE 0x12345678 -static void init_ide_data (void) -{ - byte *p; - unsigned int h, unit; - static unsigned long magic_cookie = MAGIC_COOKIE; - - if (magic_cookie != MAGIC_COOKIE) - return; /* already initialized */ - magic_cookie = 0; - - for (h = 0; h < NR_IRQS; ++h) - irq_to_hwgroup[h] = NULL; - - /* bulk initialize hwif & drive info with zeros */ - p = ((byte *) ide_hwifs) + sizeof(ide_hwifs); - do { - *--p = 0; - } while (p > (byte *) ide_hwifs); - - /* fill in any non-zero initial values */ - for (h = 0; h < MAX_HWIFS; ++h) { - ide_hwif_t *hwif = &ide_hwifs[h]; - - hwif->index = h; - hwif->noprobe = (h > 1); - hwif->io_base = default_io_base[h]; - hwif->ctl_port = hwif->io_base ? hwif->io_base+0x206 : 0x000; -#ifdef CONFIG_BLK_DEV_HD - if (hwif->io_base == HD_DATA) - hwif->noprobe = 1; /* may be overriden by ide_setup() */ -#endif /* CONFIG_BLK_DEV_HD */ - hwif->major = ide_hwif_to_major[h]; - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; - hwif->name[2] = 'e'; - hwif->name[3] = '0' + h; -#ifdef CONFIG_BLK_DEV_IDETAPE - hwif->tape_drive = NULL; -#endif /* CONFIG_BLK_DEV_IDETAPE */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - drive->select.all = (unit<<4)|0xa0; - drive->hwif = hwif; - drive->ctl = 0x08; - drive->ready_stat = READY_STAT; - drive->bad_wstat = BAD_W_STAT; - drive->special.b.recalibrate = 1; - drive->special.b.set_geometry = 1; - drive->name[0] = 'h'; - drive->name[1] = 'd'; - drive->name[2] = 'a' + (h * MAX_DRIVES) + unit; - } - } -} - -#if SUPPORT_VLB_SYNC -/* - * Some localbus EIDE interfaces require a special access sequence - * when using 32-bit I/O instructions to transfer data. We call this - * the "vlb_sync" sequence, which consists of three successive reads - * of the sector count register location, with interrupts disabled - * to ensure that the reads all happen together. - */ -static inline void do_vlb_sync (unsigned short port) { - (void) inb (port); - (void) inb (port); - (void) inb (port); -} -#endif /* SUPPORT_VLB_SYNC */ - -/* - * This is used for most PIO data transfers *from* the IDE interface - */ -void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - unsigned short io_base = HWIF(drive)->io_base; - unsigned short data_reg = io_base+IDE_DATA_OFFSET; - byte io_32bit = drive->io_32bit; - - if (io_32bit) { -#if SUPPORT_VLB_SYNC - if (io_32bit & 2) { - cli(); - do_vlb_sync(io_base+IDE_NSECTOR_OFFSET); - insl(data_reg, buffer, wcount); - if (drive->unmask) - sti(); - } else -#endif /* SUPPORT_VLB_SYNC */ - insl(data_reg, buffer, wcount); - } else - insw(data_reg, buffer, wcount<<1); -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - unsigned short io_base = HWIF(drive)->io_base; - unsigned short data_reg = io_base+IDE_DATA_OFFSET; - byte io_32bit = drive->io_32bit; - - if (io_32bit) { -#if SUPPORT_VLB_SYNC - if (io_32bit & 2) { - cli(); - do_vlb_sync(io_base+IDE_NSECTOR_OFFSET); - outsl(data_reg, buffer, wcount); - if (drive->unmask) - sti(); - } else -#endif /* SUPPORT_VLB_SYNC */ - outsl(data_reg, buffer, wcount); - } else - outsw(data_reg, buffer, wcount<<1); -} - -/* - * This should get invoked any time we exit the driver to - * wait for an interrupt response from a drive. handler() points - * at the appropriate code to handle the next interrupt, and a - * timer is started to prevent us from waiting forever in case - * something goes wrong (see the timer_expiry() handler later on). - */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout) -{ - ide_hwgroup_t *hwgroup = HWGROUP(drive); -#ifdef DEBUG - if (hwgroup->handler != NULL) { - printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", - drive->name, hwgroup->handler, handler); - } -#endif - hwgroup->handler = handler; - hwgroup->timer.expires = jiffies + timeout; - add_timer(&(hwgroup->timer)); -} - -/* - * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" - * value for this drive (from its reported identification information). - * - * Returns: 1 if lba_capacity looks sensible - * 0 otherwise - */ -static int lba_capacity_is_ok (struct hd_driveid *id) -{ - unsigned long lba_sects = id->lba_capacity; - unsigned long chs_sects = id->cyls * id->heads * id->sectors; - unsigned long _10_percent = chs_sects / 10; - - /* perform a rough sanity check on lba_sects: within 10% is "okay" */ - if ((lba_sects - chs_sects) < _10_percent) - return 1; /* lba_capacity is good */ - - /* some drives have the word order reversed */ - lba_sects = (lba_sects << 16) | (lba_sects >> 16); - if ((lba_sects - chs_sects) < _10_percent) { - id->lba_capacity = lba_sects; /* fix it */ - return 1; /* lba_capacity is (now) good */ - } - return 0; /* lba_capacity value is bad */ -} - -/* - * current_capacity() returns the capacity (in sectors) of a drive - * according to its current geometry/LBA settings. - */ -static unsigned long current_capacity (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - unsigned long capacity; - - if (!drive->present) - return 0; - if (drive->media != ide_disk) - return 0x7fffffff; /* cdrom or tape */ - /* Determine capacity, and use LBA if the drive properly supports it */ - if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { - drive->select.b.lba = 1; - capacity = id->lba_capacity; - } else { - drive->select.b.lba = 0; - capacity = drive->cyl * drive->head * drive->sect; - } - return (capacity - drive->sect0); -} - -/* - * ide_geninit() is called exactly *once* for each major, from genhd.c, - * at the beginning of the initial partition check for the drives. - */ -static void ide_geninit (struct gendisk *gd) -{ - unsigned int unit; - ide_hwif_t *hwif = gd->real_devices; - - for (unit = 0; unit < gd->nr_real; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; -#ifdef CONFIG_BLK_DEV_IDECD - if (drive->present && drive->media == ide_cdrom) - ide_cdrom_setup(drive); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->present && drive->media == ide_tape) - idetape_setup(drive); -#endif /* CONFIG_BLK_DEV_IDETAPE */ - drive->part[0].nr_sects = current_capacity(drive); - if (!drive->present || drive->media != ide_disk) { - drive->part[0].start_sect = -1; /* skip partition check */ - } - } - /* - * The partition check in genhd.c needs this string to identify - * our minor devices by name for display purposes. - * Note that doing this will prevent us from working correctly - * if ever called a second time for this major (never happens). - */ - gd->real_devices = hwif->drives[0].name; /* name of first drive */ -} - -/* - * init_gendisk() (as opposed to ide_geninit) is called for each major device, - * after probing for drives, to allocate partition tables and other data - * structures needed for the routines in genhd.c. ide_geninit() gets called - * somewhat later, during the partition check. - */ -static void init_gendisk (ide_hwif_t *hwif) -{ - struct gendisk *gd; - unsigned int unit, units, minors; - int *bs; - - /* figure out maximum drive number on the interface */ - for (units = MAX_DRIVES; units > 0; --units) { - if (hwif->drives[units-1].present) - break; - } - minors = units * (1<<PARTN_BITS); - gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); - 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); - - /* cdroms and msdos f/s are examples of non-1024 blocksizes */ - blksize_size[hwif->major] = bs; - for (unit = 0; unit < minors; ++unit) - *bs++ = BLOCK_SIZE; - - for (unit = 0; unit < units; ++unit) - hwif->drives[unit].part = &gd->part[unit << PARTN_BITS]; - - gd->major = hwif->major; /* our major device number */ - gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ - gd->minor_shift = PARTN_BITS; /* num bits for partitions */ - gd->max_p = 1<<PARTN_BITS; /* 1 + max partitions / drive */ - gd->max_nr = units; /* max num real drives */ - gd->nr_real = units; /* current num real drives */ - gd->init = ide_geninit; /* initialization function */ - gd->real_devices= hwif; /* ptr to internal data */ - - gd->next = gendisk_head; /* link new major into list */ - hwif->gd = gendisk_head = gd; -} - -static void do_reset1 (ide_drive_t *, int); /* needed below */ - -#ifdef CONFIG_BLK_DEV_IDEATAPI -/* - * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms - * during an atapi drive reset operation. If the drive has not yet responded, - * and we have not yet hit our maximum waiting time, then the timer is restarted - * for another 50ms. - */ -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); - 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) { - ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); - return; /* continue polling */ - } - hwgroup->poll_timeout = 0; /* end of polling */ - printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat); - do_reset1 (drive, 1); /* do it the old fashioned way */ - } - hwgroup->poll_timeout = 0; /* done polling */ -} -#endif /* CONFIG_BLK_DEV_IDEATAPI */ - -/* - * reset_pollfunc() gets invoked to poll the interface for completion every 50ms - * during an ide reset operation. If the drives have not yet responded, - * and we have not yet hit our maximum waiting time, then the timer is restarted - * for another 50ms. - */ -static void reset_pollfunc (ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = HWGROUP(drive); - ide_hwif_t *hwif = HWIF(drive); - byte tmp; - - if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { - if (jiffies < hwgroup->poll_timeout) { - ide_set_handler (drive, &reset_pollfunc, HZ/20); - return; /* continue polling */ - } - printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); - } else { - printk("%s: reset: ", hwif->name); - if ((tmp = GET_ERR()) == 1) - printk("success\n"); - else { - printk("master: "); - switch (tmp & 0x7f) { - case 1: printk("passed"); - break; - case 2: printk("formatter device error"); - break; - case 3: printk("sector buffer error"); - break; - case 4: printk("ECC circuitry error"); - break; - case 5: printk("controlling MPU error"); - break; - default:printk("error (0x%02x?)", tmp); - } - if (tmp & 0x80) - printk("; slave: failed"); - printk("\n"); - } - } - hwgroup->poll_timeout = 0; /* done polling */ -} - -/* - * do_reset1() attempts to recover a confused drive by resetting it. - * Unfortunately, resetting a disk drive actually resets all devices on - * the same interface, so it can really be thought of as resetting the - * interface rather than resetting the drive. - * - * ATAPI devices have their own reset mechanism which allows them to be - * individually reset without clobbering other devices on the same interface. - * - * Unfortunately, the IDE interface does not generate an interrupt to let - * us know when the reset operation has finished, so we must poll for this. - * Equally poor, though, is the fact that this may a very long time to complete, - * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, - * we set a timer to poll at 50ms intervals. - */ -static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) -{ - unsigned int unit; - unsigned long flags; - ide_hwif_t *hwif = HWIF(drive); - ide_hwgroup_t *hwgroup = HWGROUP(drive); - - save_flags(flags); - cli(); /* Why ? */ - -#ifdef CONFIG_BLK_DEV_IDEATAPI - /* For an ATAPI device, first try an ATAPI SRST. */ - if (drive->media != ide_disk) { - if (!do_not_try_atapi) { - if (!drive->keep_settings) - drive->unmask = 0; - OUT_BYTE (drive->select.all, IDE_SELECT_REG); - udelay (20); - OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); - hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); - restore_flags (flags); - return; - } - } -#endif /* CONFIG_BLK_DEV_IDEATAPI */ - - /* - * First, reset any device state data we were maintaining - * for any of the drives on this interface. - */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *rdrive = &hwif->drives[unit]; - rdrive->special.all = 0; - rdrive->special.b.set_geometry = 1; - rdrive->special.b.recalibrate = 1; - if (OK_TO_RESET_CONTROLLER) - rdrive->mult_count = 0; - if (!rdrive->keep_settings) { - rdrive->using_dma = 0; - rdrive->mult_req = 0; - rdrive->unmask = 0; - } - if (rdrive->mult_req != rdrive->mult_count) - rdrive->special.b.set_multmode = 1; - } - -#if OK_TO_RESET_CONTROLLER - /* - * Note that we also set nIEN while resetting the device, - * to mask unwanted interrupts from the interface during the reset. - * However, due to the design of PC hardware, this will cause an - * immediate interrupt due to the edge transition it produces. - * This single interrupt gives us a "fast poll" for drives that - * recover from reset very quickly, saving us the first 50ms wait time. - */ - OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */ - udelay(5); /* more than enough time */ - OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ - hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &reset_pollfunc, HZ/20); -#endif /* OK_TO_RESET_CONTROLLER */ - - restore_flags (flags); -} - -/* - * ide_do_reset() is the entry point to the drive/interface reset code. - */ -void ide_do_reset (ide_drive_t *drive) -{ - do_reset1 (drive, 0); -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->media == ide_tape) - drive->tape.reset_issued=1; -#endif /* CONFIG_BLK_DEV_IDETAPE */ -} - -/* - * Clean up after success/failure of an explicit drive cmd - */ -void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) -{ - unsigned long flags; - struct request *rq = HWGROUP(drive)->rq; - - if (rq->cmd == IDE_DRIVE_CMD) { - byte *args = (byte *) rq->buffer; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - if (args) { - args[0] = stat; - args[1] = err; - args[2] = IN_BYTE(IDE_NSECTOR_REG); - } - } - save_flags(flags); - cli(); - blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next; - HWGROUP(drive)->rq = NULL; - rq->rq_status = RQ_INACTIVE; - if (rq->sem != NULL) - up(rq->sem); - restore_flags(flags); -} - -/* - * Error reporting, in human readable form (luxurious, but a memory hog). - */ -byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) -{ - unsigned long flags; - byte err = 0; - - save_flags (flags); - sti(); - printk("%s: %s: status=0x%02x", drive->name, msg, stat); -#if FANCY_STATUS_DUMPS - if (drive->media == ide_disk) { - printk(" { "); - if (stat & BUSY_STAT) - printk("Busy "); - else { - if (stat & READY_STAT) printk("DriveReady "); - if (stat & WRERR_STAT) printk("DeviceFault "); - if (stat & SEEK_STAT) printk("SeekComplete "); - if (stat & DRQ_STAT) printk("DataRequest "); - if (stat & ECC_STAT) printk("CorrectedError "); - if (stat & INDEX_STAT) printk("Index "); - if (stat & ERR_STAT) printk("Error "); - } - printk("}"); - } -#endif /* FANCY_STATUS_DUMPS */ - printk("\n"); - if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { - err = GET_ERR(); - printk("%s: %s: error=0x%02x", drive->name, msg, err); -#if FANCY_STATUS_DUMPS - if (drive->media == ide_disk) { - printk(" { "); - if (err & BBD_ERR) printk("BadSector "); - if (err & ECC_ERR) printk("UncorrectableError "); - if (err & ID_ERR) printk("SectorIdNotFound "); - if (err & ABRT_ERR) printk("DriveStatusError "); - if (err & TRK0_ERR) printk("TrackZeroNotFound "); - if (err & MARK_ERR) printk("AddrMarkNotFound "); - printk("}"); - if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { - byte cur = IN_BYTE(IDE_SELECT_REG); - if (cur & 0x40) { /* using LBA? */ - printk(", LBAsect=%ld", (unsigned long) - ((cur&0xf)<<24) - |(IN_BYTE(IDE_HCYL_REG)<<16) - |(IN_BYTE(IDE_LCYL_REG)<<8) - | IN_BYTE(IDE_SECTOR_REG)); - } else { - printk(", CHS=%d/%d/%d", - (IN_BYTE(IDE_HCYL_REG)<<8) + - IN_BYTE(IDE_LCYL_REG), - cur & 0xf, - IN_BYTE(IDE_SECTOR_REG)); - } - if (HWGROUP(drive)->rq) - printk(", sector=%ld", HWGROUP(drive)->rq->sector); - } - } -#endif /* FANCY_STATUS_DUMPS */ - printk("\n"); - } - restore_flags (flags); - return err; -} - -/* - * try_to_flush_leftover_data() is invoked in response to a drive - * unexpectedly having its DRQ_STAT bit set. As an alternative to - * resetting the drive, this routine tries to clear the condition - * by read a sector's worth of data from the drive. Of course, - * this may not help if the drive is *waiting* for data from *us*. - */ -static void try_to_flush_leftover_data (ide_drive_t *drive) -{ - int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; - - while (i > 0) { - unsigned long buffer[16]; - unsigned int wcount = (i > 16) ? 16 : i; - i -= wcount; - ide_input_data (drive, buffer, wcount); - } -} - -/* - * ide_error() takes action based on the error returned by the controller. - */ -void ide_error (ide_drive_t *drive, const char *msg, byte stat) -{ - struct request *rq; - byte err; - - err = ide_dump_status(drive, msg, stat); - if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) - return; - /* retry only "normal" I/O: */ - if (rq->cmd == IDE_DRIVE_CMD || (rq->cmd != READ && rq->cmd != WRITE && drive->media == ide_disk)) - { - rq->errors = 1; - ide_end_drive_cmd(drive, stat, err); - return; - } - if (stat & BUSY_STAT) { /* other bits are useless when BUSY */ - rq->errors |= ERROR_RESET; - } else { - if (drive->media == ide_disk && (stat & ERR_STAT)) { - /* err has different meaning on cdrom and tape */ - if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ - rq->errors = ERROR_MAX; - else if (err & TRK0_ERR) /* help it find track zero */ - rq->errors |= ERROR_RECAL; - } - if ((stat & DRQ_STAT) && rq->cmd != WRITE) - try_to_flush_leftover_data(drive); - } - if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) - rq->errors |= ERROR_RESET; /* Mmmm.. timing problem */ - - if (rq->errors >= ERROR_MAX) { -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->media == ide_tape) { - rq->errors = 0; - idetape_end_request(0, HWGROUP(drive)); - } - else -#endif /* CONFIG_BLK_DEV_IDETAPE */ - ide_end_request(0, HWGROUP(drive)); - } - else { - if ((rq->errors & ERROR_RESET) == ERROR_RESET) { - ++rq->errors; - ide_do_reset(drive); - return; - } else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) - drive->special.b.recalibrate = 1; - ++rq->errors; - } -} - -/* - * read_intr() is the handler for disk read/multread interrupts - */ -static void read_intr (ide_drive_t *drive) -{ - byte stat; - int i; - unsigned int msect, nsect; - struct request *rq; - - if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { - ide_error(drive, "read_intr", stat); - return; - } - msect = drive->mult_count; -read_next: - rq = HWGROUP(drive)->rq; - if (msect) { - if ((nsect = rq->current_nr_sectors) > msect) - nsect = msect; - msect -= nsect; - } else - nsect = 1; - ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); -#ifdef DEBUG - printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", - drive->name, rq->sector, rq->sector+nsect-1, - (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); -#endif - rq->sector += nsect; - rq->buffer += nsect<<9; - rq->errors = 0; - i = (rq->nr_sectors -= nsect); - if ((rq->current_nr_sectors -= nsect) <= 0) - ide_end_request(1, HWGROUP(drive)); - if (i > 0) { - if (msect) - goto read_next; - ide_set_handler (drive, &read_intr, WAIT_CMD); - } -} - -/* - * write_intr() is the handler for disk write interrupts - */ -static void write_intr (ide_drive_t *drive) -{ - byte stat; - int i; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq = hwgroup->rq; - - if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { -#ifdef DEBUG - printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", - drive->name, rq->sector, (unsigned long) rq->buffer, - rq->nr_sectors-1); -#endif - if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) { - rq->sector++; - rq->buffer += 512; - rq->errors = 0; - i = --rq->nr_sectors; - --rq->current_nr_sectors; - if (rq->current_nr_sectors <= 0) - ide_end_request(1, hwgroup); - if (i > 0) { - ide_output_data (drive, rq->buffer, SECTOR_WORDS); - ide_set_handler (drive, &write_intr, WAIT_CMD); - } - return; - } - } - ide_error(drive, "write_intr", stat); -} - -/* - * multwrite() transfers a block of one or more sectors of data to a drive - * as part of a disk multwrite operation. - */ -static void multwrite (ide_drive_t *drive) -{ - struct request *rq = &HWGROUP(drive)->wrq; - unsigned int mcount = drive->mult_count; - - do { - unsigned int nsect = rq->current_nr_sectors; - if (nsect > mcount) - nsect = mcount; - mcount -= nsect; - - ide_output_data(drive, rq->buffer, nsect<<7); -#ifdef DEBUG - printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n", - drive->name, rq->sector, (unsigned long) rq->buffer, - nsect, rq->nr_sectors - nsect); -#endif - if ((rq->nr_sectors -= nsect) <= 0) - break; - if ((rq->current_nr_sectors -= nsect) == 0) { - if ((rq->bh = rq->bh->b_reqnext) != NULL) { - rq->current_nr_sectors = rq->bh->b_size>>9; - rq->buffer = rq->bh->b_data; - } else { - panic("%s: buffer list corrupted\n", drive->name); - break; - } - } else { - rq->buffer += nsect << 9; - } - } while (mcount); -} - -/* - * multwrite_intr() is the handler for disk multwrite interrupts - */ -static void multwrite_intr (ide_drive_t *drive) -{ - byte stat; - int i; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq = &hwgroup->wrq; - - if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { - if (stat & DRQ_STAT) { - if (rq->nr_sectors) { - multwrite(drive); - ide_set_handler (drive, &multwrite_intr, WAIT_CMD); - return; - } - } else { - if (!rq->nr_sectors) { /* all done? */ - rq = hwgroup->rq; - for (i = rq->nr_sectors; i > 0;){ - i -= rq->current_nr_sectors; - ide_end_request(1, hwgroup); - } - return; - } - } - } - ide_error(drive, "multwrite_intr", stat); -} - -/* - * Issue a simple drive command - * The drive must be selected beforehand. - */ -static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) -{ - ide_set_handler (drive, handler, WAIT_CMD); - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - OUT_BYTE(nsect,IDE_NSECTOR_REG); - OUT_BYTE(cmd,IDE_COMMAND_REG); -} - -/* - * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. - */ -static void set_multmode_intr (ide_drive_t *drive) -{ - byte stat = GET_STAT(); - - sti(); - if (OK_STAT(stat,READY_STAT,BAD_STAT)) { - drive->mult_count = drive->mult_req; - } else { - drive->mult_req = drive->mult_count = 0; - drive->special.b.recalibrate = 1; - (void) ide_dump_status(drive, "set_multmode", stat); - } -} - -/* - * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. - */ -static void set_geometry_intr (ide_drive_t *drive) -{ - byte stat = GET_STAT(); - - sti(); - if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - ide_error(drive, "set_geometry_intr", stat); -} - -/* - * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. - */ -static void recal_intr (ide_drive_t *drive) -{ - byte stat = GET_STAT(); - - sti(); - if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - ide_error(drive, "recal_intr", stat); -} - -/* - * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. - */ -static void drive_cmd_intr (ide_drive_t *drive) -{ - byte stat = GET_STAT(); - - sti(); - if (OK_STAT(stat,READY_STAT,BAD_STAT)) - ide_end_drive_cmd (drive, stat, GET_ERR()); - else - ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ -} - -/* - * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT - * commands to a drive. It used to do much more, but has been scaled back. - */ -static inline void do_special (ide_drive_t *drive) -{ - special_t *s = &drive->special; -next: -#ifdef DEBUG - printk("%s: do_special: 0x%02x\n", drive->name, s->all); -#endif - if (s->b.set_geometry) { - s->b.set_geometry = 0; - if (drive->media == ide_disk) { - OUT_BYTE(drive->sect,IDE_SECTOR_REG); - OUT_BYTE(drive->cyl,IDE_LCYL_REG); - OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG); - OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG); - ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr); - } - } else if (s->b.recalibrate) { - s->b.recalibrate = 0; - if (drive->media == ide_disk) { - ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr); - } - } else if (s->b.set_pio) { - ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; - s->b.set_pio = 0; - if (tuneproc != NULL) - tuneproc(drive, drive->pio_req); - goto next; - } else if (s->b.set_multmode) { - s->b.set_multmode = 0; - if (drive->media == ide_disk) { - if (drive->id && drive->mult_req > drive->id->max_multsect) - drive->mult_req = drive->id->max_multsect; - ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr); - } else - drive->mult_req = 0; - } else if (s->all) { - s->all = 0; - printk("%s: bad special flag: 0x%02x\n", drive->name, s->all); - } -} - -/* - * This routine busy-waits for the drive status to be not "busy". - * It then checks the status for all of the "good" bits and none - * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() -- caller should just return. - * - * This routine should get fixed to not hog the cpu during extra long waits.. - * That could be done by busy-waiting for the first jiffy or two, and then - * setting a timer to wake up at half second intervals thereafter, - * until timeout is achieved, before timing out. - */ -int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) -{ - byte stat; - unsigned long flags; - -test: - udelay(1); /* spec allows drive 400ns to change "BUSY" */ - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; /* fast exit for most frequent case */ - if (!(stat & BUSY_STAT)) { - ide_error(drive, "status error", stat); - return 1; - } - - save_flags(flags); - sti(); - timeout += jiffies; - do { - if (!((stat = GET_STAT()) & BUSY_STAT)) { - restore_flags(flags); - goto test; - } - } while (jiffies <= timeout); - - restore_flags(flags); - ide_error(drive, "status timeout", GET_STAT()); - return 1; -} - -/* - * do_rw_disk() issues WIN_{MULT}READ and WIN_{MULT}WRITE commands to a disk, - * using LBA if supported, or CHS otherwise, to address sectors. It also takes - * care of issuing special DRIVE_CMDs. - */ -static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) -{ - unsigned short io_base = HWIF(drive)->io_base; - - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - OUT_BYTE(rq->nr_sectors,io_base+IDE_NSECTOR_OFFSET); - if (drive->select.b.lba) { -#ifdef DEBUG - printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n", - drive->name, (rq->cmd==READ)?"read":"writ", - block, rq->nr_sectors, (unsigned long) rq->buffer); -#endif - OUT_BYTE(block,io_base+IDE_SECTOR_OFFSET); - OUT_BYTE(block>>=8,io_base+IDE_LCYL_OFFSET); - OUT_BYTE(block>>=8,io_base+IDE_HCYL_OFFSET); - OUT_BYTE(((block>>8)&0x0f)|drive->select.all,io_base+IDE_SELECT_OFFSET); - } else { - unsigned int sect,head,cyl,track; - track = block / drive->sect; - sect = block % drive->sect + 1; - OUT_BYTE(sect,io_base+IDE_SECTOR_OFFSET); - head = track % drive->head; - cyl = track / drive->head; - OUT_BYTE(cyl,io_base+IDE_LCYL_OFFSET); - OUT_BYTE(cyl>>8,io_base+IDE_HCYL_OFFSET); - OUT_BYTE(head|drive->select.all,io_base+IDE_SELECT_OFFSET); -#ifdef DEBUG - printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n", - drive->name, (rq->cmd==READ)?"read":"writ", cyl, - head, sect, rq->nr_sectors, (unsigned long) rq->buffer); -#endif - } - if (rq->cmd == READ) { -#ifdef CONFIG_BLK_DEV_TRITON - if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) - return; -#endif /* CONFIG_BLK_DEV_TRITON */ - ide_set_handler(drive, &read_intr, WAIT_CMD); - OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+IDE_COMMAND_OFFSET); - return; - } - if (rq->cmd == WRITE) { -#ifdef CONFIG_BLK_DEV_TRITON - if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) - return; -#endif /* CONFIG_BLK_DEV_TRITON */ - OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, io_base+IDE_COMMAND_OFFSET); - if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk("%s: no DRQ after issuing %s\n", drive->name, - drive->mult_count ? "MULTWRITE" : "WRITE"); - return; - } - if (!drive->unmask) - cli(); - if (drive->mult_count) { - HWGROUP(drive)->wrq = *rq; /* scratchpad */ - ide_set_handler (drive, &multwrite_intr, WAIT_CMD); - multwrite(drive); - } else { - ide_set_handler (drive, &write_intr, WAIT_CMD); - ide_output_data(drive, rq->buffer, SECTOR_WORDS); - } - return; - } - if (rq->cmd == IDE_DRIVE_CMD) { - byte *args = rq->buffer; - if (args) { -#ifdef DEBUG - printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x\n", - drive->name, args[0], args[1], args[2]); -#endif - OUT_BYTE(args[2],io_base+IDE_FEATURE_OFFSET); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return; - } else { - /* - * NULL is actually a valid way of waiting for - * all current requests to be flushed from the queue. - */ -#ifdef DEBUG - printk("%s: DRIVE_CMD (null)\n", drive->name); -#endif - ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); - return; - } - } - printk("%s: bad command: %d\n", drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); -} - -/* - * do_request() initiates handling of a new I/O request - */ -static inline void do_request (ide_hwif_t *hwif, struct request *rq) -{ - unsigned int minor, unit; - unsigned long block, blockend; - ide_drive_t *drive; - - sti(); -#ifdef DEBUG - printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); -#endif - minor = MINOR(rq->rq_dev); - unit = minor >> PARTN_BITS; - if (MAJOR(rq->rq_dev) != hwif->major || unit >= MAX_DRIVES) { - printk("%s: bad device number: %s\n", - hwif->name, kdevname(rq->rq_dev)); - goto kill_rq; - } - drive = &hwif->drives[unit]; -#ifdef DEBUG - if (rq->bh && !buffer_locked(rq->bh)) { - printk("%s: block not locked\n", drive->name); - goto kill_rq; - } -#endif - block = rq->sector; - blockend = block + rq->nr_sectors; - if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { - printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, - (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); - goto kill_rq; - } - block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; -#if FAKE_FDISK_FOR_EZDRIVE - if (block == 0 && drive->remap_0_to_1) - block = 1; /* redirect MBR access to EZ-Drive partn table */ -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive; -#ifdef CONFIG_BLK_DEV_HT6560B - if (hwif->selectproc) - hwif->selectproc (drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ -#if (DISK_RECOVERY_TIME > 0) - while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); -#endif - -#ifdef CONFIG_BLK_DEV_IDETAPE - POLL_HWIF_TAPE_DRIVE; /* macro from ide-tape.h */ -#endif /* CONFIG_BLK_DEV_IDETAPE */ - - OUT_BYTE(drive->select.all,IDE_SELECT_REG); - if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { - printk("%s: drive not ready for command\n", drive->name); - return; - } - - if (!drive->special.all) { -#ifdef CONFIG_BLK_DEV_IDEATAPI - switch (drive->media) { - case ide_disk: - do_rw_disk (drive, rq, block); - return; -#ifdef CONFIG_BLK_DEV_IDECD - case ide_cdrom: - ide_do_rw_cdrom (drive, block); - return; -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - case ide_tape: - if (rq->cmd == IDE_DRIVE_CMD) { - byte *args = (byte *) rq->buffer; - OUT_BYTE(args[2],IDE_FEATURE_REG); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return; - } - idetape_do_request (drive, rq, block); - return; -#endif /* CONFIG_BLK_DEV_IDETAPE */ - - default: - printk("%s: media type %d not supported\n", - drive->name, drive->media); - goto kill_rq; - } -#else - do_rw_disk (drive, rq, block); /* simpler and faster */ - return; -#endif /* CONFIG_BLK_DEV_IDEATAPI */; - } - do_special(drive); - return; -kill_rq: - ide_end_request(0, hwif->hwgroup); -} - -/* - * The driver enables interrupts as much as possible. In order to do this, - * (a) the device-interrupt is always masked before entry, and - * (b) the timeout-interrupt is always disabled before entry. - * - * If we enter here from, say irq14, and then start a new request for irq15, - * (possible with "serialize" option) then we cannot ensure that we exit - * before the irq15 hits us. So, we must be careful not to let this bother us. - * - * Interrupts are still masked (by default) whenever we are exchanging - * data/cmds with a drive, because some drives seem to have very poor - * tolerance for latency during I/O. For devices which don't suffer from - * this problem (most don't), the unmask flag can be set using the "hdparm" - * utility, to permit other interrupts during data/cmd transfers. - */ -void ide_do_request (ide_hwgroup_t *hwgroup) -{ - cli(); /* paranoia */ - if (hwgroup->handler != NULL) { - printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); - return; - } - do { - ide_hwif_t *hwif = hwgroup->hwif; - struct request *rq; - if ((rq = hwgroup->rq) == NULL) { - do { - rq = blk_dev[hwif->major].current_request; - if (rq != NULL && rq->rq_status != RQ_INACTIVE) - goto got_rq; - } while ((hwif = hwif->next) != hwgroup->hwif); - return; /* no work left for this hwgroup */ - } - got_rq: - do_request(hwgroup->hwif = hwif, hwgroup->rq = rq); - cli(); - } while (hwgroup->handler == NULL); -} - -/* - * do_hwgroup_request() invokes ide_do_request() after first masking - * all possible interrupts for the current hwgroup. This prevents race - * conditions in the event that an unexpected interrupt occurs while - * we are in the driver. - * - * Note that when an interrupt is used to reenter the driver, the first level - * handler will already have masked the irq that triggered, but any other ones - * for the hwgroup will still be unmasked. The driver tries to be careful - * about such things. - */ -static void do_hwgroup_request (ide_hwgroup_t *hwgroup) -{ - if (hwgroup->handler == NULL) { - ide_hwif_t *hgif = hwgroup->hwif; - ide_hwif_t *hwif = hgif; - do { - disable_irq(hwif->irq); - } while ((hwif = hwif->next) != hgif); - ide_do_request (hwgroup); - do { - enable_irq(hwif->irq); - } while ((hwif = hwif->next) != hgif); - } -} - -static void do_ide0_request (void) /* invoked with cli() */ -{ - do_hwgroup_request (ide_hwifs[0].hwgroup); -} - -static void do_ide1_request (void) /* invoked with cli() */ -{ - do_hwgroup_request (ide_hwifs[1].hwgroup); -} - -static void do_ide2_request (void) /* invoked with cli() */ -{ - do_hwgroup_request (ide_hwifs[2].hwgroup); -} - -static void do_ide3_request (void) /* invoked with cli() */ -{ - do_hwgroup_request (ide_hwifs[3].hwgroup); -} - -static void timer_expiry (unsigned long data) -{ - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; - ide_drive_t *drive = hwgroup->drive; - unsigned long flags; - - save_flags(flags); - cli(); - - if (hwgroup->poll_timeout != 0) { /* polling in progress? */ - ide_handler_t *handler = hwgroup->handler; - hwgroup->handler = NULL; - handler(drive); - } else if (hwgroup->handler == NULL) { /* not waiting for anything? */ - sti(); /* drive must have responded just as the timer expired */ - printk("%s: marginal timeout\n", drive->name); - } else { - hwgroup->handler = NULL; /* abort the operation */ - if (hwgroup->hwif->dmaproc) - (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive); - ide_error(drive, "irq timeout", GET_STAT()); - } - if (hwgroup->handler == NULL) - do_hwgroup_request (hwgroup); - restore_flags(flags); -} - -/* - * There's nothing really useful we can do with an unexpected interrupt, - * other than reading the status register (to clear it), and logging it. - * There should be no way that an irq can happen before we're ready for it, - * so we needn't worry much about losing an "important" interrupt here. - * - * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the - * drive enters "idle", "standby", or "sleep" mode, so if the status looks - * "good", we just ignore the interrupt completely. - * - * This routine assumes cli() is in effect when called. - * - * If an unexpected interrupt happens on irq15 while we are handling irq14 - * and if the two interfaces are "serialized" (CMD640B), then it looks like - * we could screw up by interfering with a new request being set up for irq15. - * - * In reality, this is a non-issue. The new command is not sent unless the - * drive is ready to accept one, in which case we know the drive is not - * trying to interrupt us. And ide_set_handler() is always invoked before - * completing the issuance of any new drive command, so we will not be - * accidently invoked as a result of any valid command completion interrupt. - * - */ -static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) -{ - byte stat; - unsigned int unit; - ide_hwif_t *hwif = hwgroup->hwif; - - /* - * handle the unexpected interrupt - */ - do { - if (hwif->irq == irq) { - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (!drive->present) - continue; -#ifdef CONFIG_BLK_DEV_HT6560B - if (hwif->selectproc) - hwif->selectproc (drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ - if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) - (void) ide_dump_status(drive, "unexpected_intr", stat); - if ((stat & DRQ_STAT)) - try_to_flush_leftover_data(drive); - } - } - } while ((hwif = hwif->next) != hwgroup->hwif); -#ifdef CONFIG_BLK_DEV_HT6560B - if (hwif->selectproc) - hwif->selectproc (hwgroup->drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ -} - -/* - * entry point for all interrupts, caller does cli() for us - */ -static void ide_intr (int irq, struct pt_regs *regs) -{ - ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq]; - ide_handler_t *handler; - - if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) { - ide_drive_t *drive = hwgroup->drive; - hwgroup->handler = NULL; - del_timer(&(hwgroup->timer)); - if (drive->unmask) - sti(); - handler(drive); - cli(); /* this is necessary, as next rq may be different irq */ - if (hwgroup->handler == NULL) { - SET_RECOVERY_TIMER(HWIF(drive)); - ide_do_request(hwgroup); - } - } else { - unexpected_intr(irq, hwgroup); - } - cli(); -} - -/* - * get_info_ptr() returns the (ide_drive_t *) for a given device number. - * It returns NULL if the given device number does not match any present drives. - */ -static ide_drive_t *get_info_ptr (kdev_t i_rdev) -{ - int major = MAJOR(i_rdev); - unsigned int h; - - for (h = 0; h < MAX_HWIFS; ++h) { - ide_hwif_t *hwif = &ide_hwifs[h]; - if (hwif->present && major == hwif->major) { - unsigned unit = DEVICE_NR(i_rdev); - if (unit < MAX_DRIVES) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present) - return drive; - } else if (major == IDE0_MAJOR && unit < 4) { - printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit); - printk("ide: to fix it, run: /usr/src/linux/drivers/block/MAKEDEV.ide\n"); - } - break; - } - } - return NULL; -} - -/* - * This function is intended to be used prior to invoking ide_do_drive_cmd(). - */ -void ide_init_drive_cmd (struct request *rq) -{ - rq->buffer = NULL; - rq->cmd = IDE_DRIVE_CMD; - rq->sector = 0; - rq->nr_sectors = 0; - rq->current_nr_sectors = 0; - rq->sem = NULL; - rq->bh = NULL; - rq->bhtail = NULL; - rq->next = NULL; - -#if 0 /* these are done each time through ide_do_drive_cmd() */ - rq->errors = 0; - rq->rq_status = RQ_ACTIVE; - rq->rq_dev = ????; -#endif -} - -/* - * This function issues a special IDE device request - * onto the request queue. - * - * If action is ide_wait, then then rq is queued at the end of - * the request queue, and the function sleeps until it has been - * processed. This is for use when invoked from an ioctl handler. - * - * If action is ide_preempt, then the rq is queued at the head of - * the request queue, displacing the currently-being-processed - * request and this function returns immediately without waiting - * for the new rq to be completed. This is VERY DANGEROUS, and is - * intended for careful use by the ATAPI tape/cdrom driver code. - * - * 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 - * ATAPI tape/cdrom driver code. - * - * If action is ide_end, then the rq is queued at the end of the - * request queue, and the function returns immediately without waiting - * for the new rq to be completed. This is again intended for careful - * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c, - * when operating in the pipelined operation mode). - */ -int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action) -{ - unsigned long flags; - unsigned int major = HWIF(drive)->major; - struct request *cur_rq; - struct blk_dev_struct *bdev = &blk_dev[major]; - struct semaphore sem = MUTEX_LOCKED; - - rq->errors = 0; - rq->rq_status = RQ_ACTIVE; - rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS); - if (action == ide_wait) - rq->sem = &sem; - - save_flags(flags); - cli(); - cur_rq = bdev->current_request; - - if (cur_rq == NULL || action == ide_preempt) { - rq->next = cur_rq; - bdev->current_request = rq; - if (action == ide_preempt) { - HWGROUP(drive)->rq = NULL; - } else - if (HWGROUP(drive)->rq == NULL) { /* is this necessary (?) */ - bdev->request_fn(); - cli(); - } - } else { - if (action == ide_wait || action == ide_end) { - while (cur_rq->next != NULL) /* find end of list */ - cur_rq = cur_rq->next; - } - rq->next = cur_rq->next; - cur_rq->next = rq; - } - if (action == ide_wait && rq->rq_status != RQ_INACTIVE) - down(&sem); /* wait for it to be serviced */ - restore_flags(flags); - return rq->errors ? -EIO : 0; /* return -EIO if errors */ -} - -static int ide_open(struct inode * inode, struct file * filp) -{ - ide_drive_t *drive; - unsigned long flags; - - if ((drive = get_info_ptr(inode->i_rdev)) == NULL) - return -ENODEV; - save_flags(flags); - cli(); - while (drive->busy) - sleep_on(&drive->wqueue); - drive->usage++; - restore_flags(flags); -#ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == ide_cdrom) - return ide_cdrom_open (inode, filp, drive); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->media == ide_tape) - return idetape_blkdev_open (inode, filp, drive); -#endif /* CONFIG_BLK_DEV_IDETAPE */ - if (drive->removeable) { - byte door_lock[] = {WIN_DOORLOCK,0,0,0}; - struct request rq; - check_disk_change(inode->i_rdev); - ide_init_drive_cmd (&rq); - rq.buffer = door_lock; - /* - * Ignore the return code from door_lock, - * since the open() has already succeeded, - * and the door_lock is irrelevant at this point. - */ - (void) ide_do_drive_cmd(drive, &rq, ide_wait); - } - return 0; -} - -/* - * Releasing a block device means we sync() it, so that it can safely - * be forgotten about... - */ -static void ide_release(struct inode * inode, struct file * file) -{ - ide_drive_t *drive; - - if ((drive = get_info_ptr(inode->i_rdev)) != NULL) { - sync_dev(inode->i_rdev); - drive->usage--; -#ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == ide_cdrom) { - ide_cdrom_release (inode, file, drive); - return; - } -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->media == ide_tape) { - idetape_blkdev_release (inode, file, drive); - return; - } -#endif /* CONFIG_BLK_DEV_IDETAPE */ - if (drive->removeable) { - byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0}; - struct request rq; - invalidate_buffers(inode->i_rdev); - ide_init_drive_cmd (&rq); - rq.buffer = door_unlock; - (void) ide_do_drive_cmd(drive, &rq, ide_wait); - } - } -} - -/* - * This routine is called to flush all partitions and partition tables - * for a changed disk, and then re-read the new partition table. - * If we are revalidating a disk because of a media change, then we - * enter with usage == 0. If we are using an ioctl, we automatically have - * usage == 1 (we need an open channel to use an ioctl :-), so this - * is our limit. - */ -static int revalidate_disk(kdev_t i_rdev) -{ - ide_drive_t *drive; - unsigned int p, major, minor; - long flags; - - if ((drive = get_info_ptr(i_rdev)) == NULL) - return -ENODEV; - - major = MAJOR(i_rdev); - minor = drive->select.b.unit << PARTN_BITS; - save_flags(flags); - cli(); - if (drive->busy || (drive->usage > 1)) { - restore_flags(flags); - return -EBUSY; - }; - drive->busy = 1; - restore_flags(flags); - - for (p = 0; p < (1<<PARTN_BITS); ++p) { - if (drive->part[p].nr_sects > 0) { - kdev_t devp = MKDEV(major, minor+p); - sync_dev (devp); - invalidate_inodes (devp); - invalidate_buffers (devp); - } - drive->part[p].start_sect = 0; - drive->part[p].nr_sects = 0; - }; - - drive->part[0].nr_sects = current_capacity(drive); - if (drive->media == ide_disk) - resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit); - - drive->busy = 0; - wake_up(&drive->wqueue); - return 0; -} - -static int write_fs_long (unsigned long useraddr, long value) -{ - int err; - - if (NULL == (long *)useraddr) - return -EINVAL; - if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long)))) - return err; - put_user((unsigned)value, (long *) useraddr); - return 0; -} - -static int ide_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct hd_geometry *loc = (struct hd_geometry *) arg; - int err; - ide_drive_t *drive; - unsigned long flags; - struct request rq; - - ide_init_drive_cmd (&rq); - if (!inode || !(inode->i_rdev)) - return -EINVAL; - if ((drive = get_info_ptr(inode->i_rdev)) == NULL) - return -ENODEV; - switch (cmd) { - case HDIO_GETGEO: - if (!loc || drive->media != ide_disk) return -EINVAL; - err = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); - if (err) return err; - put_user(drive->bios_head, (byte *) &loc->heads); - put_user(drive->bios_sect, (byte *) &loc->sectors); - put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders); - put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, - (unsigned long *) &loc->start); - return 0; - - case BLKFLSBUF: - if(!suser()) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; - - case BLKRASET: - if(!suser()) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - - case BLKRAGET: - return write_fs_long(arg, read_ahead[MAJOR(inode->i_rdev)]); - - case BLKGETSIZE: /* Return device size */ - return write_fs_long(arg, drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects); - case BLKRRPART: /* Re-read partition tables */ - return revalidate_disk(inode->i_rdev); - - case HDIO_GET_KEEPSETTINGS: - return write_fs_long(arg, drive->keep_settings); - - case HDIO_GET_UNMASKINTR: - return write_fs_long(arg, drive->unmask); - - case HDIO_GET_DMA: - return write_fs_long(arg, drive->using_dma); - - case HDIO_GET_32BIT: - return write_fs_long(arg, drive->io_32bit); - - case HDIO_GET_MULTCOUNT: - return write_fs_long(arg, drive->mult_count); - - case HDIO_GET_IDENTITY: - if (!arg || (MINOR(inode->i_rdev) & PARTN_MASK)) - return -EINVAL; - if (drive->id == NULL) - return -ENOMSG; - err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id)); - if (!err) - memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id)); - return err; - - case HDIO_GET_NOWERR: - return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT); - - case HDIO_SET_DMA: -#ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == ide_cdrom) - return -EPERM; -#endif /* CONFIG_BLK_DEV_IDECD */ - if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) - return -EPERM; - case HDIO_SET_KEEPSETTINGS: - case HDIO_SET_UNMASKINTR: - case HDIO_SET_NOWERR: - if (arg > 1) - return -EINVAL; - case HDIO_SET_32BIT: - if (!suser()) - return -EACCES; - if ((MINOR(inode->i_rdev) & PARTN_MASK)) - return -EINVAL; - save_flags(flags); - cli(); - switch (cmd) { - case HDIO_SET_DMA: - if (!(HWIF(drive)->dmaproc)) { - restore_flags(flags); - return -EPERM; - } - drive->using_dma = arg; - break; - case HDIO_SET_KEEPSETTINGS: - drive->keep_settings = arg; - break; - case HDIO_SET_UNMASKINTR: - if (arg && HWIF(drive)->no_unmask) { - restore_flags(flags); - return -EPERM; - } - drive->unmask = arg; - break; - case HDIO_SET_NOWERR: - drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - break; - case HDIO_SET_32BIT: - if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) - return -EINVAL; - drive->io_32bit = arg; -#ifdef CONFIG_BLK_DEV_DTC2278 - if (HWIF(drive)->chipset == ide_dtc2278) - HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; -#endif /* CONFIG_BLK_DEV_DTC2278 */ - break; - } - restore_flags(flags); - return 0; - - case HDIO_SET_MULTCOUNT: - if (!suser()) - return -EACCES; - if (MINOR(inode->i_rdev) & PARTN_MASK) - return -EINVAL; - if (drive->id && arg > drive->id->max_multsect) - return -EINVAL; - save_flags(flags); - cli(); - if (drive->special.b.set_multmode) { - restore_flags(flags); - return -EBUSY; - } - drive->mult_req = arg; - drive->special.b.set_multmode = 1; - restore_flags(flags); - (void) ide_do_drive_cmd (drive, &rq, ide_wait); - return (drive->mult_count == arg) ? 0 : -EIO; - - case HDIO_DRIVE_CMD: - { - unsigned long args; - - if (NULL == (long *) arg) - err = ide_do_drive_cmd(drive, &rq, ide_wait); - else { - if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long)))) - { - args = get_user((long *)arg); - if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) { - rq.buffer = (char *) &args; - err = ide_do_drive_cmd(drive, &rq, ide_wait); - put_user(args,(long *)arg); - } - } - } - return err; - } - case HDIO_SET_PIO_MODE: - if (!suser()) - return -EACCES; - if (MINOR(inode->i_rdev) & PARTN_MASK) - return -EINVAL; - if (!HWIF(drive)->tuneproc) - return -ENOSYS; - save_flags(flags); - cli(); - drive->pio_req = (int) arg; - drive->special.b.set_pio = 1; - restore_flags(flags); - return 0; - - RO_IOCTLS(inode->i_rdev, arg); - - default: -#ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == ide_cdrom) - return ide_cdrom_ioctl(drive, inode, file, cmd, arg); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->media == ide_tape) - return idetape_blkdev_ioctl(drive, inode, file, cmd, arg); -#endif /* CONFIG_BLK_DEV_IDETAPE */ - return -EPERM; - } -} - -static int ide_check_media_change (kdev_t i_rdev) -{ - ide_drive_t *drive; - - if ((drive = get_info_ptr(i_rdev)) == NULL) - return -ENODEV; -#ifdef CONFIG_BLK_DEV_IDECD - if (drive->media == ide_cdrom) - return ide_cdrom_check_media_change (drive); -#endif /* CONFIG_BLK_DEV_IDECD */ - if (drive->removeable) /* for disks */ - return 1; /* always assume it was changed */ - return 0; -} - -void ide_fixstring (byte *s, const int bytecount, const int byteswap) -{ - byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */ - - if (byteswap) { - /* convert from big-endian to host byte order */ - for (p = end ; p != s;) { - unsigned short *pp = (unsigned short *) (p -= 2); - *pp = ntohs(*pp); - } - } - - /* strip leading blanks */ - while (s != end && *s == ' ') - ++s; - - /* compress internal blanks and strip trailing blanks */ - while (s != end && *s) { - if (*s++ != ' ' || (s != end && *s && *s != ' ')) - *p++ = *(s-1); - } - - /* wipe out trailing garbage */ - while (p != end) - *p++ = '\0'; -} - -static inline void do_identify (ide_drive_t *drive, byte cmd) -{ - int bswap; - struct hd_driveid *id; - unsigned long capacity, check; - - id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL); - ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ - sti(); - - /* - * EATA SCSI controllers do a hardware ATA emulation: ignore them - */ - if ((id->model[0] == 'P' && id->model[1] == 'M') - || (id->model[0] == 'S' && id->model[1] == 'K')) { - printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model); - drive->present = 0; - return; - } - - /* - * WIN_IDENTIFY returns little-endian info, - * WIN_PIDENTIFY *usually* returns little-endian info. - */ - bswap = 1; - if (cmd == WIN_PIDENTIFY) { - if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */ - || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */ - || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */ - bswap = 0; /* Vertos drives may still be weird */ - } - ide_fixstring (id->model, sizeof(id->model), bswap); - ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap); - ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap); - - /* - * Check for an ATAPI device - */ - - if (cmd == WIN_PIDENTIFY) { - byte type = (id->config >> 8) & 0x1f; - printk("%s: %s, ATAPI ", drive->name, id->model); - switch (type) { - case 0: /* Early cdrom models used zero */ - case 5: -#ifdef CONFIG_BLK_DEV_IDECD - printk ("CDROM drive\n"); - drive->media = ide_cdrom; - drive->present = 1; - drive->removeable = 1; - return; -#else - printk ("CDROM "); - break; -#endif /* CONFIG_BLK_DEV_IDECD */ - case 1: -#ifdef CONFIG_BLK_DEV_IDETAPE - printk ("TAPE drive"); - if (idetape_identify_device (drive,id)) { - drive->media = ide_tape; - drive->present = 1; - drive->removeable = 1; - if (HWIF(drive)->dmaproc != NULL && - !HWIF(drive)->dmaproc(ide_dma_check, drive)) - printk(", DMA"); - printk("\n"); - } - else { - drive->present = 0; - printk ("\nide-tape: the tape is not supported by this version of the driver\n"); - } - return; -#else - printk ("TAPE "); - break; -#endif /* CONFIG_BLK_DEV_IDETAPE */ - default: - drive->present = 0; - printk("Type %d - Unknown device\n", type); - return; - } - drive->present = 0; - printk("- not supported by this kernel\n"); - return; - } - - /* check for removeable disks (eg. SYQUEST), ignore 'WD' drives */ - if (id->config & (1<<7)) { /* removeable disk ? */ - if (id->model[0] != 'W' || id->model[1] != 'D') - drive->removeable = 1; - } - - drive->media = ide_disk; - /* Extract geometry if we did not already have one for the drive */ - if (!drive->present) { - drive->present = 1; - drive->cyl = drive->bios_cyl = id->cyls; - drive->head = drive->bios_head = id->heads; - drive->sect = drive->bios_sect = id->sectors; - } - /* Handle logical geometry translation by the drive */ - if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads - && (id->cur_heads <= 16) && id->cur_sectors) - { - /* - * Extract the physical drive geometry for our use. - * Note that we purposely do *not* update the bios info. - * This way, programs that use it (like fdisk) will - * still have the same logical view as the BIOS does, - * which keeps the partition table from being screwed. - * - * An exception to this is the cylinder count, - * which we reexamine later on to correct for 1024 limitations. - */ - drive->cyl = id->cur_cyls; - drive->head = id->cur_heads; - drive->sect = id->cur_sectors; - - /* check for word-swapped "capacity" field in id information */ - capacity = drive->cyl * drive->head * drive->sect; - check = (id->cur_capacity0 << 16) | id->cur_capacity1; - if (check == capacity) { /* was it swapped? */ - /* yes, bring it into little-endian order: */ - id->cur_capacity0 = (capacity >> 0) & 0xffff; - id->cur_capacity1 = (capacity >> 16) & 0xffff; - } - } - /* Use physical geometry if what we have still makes no sense */ - if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) { - drive->cyl = id->cyls; - drive->head = id->heads; - drive->sect = id->sectors; - } - /* Correct the number of cyls if the bios value is too small */ - if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) { - if (drive->cyl > drive->bios_cyl) - drive->bios_cyl = drive->cyl; - } - - (void) current_capacity (drive); /* initialize LBA selection */ - - printk ("%s: %.40s, %ldMB w/%dKB Cache, %sCHS=%d/%d/%d", - drive->name, id->model, current_capacity(drive)/2048L, id->buf_size/2, - drive->select.b.lba ? "LBA, " : "", - drive->bios_cyl, drive->bios_head, drive->bios_sect); - - drive->mult_count = 0; - if (id->max_multsect) { - drive->mult_req = INITIAL_MULT_COUNT; - if (drive->mult_req > id->max_multsect) - drive->mult_req = id->max_multsect; - if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) - drive->special.b.set_multmode = 1; - } - if (HWIF(drive)->dmaproc != NULL) { /* hwif supports DMA? */ - if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) - printk(", DMA"); - } - printk("\n"); -} - -/* - * Delay for *at least* 10ms. As we don't know how much time is left - * until the next tick occurs, we wait an extra tick to be safe. - * This is used only during the probing/polling for drives at boot time. - */ -static void delay_10ms (void) -{ - unsigned long timer = jiffies + (HZ + 99)/100 + 1; - while (timer > jiffies); -} - -/* - * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive - * and waits for a response. It also monitors irqs while this is - * happening, in hope of automatically determining which one is - * being used by the interface. - * - * Returns: 0 device was identified - * 1 device timed-out (no response to identify request) - * 2 device aborted the command (refused to identify itself) - */ -static int try_to_identify (ide_drive_t *drive, byte cmd) -{ - int hd_status, rc; - unsigned long timeout; - int irqs = 0; - - if (!HWIF(drive)->irq) { /* already got an IRQ? */ - probe_irq_off(probe_irq_on()); /* clear dangling irqs */ - irqs = probe_irq_on(); /* start monitoring irqs */ - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ - } - - delay_10ms(); /* 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 */ - } else - hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ - - OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */ - timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; - timeout += jiffies; - do { - if (jiffies > timeout) { - if (!HWIF(drive)->irq) - (void) probe_irq_off(irqs); - return 1; /* drive timed-out */ - } - delay_10ms(); /* give drive a breather */ - } while (IN_BYTE(hd_status) & BUSY_STAT); - - delay_10ms(); /* wait for IRQ and DRQ_STAT */ - if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { - cli(); /* some systems need this */ - do_identify(drive, cmd); /* drive returned ID */ - if (drive->present && drive->media != ide_tape) { - ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; - if (tuneproc != NULL && drive->autotune == 1) - tuneproc(drive, 255); /* auto-tune PIO mode */ - } - rc = 0; /* drive responded with ID */ - } else - rc = 2; /* drive refused ID */ - if (!HWIF(drive)->irq) { - irqs = probe_irq_off(irqs); /* get irq number */ - if (irqs > 0) - HWIF(drive)->irq = irqs; - else /* Mmmm.. multiple IRQs */ - printk("%s: IRQ probe failed (%d)\n", drive->name, irqs); - } - return rc; -} - -/* - * do_probe() has the difficult job of finding a drive if it exists, - * without getting hung up if it doesn't exist, without trampling on - * ethernet cards, and without leaving any IRQs dangling to haunt us later. - * - * If a drive is "known" to exist (from CMOS or kernel parameters), - * but does not respond right away, the probe will "hang in there" - * for the maximum wait time (about 30 seconds), otherwise it will - * exit much more quickly. - * - * Returns: 0 device was identified - * 1 device timed-out (no response to identify request) - * 2 device aborted the command (refused to identify itself) - * 3 bad status from device (possible for ATAPI drives) - * 4 probe was not attempted because failure was obvious - */ -static int do_probe (ide_drive_t *drive, byte cmd) -{ - int rc; -#ifdef CONFIG_BLK_DEV_IDEATAPI - if (drive->present) { /* avoid waiting for inappropriate probes */ - if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY)) - return 4; - } -#endif /* CONFIG_BLK_DEV_IDEATAPI */ -#ifdef DEBUG - printk("probing for %s: present=%d, media=%d, probetype=%s\n", - drive->name, drive->present, drive->media, - (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); -#endif -#ifdef CONFIG_BLK_DEV_HT6560B - if (HWIF(drive)->selectproc) - HWIF(drive)->selectproc (drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ - OUT_BYTE(drive->select.all,IDE_SELECT_REG); /* select target drive */ - delay_10ms(); /* wait for BUSY_STAT */ - if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { - OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */ - return 3; /* no i/f present: avoid killing ethernet cards */ - } - - if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) - || drive->present || cmd == WIN_PIDENTIFY) - { - if ((rc = try_to_identify(drive,cmd))) /* send cmd and wait */ - rc = try_to_identify(drive,cmd); /* failed: try again */ - if (rc == 1) - printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT()); - (void) GET_STAT(); /* ensure drive irq is clear */ - } else { - rc = 3; /* not present or maybe ATAPI */ - } - if (drive->select.b.unit != 0) { - OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */ - delay_10ms(); - (void) GET_STAT(); /* ensure drive irq is clear */ - } - return rc; -} - -/* - * probe_for_drive() tests for existance of a given drive using do_probe(). - * - * Returns: 0 no device was found - * 1 device was found (note: drive->present might still be 0) - */ -static inline byte probe_for_drive (ide_drive_t *drive) -{ - if (drive->noprobe) /* skip probing? */ - return drive->present; - if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ -#ifdef CONFIG_BLK_DEV_IDEATAPI - (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ -#endif /* CONFIG_BLK_DEV_IDEATAPI */ - } - if (!drive->present) - return 0; /* drive not found */ - if (drive->id == NULL) { /* identification failed? */ - if (drive->media == ide_disk) { - printk ("%s: non-IDE drive, CHS=%d/%d/%d\n", - drive->name, drive->cyl, drive->head, drive->sect); - } -#ifdef CONFIG_BLK_DEV_IDECD - else if (drive->media == ide_cdrom) { - printk("%s: ATAPI cdrom (?)\n", drive->name); - } -#endif /* CONFIG_BLK_DEV_IDECD */ - else { - drive->present = 0; /* nuke it */ - return 1; /* drive was found */ - } - } - if (drive->media == ide_disk && !drive->select.b.lba) { - if (!drive->head || drive->head > 16) { - printk("%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", - drive->name, drive->head); - drive->present = 0; - } - } - return 1; /* drive was found */ -} - -/* - * This routine only knows how to look for drive units 0 and 1 - * on an interface, so any setting of MAX_DRIVES > 2 won't work here. - */ -static void probe_for_drives (ide_hwif_t *hwif) -{ - unsigned int unit; - - if (check_region(hwif->io_base,8) || check_region(hwif->ctl_port,1)) { - int msgout = 0; - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present) { - drive->present = 0; - printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name); - msgout = 1; - } - } - if (!msgout) - printk("%s: ports already in use, skipping probe\n", hwif->name); - } else { - unsigned long flags; - save_flags(flags); - -#if (MAX_DRIVES > 2) - printk("%s: probing for first 2 of %d possible drives\n", hwif->name, MAX_DRIVES); -#endif - sti(); /* needed for jiffies and irq probing */ - /* - * Second drive should only exist if first drive was found, - * but a lot of cdrom drives seem to be configured as slave-only - */ - for (unit = 0; unit < 2; ++unit) { /* note the hardcoded '2' */ - ide_drive_t *drive = &hwif->drives[unit]; - (void) probe_for_drive (drive); - } - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present) { - hwif->present = 1; - request_region(hwif->io_base, 8, hwif->name); - request_region(hwif->ctl_port, 1, hwif->name); - break; - } - } - restore_flags(flags); - } -} - -/* - * stridx() returns the offset of c within s, - * or -1 if c is '\0' or not found within s. - */ -static int stridx (const char *s, char c) -{ - char *i = strchr(s, c); - return (i && c) ? i - s : -1; -} - -/* - * match_parm() does parsing for ide_setup(): - * - * 1. the first char of s must be '='. - * 2. if the remainder matches one of the supplied keywords, - * the index (1 based) of the keyword is negated and returned. - * 3. if the remainder is a series of no more than max_vals numbers - * separated by commas, the numbers are saved in vals[] and a - * count of how many were saved is returned. Base10 is assumed, - * and base16 is allowed when prefixed with "0x". - * 4. otherwise, zero is returned. - */ -static int match_parm (char *s, const char *keywords[], int vals[], int max_vals) -{ - static const char *decimal = "0123456789"; - static const char *hex = "0123456789abcdef"; - int i, n; - - if (*s++ == '=') { - /* - * Try matching against the supplied keywords, - * and return -(index+1) if we match one - */ - for (i = 0; *keywords != NULL; ++i) { - if (!strcmp(s, *keywords++)) - return -(i+1); - } - /* - * Look for a series of no more than "max_vals" - * numeric values separated by commas, in base10, - * or base16 when prefixed with "0x". - * Return a count of how many were found. - */ - for (n = 0; (i = stridx(decimal, *s)) >= 0;) { - vals[n] = i; - while ((i = stridx(decimal, *++s)) >= 0) - vals[n] = (vals[n] * 10) + i; - if (*s == 'x' && !vals[n]) { - while ((i = stridx(hex, *++s)) >= 0) - vals[n] = (vals[n] * 0x10) + i; - } - if (++n == max_vals) - break; - if (*s == ',') - ++s; - } - if (!*s) - return n; - } - return 0; /* zero = nothing matched */ -} - -/* - * ide_setup() gets called VERY EARLY during initialization, - * to handle kernel "command line" strings beginning with "hdx=" - * or "ide". Here is the complete set currently supported: - * - * "hdx=" is recognized for all "x" from "a" to "h", such as "hdc". - * "idex=" is recognized for all "x" from "0" to "3", such as "ide1". - * - * "hdx=noprobe" : drive may be present, but do not probe for it - * "hdx=nowerr" : ignore the WRERR_STAT bit on this drive - * "hdx=cdrom" : drive is present, and is a cdrom drive - * "hdx=cyl,head,sect" : disk drive is present, with specified geometry - * "hdx=autotune" : driver will attempt to tune interface speed - * to the fastest PIO mode supported, - * if possible for this drive only. - * Not fully supported by all chipset types, - * and quite likely to cause trouble with - * older/odd IDE drives. - * - * "idex=noprobe" : do not attempt to access/use this interface - * "idex=base" : probe for an interface at the addr specified, - * where "base" is usually 0x1f0 or 0x170 - * and "ctl" is assumed to be "base"+0x206 - * "idex=base,ctl" : specify both base and ctl - * "idex=base,ctl,irq" : specify base, ctl, and irq number - * "idex=autotune" : driver will attempt to tune interface speed - * to the fastest PIO mode supported, - * for all drives on this interface. - * Not fully supported by all chipset types, - * and quite likely to cause trouble with - * older/odd IDE drives. - * "idex=noautotune" : driver will NOT attempt to tune interface speed - * This is the default for most chipsets, - * except the cmd640. - * - * The following two are valid ONLY on ide0, - * and the defaults for the base,ctl ports must not be altered. - * - * "ide0=serialize" : do not overlap operations on ide0 and ide1. - * "ide0=dtc2278" : probe/support DTC2278 interface - * "ide0=ht6560b" : probe/support HT6560B interface - * "ide0=cmd640_vlb" : *REQUIRED* for VLB cards with the CMD640 chip - * (not for PCI -- automatically detected) - * "ide0=qd6580" : probe/support qd6580 interface - * "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445) - * "ide0=umc8672" : probe/support umc8672 chipsets - */ -void ide_setup (char *s) -{ - int i, vals[3]; - ide_hwif_t *hwif; - ide_drive_t *drive; - unsigned int hw, unit; - const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); - const char max_hwif = '0' + (MAX_HWIFS - 1); - - printk("ide_setup: %s", s); - init_ide_data (); - - /* - * Look for drive options: "hdx=" - */ - if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { - const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize", - "autotune", "noautotune", NULL}; - unit = s[2] - 'a'; - hw = unit / MAX_DRIVES; - unit = unit % MAX_DRIVES; - hwif = &ide_hwifs[hw]; - drive = &hwif->drives[unit]; - switch (match_parm(&s[3], hd_words, vals, 3)) { - case -1: /* "noprobe" */ - drive->noprobe = 1; - goto done; - case -2: /* "nowerr" */ - drive->bad_wstat = BAD_R_STAT; - hwif->noprobe = 0; - goto done; - case -3: /* "cdrom" */ - drive->present = 1; - drive->media = ide_cdrom; - hwif->noprobe = 0; - goto done; - case -4: /* "serialize" */ - printk(" -- USE \"ide%c=serialize\" INSTEAD", '0'+hw); - goto do_serialize; - case -5: /* "autotune" */ - drive->autotune = 1; - goto done; - case -6: /* "noautotune" */ - drive->autotune = 2; - goto done; - case 3: /* cyl,head,sect */ - drive->media = ide_disk; - drive->cyl = drive->bios_cyl = vals[0]; - drive->head = drive->bios_head = vals[1]; - drive->sect = drive->bios_sect = vals[2]; - drive->present = 1; - drive->forced_geom = 1; - hwif->noprobe = 0; - goto done; - default: - goto bad_option; - } - } - /* - * Look for interface options: "idex=" - */ - if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) { - /* - * Be VERY CAREFUL changing this: note hardcoded indexes below - */ - const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", - "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", NULL}; - hw = s[3] - '0'; - hwif = &ide_hwifs[hw]; - i = match_parm(&s[4], ide_words, vals, 3); - - /* - * Cryptic check to ensure chipset not already set for hwif: - */ - if (i != -1 && i != -2) { - if (hwif->chipset != ide_unknown) - goto bad_option; - if (i < 0 && ide_hwifs[1].chipset != ide_unknown) - goto bad_option; - } - /* - * Interface keywords work only for ide0: - */ - if (i <= -6 && hw != 0) - goto bad_hwif; - - switch (i) { -#ifdef CONFIG_BLK_DEV_ALI14XX - case -10: /* "ali14xx" */ - { - extern void init_ali14xx (void); - init_ali14xx(); - goto done; - } -#endif /* CONFIG_BLK_DEV_ALI14XX */ -#ifdef CONFIG_BLK_DEV_UMC8672 - case -9: /* "umc8672" */ - { - extern void init_umc8672 (void); - init_umc8672(); - goto done; - } -#endif /* CONFIG_BLK_DEV_UMC8672 */ -#ifdef CONFIG_BLK_DEV_DTC2278 - case -8: /* "dtc2278" */ - { - extern void init_dtc2278 (void); - init_dtc2278(); - goto done; - } -#endif /* CONFIG_BLK_DEV_DTC2278 */ -#ifdef CONFIG_BLK_DEV_CMD640 - case -7: /* "cmd640_vlb" */ - { - extern int cmd640_vlb; /* flag for cmd640.c */ - cmd640_vlb = 1; - goto done; - } -#endif /* CONFIG_BLK_DEV_CMD640 */ -#ifdef CONFIG_BLK_DEV_HT6560B - case -6: /* "ht6560b" */ - { - extern void init_ht6560b (void); - init_ht6560b(); - goto done; - } -#endif /* CONFIG_BLK_DEV_HT6560B */ -#if CONFIG_BLK_DEV_QD6580 - case -5: /* "qd6580" (no secondary i/f) */ - { - extern void init_qd6580 (void); - init_qd6580(); - goto done; - } -#endif /* CONFIG_BLK_DEV_QD6580 */ - case -4: /* "noautotune" */ - hwif->drives[0].autotune = 2; - hwif->drives[1].autotune = 2; - goto done; - case -3: /* "autotune" */ - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - goto done; - case -2: /* "serialize" */ - do_serialize: - if (hw > 1) goto bad_hwif; - ide_hwifs[0].serialized = 1; - goto done; - - case -1: /* "noprobe" */ - hwif->noprobe = 1; - goto done; - - case 1: /* base */ - vals[1] = vals[0] + 0x206; /* default ctl */ - case 2: /* base,ctl */ - vals[2] = 0; /* default irq = probe for it */ - case 3: /* base,ctl,irq */ - hwif->io_base = vals[0]; - hwif->ctl_port = vals[1]; - hwif->irq = vals[2]; - hwif->noprobe = 0; - hwif->chipset = ide_generic; - goto done; - - case 0: goto bad_option; - default: - printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n"); - return; - } - } -bad_option: - printk(" -- BAD OPTION\n"); - return; -bad_hwif: - printk("-- NOT SUPPORTED ON ide%d", hw); -done: - printk("\n"); -} - -/* - * This routine is called from the partition-table code in genhd.c - * to "convert" a drive to a logical geometry with fewer than 1024 cyls. - * - * The second parameter, "xparm", determines exactly how the translation - * will be handled: - * 0 = convert to CHS with fewer than 1024 cyls - * using the same method as Ontrack DiskManager. - * 1 = same as "0", plus offset everything by 63 sectors. - * -1 = similar to "0", plus redirect sector 0 to sector 1. - * >1 = convert to a CHS geometry with "xparm" heads. - * - * Returns 0 if the translation was not possible, if the device was not - * an IDE disk drive, or if a geometry was "forced" on the commandline. - * Returns 1 if the geometry translation was successful. - */ -int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) -{ - ide_drive_t *drive; - static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; - const byte *heads = head_vals; - unsigned long tracks; - - if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom) - return 0; - - if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) - return 0; /* we already have a translation */ - - printk("%s ", msg); - - if (drive->id) { - drive->cyl = drive->id->cyls; - drive->head = drive->id->heads; - drive->sect = drive->id->sectors; - } - drive->bios_cyl = drive->cyl; - drive->bios_head = drive->head; - drive->bios_sect = drive->sect; - drive->special.b.set_geometry = 1; - - tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63; - drive->bios_sect = 63; - if (xparm > 1) { - drive->bios_head = xparm; - drive->bios_cyl = tracks / drive->bios_head; - } else { - while (drive->bios_cyl >= 1024) { - drive->bios_head = *heads; - drive->bios_cyl = tracks / drive->bios_head; - if (0 == *++heads) - break; - } -#if FAKE_FDISK_FOR_EZDRIVE - if (xparm == -1) { - drive->remap_0_to_1 = 1; - msg = "0->1"; - } else -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - if (xparm == 1) { - drive->sect0 = 63; - drive->bios_cyl = (tracks - 1) / drive->bios_head; - msg = "+63"; - } - printk("[remap %s] ", msg); - } - drive->part[0].nr_sects = current_capacity(drive); - printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect); - return 1; -} - -/* - * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc - * controller that is BIOS compatible with ST-506, and thus showing up in our - * BIOS table, but not register compatible, and therefore not present in CMOS. - * - * Furthermore, we will assume that our ST-506 drives <if any> are the primary - * drives in the system -- the ones reflected as drive 1 or 2. The first - * drive is stored in the high nibble of CMOS byte 0x12, the second in the low - * nibble. This will be either a 4 bit drive type or 0xf indicating use byte - * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value - * means we have an AT controller hard disk for that drive. - * - * Of course, there is no guarantee that either drive is actually on the - * "primary" IDE interface, but we don't bother trying to sort that out here. - * If a drive is not actually on the primary interface, then these parameters - * will be ignored. This results in the user having to supply the logical - * drive geometry as a boot parameter for each drive not on the primary i/f. - * - * The only "perfect" way to handle this would be to modify the setup.[cS] code - * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info - * for us during initialization. I have the necessary docs -- any takers? -ml - */ - -static void probe_cmos_for_drives (ide_hwif_t *hwif) -{ -#ifdef __i386__ - extern struct drive_info_struct drive_info; - byte cmos_disks, *BIOS = (byte *) &drive_info; - int unit; - - outb_p(0x12,0x70); /* specify CMOS address 0x12 */ - cmos_disks = inb_p(0x71); /* read the data from 0x12 */ - /* Extract drive geometry from CMOS+BIOS if not already setup */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) { - drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; - drive->head = drive->bios_head = *(BIOS+2); - drive->sect = drive->bios_sect = *(BIOS+14); - drive->ctl = *(BIOS+8); - drive->present = 1; - } - BIOS += 16; - } -#endif -} - -/* - * This routine sets up the irq for an ide interface, and creates a new - * hwgroup for the irq/hwif if none was previously assigned. - * - * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with - * interrupts completely disabled. This can be bad for interrupt latency, - * but anything else has led to problems on some machines. We re-enable - * interrupts as much as we can safely do in most places. - */ -static int init_irq (ide_hwif_t *hwif) -{ - unsigned long flags; - int irq = hwif->irq; - ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq]; - - save_flags(flags); - cli(); - - /* - * Grab the irq if we don't already have it from a previous hwif - */ - if (hwgroup == NULL) { - if (request_irq(irq, ide_intr, SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name)) { - restore_flags(flags); - printk(" -- FAILED!"); - return 1; - } - } - /* - * Check for serialization with ide1. - * This code depends on us having already taken care of ide1. - */ - if (hwif->serialized && hwif->name[3] == '0' && ide_hwifs[1].present) - hwgroup = ide_hwifs[1].hwgroup; - /* - * If this is the first interface in a group, - * then we need to create the hwgroup structure - */ - if (hwgroup == NULL) { - hwgroup = kmalloc (sizeof(ide_hwgroup_t), GFP_KERNEL); - hwgroup->hwif = hwif->next = hwif; - hwgroup->rq = NULL; - hwgroup->handler = NULL; - hwgroup->drive = &hwif->drives[0]; - hwgroup->poll_timeout = 0; - init_timer(&hwgroup->timer); - hwgroup->timer.function = &timer_expiry; - hwgroup->timer.data = (unsigned long) hwgroup; - } else { - hwif->next = hwgroup->hwif->next; - hwgroup->hwif->next = hwif; - } - hwif->hwgroup = hwgroup; - irq_to_hwgroup[irq] = hwgroup; - - restore_flags(flags); /* safe now that hwif->hwgroup is set up */ - - printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name, - hwif->io_base, hwif->io_base+7, hwif->ctl_port, irq); - if (hwgroup->hwif != hwif) - printk(" (serialized with %s)", hwgroup->hwif->name); - printk("\n"); - return 0; -} - -static struct file_operations ide_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - ide_ioctl, /* ioctl */ - NULL, /* mmap */ - ide_open, /* open */ - ide_release, /* release */ - block_fsync /* fsync */ - ,NULL, /* fasync */ - ide_check_media_change, /* check_media_change */ - revalidate_disk /* revalidate */ -}; - -#ifdef CONFIG_PCI -#if defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON) - -typedef void (ide_pci_init_proc_t)(byte, byte); - -/* - * ide_probe_pci() scans PCI for a specific vendor/device function, - * and invokes the supplied init routine for each instance detected. - */ -static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj) -{ - unsigned long flags; - unsigned index; - byte fn, bus; - - save_flags(flags); - cli(); - for (index = 0; !pcibios_find_device (vendor, device, index, &bus, &fn); ++index) { - init (bus, fn + func_adj); - } - restore_flags(flags); -} - -#endif /* defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON) */ -#endif /* CONFIG_PCI */ - -/* - * ide_init_pci() finds/initializes "known" PCI IDE interfaces - * - * This routine should ideally be using pcibios_find_class() to find - * all IDE interfaces, but that function causes some systems to "go weird". - */ -static void probe_for_hwifs (void) -{ -#ifdef CONFIG_PCI - /* - * Find/initialize PCI IDE interfaces - */ - if (pcibios_present()) { -#ifdef CONFIG_BLK_DEV_RZ1000 - ide_pci_init_proc_t init_rz1000; - ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0); -#endif /* CONFIG_BLK_DEV_RZ1000 */ -#ifdef CONFIG_BLK_DEV_TRITON - /* - * Apparently the BIOS32 services on Intel motherboards are - * buggy and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us. - * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0, - * and then add 1. - */ - ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1); -#endif /* CONFIG_BLK_DEV_TRITON */ - } -#endif /* CONFIG_PCI */ -#ifdef CONFIG_BLK_DEV_CMD640 - { - extern void ide_probe_for_cmd640x (void); - ide_probe_for_cmd640x(); - } -#endif -} - -/* - * This is gets invoked once during initialization, to set *everything* up - */ -int ide_init (void) -{ - int h; - - init_ide_data (); - /* - * Probe for special "known" interface chipsets - */ - probe_for_hwifs (); - - /* - * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports - */ - for (h = 0; h < MAX_HWIFS; ++h) { - ide_hwif_t *hwif = &ide_hwifs[h]; - if (!hwif->noprobe) { - if (hwif->io_base == HD_DATA) - probe_cmos_for_drives (hwif); - probe_for_drives (hwif); - } - if (hwif->present) { - if (!hwif->irq) { - if (!(hwif->irq = default_irqs[h])) { - printk("%s: DISABLED, NO IRQ\n", hwif->name); - hwif->present = 0; - continue; - } - } -#ifdef CONFIG_BLK_DEV_HD - if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) { - printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name); - hwif->present = 0; - } -#endif /* CONFIG_BLK_DEV_HD */ - } - } - - /* - * Now we try to set up irqs and major devices for what was found - */ - for (h = MAX_HWIFS-1; h >= 0; --h) { - void (*rfn)(void); - ide_hwif_t *hwif = &ide_hwifs[h]; - if (!hwif->present) - continue; - hwif->present = 0; /* we set it back to 1 if all is ok below */ - switch (hwif->major) { - case IDE0_MAJOR: rfn = &do_ide0_request; break; - case IDE1_MAJOR: rfn = &do_ide1_request; break; - case IDE2_MAJOR: rfn = &do_ide2_request; break; - case IDE3_MAJOR: rfn = &do_ide3_request; break; - default: - printk("%s: request_fn NOT DEFINED\n", hwif->name); - continue; - } - if (register_blkdev (hwif->major, hwif->name, &ide_fops)) { - printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major); - } else if (init_irq (hwif)) { - printk("%s: UNABLE TO GET IRQ %d\n", hwif->name, hwif->irq); - (void) unregister_blkdev (hwif->major, hwif->name); - } else { - init_gendisk(hwif); - blk_dev[hwif->major].request_fn = rfn; - read_ahead[hwif->major] = 8; /* (4kB) */ - hwif->present = 1; /* success */ - } - } - -#ifdef CONFIG_BLK_DEV_IDETAPE - idetape_register_chrdev(); /* Register character device interface to the ide tape */ -#endif /* CONFIG_BLK_DEV_IDETAPE */ - - return 0; -} diff --git a/i386/i386at/gpl/linux/block/ide.h b/i386/i386at/gpl/linux/block/ide.h deleted file mode 100644 index b1ebc4c..0000000 --- a/i386/i386at/gpl/linux/block/ide.h +++ /dev/null @@ -1,655 +0,0 @@ -/* - * linux/drivers/block/ide.h - * - * Copyright (C) 1994, 1995 Linus Torvalds & authors - */ - -#include <linux/config.h> - -/* - * 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. - * - * Primary i/f: ide0: major=3; (hda) minor=0; (hdb) minor=64 - * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64 - * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 - * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 - */ - -/****************************************************************************** - * 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 */ -#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */ - -#ifndef SUPPORT_VLB_SYNC /* 1 to support weird 32-bit chips */ -#define SUPPORT_VLB_SYNC 1 /* 0 to reduce kernel size */ -#endif -#ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */ -#define DISK_RECOVERY_TIME 0 /* for hardware that needs it */ -#endif -#ifndef OK_TO_RESET_CONTROLLER /* 1 needed for good error recovery */ -#define OK_TO_RESET_CONTROLLER 1 /* 0 for use with AH2372A/B interface */ -#endif -#ifndef FAKE_FDISK_FOR_EZDRIVE /* 1 to help linux fdisk with EZDRIVE */ -#define FAKE_FDISK_FOR_EZDRIVE 1 /* 0 to reduce kernel size */ -#endif -#ifndef FANCY_STATUS_DUMPS /* 1 for human-readable drive errors */ -#define FANCY_STATUS_DUMPS 1 /* 0 to reduce kernel size */ -#endif - -#if defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE) -#define CONFIG_BLK_DEV_IDEATAPI 1 -#endif - -/* - * IDE_DRIVE_CMD is used to implement many features of the hdparm utility - */ -#define IDE_DRIVE_CMD 99 /* (magic) undef to reduce kernel size*/ - -/* - * "No user-serviceable parts" beyond this point :) - *****************************************************************************/ - -typedef unsigned char byte; /* used everywhere */ - -/* - * Probably not wise to fiddle with these - */ -#define ERROR_MAX 8 /* Max read/write errors per sector */ -#define ERROR_RESET 3 /* Reset controller every 4th retry */ -#define ERROR_RECAL 1 /* Recalibrate every 2nd retry */ - -/* - * Ensure that various configuration flags have compatible settings - */ -#ifdef REALLY_SLOW_IO -#undef REALLY_FAST_IO -#endif - -/* - * Definitions for accessing IDE controller registers - */ - -#define HWIF(drive) ((ide_hwif_t *)drive->hwif) -#define HWGROUP(drive) ((ide_hwgroup_t *)(HWIF(drive)->hwgroup)) - -#define IDE_DATA_OFFSET (0) -#define IDE_ERROR_OFFSET (1) -#define IDE_NSECTOR_OFFSET (2) -#define IDE_SECTOR_OFFSET (3) -#define IDE_LCYL_OFFSET (4) -#define IDE_HCYL_OFFSET (5) -#define IDE_SELECT_OFFSET (6) -#define IDE_STATUS_OFFSET (7) -#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET -#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -#define IDE_DATA_REG (HWIF(drive)->io_base+IDE_DATA_OFFSET) -#define IDE_ERROR_REG (HWIF(drive)->io_base+IDE_ERROR_OFFSET) -#define IDE_NSECTOR_REG (HWIF(drive)->io_base+IDE_NSECTOR_OFFSET) -#define IDE_SECTOR_REG (HWIF(drive)->io_base+IDE_SECTOR_OFFSET) -#define IDE_LCYL_REG (HWIF(drive)->io_base+IDE_LCYL_OFFSET) -#define IDE_HCYL_REG (HWIF(drive)->io_base+IDE_HCYL_OFFSET) -#define IDE_SELECT_REG (HWIF(drive)->io_base+IDE_SELECT_OFFSET) -#define IDE_STATUS_REG (HWIF(drive)->io_base+IDE_STATUS_OFFSET) -#define IDE_CONTROL_REG (HWIF(drive)->ctl_port) -#define IDE_FEATURE_REG IDE_ERROR_REG -#define IDE_COMMAND_REG IDE_STATUS_REG -#define IDE_ALTSTATUS_REG IDE_CONTROL_REG - -#ifdef REALLY_FAST_IO -#define OUT_BYTE(b,p) outb((b),p) -#define IN_BYTE(p) (byte)inb(p) -#else -#define OUT_BYTE(b,p) outb_p((b),p) -#define IN_BYTE(p) (byte)inb_p(p) -#endif /* REALLY_FAST_IO */ - -#define GET_ERR() IN_BYTE(IDE_ERROR_REG) -#define GET_STAT() IN_BYTE(IDE_STATUS_REG) -#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) -#define BAD_R_STAT (BUSY_STAT | ERR_STAT) -#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) -#define BAD_STAT (BAD_R_STAT | DRQ_STAT) -#define DRIVE_READY (READY_STAT | SEEK_STAT) -#define DATA_READY (DRIVE_READY | DRQ_STAT) - -/* - * Some more useful definitions - */ -#define IDE_MAJOR_NAME "ide" /* the same for all i/f; see also genhd.c */ -#define MAJOR_NAME IDE_MAJOR_NAME -#define PARTN_BITS 6 /* number of minor dev bits for partitions */ -#define PARTN_MASK ((1<<PARTN_BITS)-1) /* a useful bit mask */ -#define MAX_DRIVES 2 /* per interface; 2 assumed by lots of code */ -#define MAX_HWIFS 4 /* an arbitrary, but realistic limit */ -#define SECTOR_WORDS (512 / 4) /* number of 32bit words per sector */ - -/* - * Timeouts for various operations: - */ -#define WAIT_DRQ (5*HZ/100) /* 50msec - spec allows up to 20ms */ -#define WAIT_READY (3*HZ/100) /* 30msec - should be instantaneous */ -#define WAIT_PIDENTIFY (1*HZ) /* 1sec - should be less than 3ms (?) */ -#define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ -#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ - -#ifdef CONFIG_BLK_DEV_IDETAPE -#include "ide-tape.h" -#endif /* CONFIG_BLK_DEV_IDETAPE */ - -#ifdef CONFIG_BLK_DEV_IDECD - -struct atapi_request_sense { - unsigned char error_code : 7; - unsigned char valid : 1; - byte reserved1; - unsigned char sense_key : 4; - unsigned char reserved2 : 1; - unsigned char ili : 1; - unsigned char reserved3 : 2; - byte info[4]; - byte sense_len; - byte command_info[4]; - byte asc; - byte ascq; - byte fru; - byte sense_key_specific[3]; -}; - -struct packet_command { - char *buffer; - int buflen; - int stat; - struct atapi_request_sense *sense_data; - unsigned char c[12]; -}; - -/* Space to hold the disk TOC. */ - -#define MAX_TRACKS 99 -struct atapi_toc_header { - unsigned short toc_length; - byte first_track; - byte last_track; -}; - -struct atapi_toc_entry { - byte reserved1; - unsigned control : 4; - unsigned adr : 4; - byte track; - byte reserved2; - union { - unsigned lba; - struct { - byte reserved3; - byte m; - byte s; - byte f; - } msf; - } addr; -}; - -struct atapi_toc { - int last_session_lba; - int xa_flag; - unsigned capacity; - struct atapi_toc_header hdr; - struct atapi_toc_entry ent[MAX_TRACKS+1]; /* One extra for the leadout. */ -}; - - -/* This structure is annoyingly close to, but not identical with, - the cdrom_subchnl structure from cdrom.h. */ -struct atapi_cdrom_subchnl -{ - u_char acdsc_reserved; - u_char acdsc_audiostatus; - u_short acdsc_length; - u_char acdsc_format; - - u_char acdsc_adr: 4; - u_char acdsc_ctrl: 4; - u_char acdsc_trk; - u_char acdsc_ind; - union - { - struct - { - u_char minute; - u_char second; - u_char frame; - } msf; - int lba; - } acdsc_absaddr; - union - { - struct - { - u_char minute; - u_char second; - u_char frame; - } msf; - int lba; - } acdsc_reladdr; -}; - - -/* Extra per-device info for cdrom drives. */ -struct cdrom_info { - - /* Buffer for table of contents. NULL if we haven't allocated - a TOC buffer for this device yet. */ - - struct atapi_toc *toc; - - /* Sector buffer. If a read request wants only the first part of a cdrom - block, we cache the rest of the block here, in the expectation that that - data is going to be wanted soon. SECTOR_BUFFERED is the number of the - first buffered sector, and NSECTORS_BUFFERED is the number of sectors - in the buffer. Before the buffer is allocated, we should have - SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */ - - unsigned long sector_buffered; - unsigned long nsectors_buffered; - char *sector_buffer; - - /* The result of the last successful request sense command - on this device. */ - struct atapi_request_sense sense_data; -}; - -#endif /* CONFIG_BLK_DEV_IDECD */ - -/* - * Now for the data we need to maintain per-drive: ide_drive_t - */ - -typedef enum {ide_disk, ide_cdrom, ide_tape} ide_media_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned set_geometry : 1; /* respecify drive geometry */ - unsigned recalibrate : 1; /* seek to cyl 0 */ - unsigned set_multmode : 1; /* set multmode count */ - unsigned set_pio : 1; /* set pio mode */ - unsigned reserved : 4; /* unused */ - } b; - } special_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; - } select_t; - -typedef struct ide_drive_s { - special_t special; /* special action flags */ - unsigned present : 1; /* drive is physically present */ - unsigned noprobe : 1; /* from: hdx=noprobe */ - unsigned keep_settings : 1; /* restore settings after drive reset */ - unsigned busy : 1; /* currently doing revalidate_disk() */ - unsigned removeable : 1; /* 1 if need to do check_media_change */ - unsigned using_dma : 1; /* disk is using dma for read/write */ - unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - unsigned unmask : 1; /* flag: okay to unmask other irqs */ - unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ -#if FAKE_FDISK_FOR_EZDRIVE - unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - ide_media_t media; /* disk, cdrom, tape */ - select_t select; /* basic drive/head select reg value */ - byte ctl; /* "normal" value for IDE_CONTROL_REG */ - byte ready_stat; /* min status value for drive ready */ - byte mult_count; /* current multiple sector setting */ - byte mult_req; /* requested multiple sector setting */ - byte pio_req; /* requested multiple sector setting */ - byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ - byte bad_wstat; /* used for ignoring WRERR_STAT */ - byte sect0; /* offset of first sector for DM6:DDO */ - byte usage; /* current "open()" count for drive */ - byte head; /* "real" number of heads */ - byte sect; /* "real" sectors per track */ - byte bios_head; /* BIOS/fdisk/LILO number of heads */ - byte bios_sect; /* BIOS/fdisk/LILO sectors per track */ - unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */ - unsigned short cyl; /* "real" number of cyls */ - 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 */ - struct hd_struct *part; /* drive partition table */ - char name[4]; /* drive name, such as "hda" */ -#ifdef CONFIG_BLK_DEV_IDECD - struct cdrom_info cdrom_info; /* for ide-cd.c */ -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - idetape_tape_t tape; /* for ide-tape.c */ -#endif /* CONFIG_BLK_DEV_IDETAPE */ - - } ide_drive_t; - -/* - * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * Returns 0 if all went well. - * 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_action_t; - -typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); - - -/* - * An ide_tuneproc_t() is used to set the speed of an IDE interface - * to a particular PIO mode. The "byte" parameter is used - * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255 - * indicates that the interface driver should "auto-tune" the PIO mode - * according to the drive capabilities in drive->id; - * - * Not all interface types support tuning, and not all of those - * support all possible PIO settings. They may silently ignore - * or round values as they see fit. - */ -typedef void (ide_tuneproc_t)(ide_drive_t *, byte); - -/* - * This is used to provide HT6560B interface support. - * It will probably also be used by the DC4030VL driver. - */ -typedef void (ide_selectproc_t) (ide_drive_t *); - -/* - * hwif_chipset_t is used to keep track of the specific hardware - * chipset used by each IDE interface, if known. - */ -typedef enum { ide_unknown, ide_generic, ide_triton, - ide_cmd640, ide_dtc2278, ide_ali14xx, - ide_qd6580, ide_umc8672, ide_ht6560b } - hwif_chipset_t; - -typedef struct hwif_s { - struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ - void *hwgroup; /* actually (ide_hwgroup_t *) */ - unsigned short io_base; /* base io port addr */ - unsigned short ctl_port; /* usually io_base+0x206 */ - ide_drive_t drives[MAX_DRIVES]; /* drive info */ - struct gendisk *gd; /* gendisk structure */ - ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ -#ifdef CONFIG_BLK_DEV_HT6560B - ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ -#endif /* CONFIG_BLK_DEV_HT6560B */ - ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ - unsigned long *dmatable; /* dma physical region descriptor table */ - unsigned short dma_base; /* base addr for dma ports (triton) */ - byte irq; /* our irq number */ - byte major; /* our major number */ - char name[5]; /* name of interface, eg. "ide0" */ - byte index; /* 0 for ide0; 1 for ide1; ... */ - hwif_chipset_t chipset; /* sub-module for tuning.. */ - unsigned noprobe : 1; /* don't probe for this interface */ - unsigned present : 1; /* this interface exists */ - unsigned serialized : 1; /* valid only for ide_hwifs[0] */ - unsigned no_unmask : 1; /* disallow setting unmask bits */ -#if (DISK_RECOVERY_TIME > 0) - unsigned long last_time; /* time when previous rq was done */ -#endif -#ifdef CONFIG_BLK_DEV_IDECD - struct request request_sense_request; /* from ide-cd.c */ - struct packet_command request_sense_pc; /* from ide-cd.c */ -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE - ide_drive_t *tape_drive; /* Pointer to the tape on this interface */ -#endif /* CONFIG_BLK_DEV_IDETAPE */ - } ide_hwif_t; - -/* - * internal ide interrupt handler type - */ -typedef void (ide_handler_t)(ide_drive_t *); - -typedef struct hwgroup_s { - ide_handler_t *handler;/* irq handler, if active */ - ide_drive_t *drive; /* current drive */ - ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ - struct request *rq; /* current request */ - struct timer_list timer; /* failsafe timer */ - struct request wrq; /* local copy of current write rq */ - unsigned long poll_timeout; /* timeout value during long polls */ - } ide_hwgroup_t; - -/* - * 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 - * pointers to a hwif (ide_hwif_t *), rather than indexing this - * structure directly (the allocation/layout may change!). - */ -#ifdef _IDE_C - ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ -#else -extern ide_hwif_t ide_hwifs[]; -#endif - -/* - * One final include file, which references some of the data/defns from above - */ -#define IDE_DRIVER /* "parameter" for blk.h */ -#include <linux/blk.h> - -#if (DISK_RECOVERY_TIME > 0) -void ide_set_recovery_timer (ide_hwif_t *); -#define SET_RECOVERY_TIMER(drive) ide_set_recovery_timer (drive) -#else -#define SET_RECOVERY_TIMER(drive) -#endif - -/* - * This is used for (nearly) all data transfers from the IDE interface - */ -void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); - -/* - * This is used for (nearly) all data transfers to the IDE interface - */ -void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); - -/* - * This is used on exit from the driver, to designate the next irq handler - * and also to start the safety timer. - */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout); - -/* - * Error reporting, in human readable form (luxurious, but a memory hog). - */ -byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat); - -/* - * ide_error() takes action based on the error returned by the controller. - * The calling function must return afterwards, to restart the request. - */ -void ide_error (ide_drive_t *drive, const char *msg, byte stat); - -/* - * ide_fixstring() cleans up and (optionally) byte-swaps a text string, - * removing leading/trailing blanks and compressing internal blanks. - * It is primarily used to tidy up the model name/number fields as - * returned by the WIN_[P]IDENTIFY commands. - */ -void ide_fixstring (byte *s, const int bytecount, const int byteswap); - -/* - * This routine busy-waits for the drive status to be not "busy". - * It then checks the status for all of the "good" bits and none - * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() -- caller should return. - * - */ -int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout); - -/* - * This routine is called from the partition-table code in genhd.c - * to "convert" a drive to a logical geometry with fewer than 1024 cyls. - * - * The second parameter, "xparm", determines exactly how the translation - * will be handled: - * 0 = convert to CHS with fewer than 1024 cyls - * using the same method as Ontrack DiskManager. - * 1 = same as "0", plus offset everything by 63 sectors. - * -1 = similar to "0", plus redirect sector 0 to sector 1. - * >1 = convert to a CHS geometry with "xparm" heads. - * - * Returns 0 if the translation was not possible, if the device was not - * an IDE disk drive, or if a geometry was "forced" on the commandline. - * Returns 1 if the geometry translation was successful. - */ -int ide_xlate_1024 (kdev_t, int, const char *); - -/* - * Start a reset operation for an IDE interface. - * The caller should return immediately after invoking this. - */ -void ide_do_reset (ide_drive_t *); - -/* - * This function is intended to be used prior to invoking ide_do_drive_cmd(). - */ -void ide_init_drive_cmd (struct request *rq); - -/* - * "action" parameter type for ide_do_drive_cmd() below. - */ -typedef enum - {ide_wait, /* insert rq at end of list, and wait for it */ - ide_next, /* insert rq immediately after current request */ - ide_preempt, /* insert rq in front of current request */ - ide_end} /* insert rq at end of list, but don't wait for it */ - ide_action_t; - -/* - * This function issues a special IDE device request - * onto the request queue. - * - * If action is ide_wait, then then rq is queued at the end of - * the request queue, and the function sleeps until it has been - * processed. This is for use when invoked from an ioctl handler. - * - * If action is ide_preempt, then the rq is queued at the head of - * the request queue, displacing the currently-being-processed - * request and this function returns immediately without waiting - * for the new rq to be completed. This is VERY DANGEROUS, and is - * intended for careful use by the ATAPI tape/cdrom driver code. - * - * 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 - * ATAPI tape/cdrom driver code. - * - * If action is ide_end, then the rq is queued at the end of the - * request queue, and the function returns immediately without waiting - * for the new rq to be completed. This is again intended for careful - * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c, - * when operating in the pipelined operation mode). - */ -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). - */ -void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); - -#ifdef CONFIG_BLK_DEV_IDECD -/* - * These are routines in ide-cd.c invoked from ide.c - */ -void ide_do_rw_cdrom (ide_drive_t *, unsigned long); -int ide_cdrom_ioctl (ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); -int ide_cdrom_check_media_change (ide_drive_t *); -int ide_cdrom_open (struct inode *, struct file *, ide_drive_t *); -void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *); -void ide_cdrom_setup (ide_drive_t *); -#endif /* CONFIG_BLK_DEV_IDECD */ - -#ifdef CONFIG_BLK_DEV_IDETAPE - -/* - * Functions in ide-tape.c which are invoked from ide.c: - */ - -/* - * idetape_identify_device is called during device probing stage to - * probe for an ide atapi tape drive and to initialize global variables - * in ide-tape.c which provide the link between the character device - * and the correspoding block device. - * - * Returns 1 if an ide tape was detected and is supported. - * Returns 0 otherwise. - */ - -int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id); - -/* - * idetape_setup is called a bit later than idetape_identify_device, - * during the search for disk partitions, to initialize various tape - * state variables in ide_drive_t *drive. - */ - -void idetape_setup (ide_drive_t *drive); - -/* - * idetape_do_request is our request function. It is called by ide.c - * to process a new request. - */ - -void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block); - -/* - * idetape_end_request is used to finish servicing a request, and to - * insert a pending pipeline request into the main device queue. - */ - -void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup); - -/* - * Block device interface functions. - */ - -int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive); -void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive); - -/* - * idetape_register_chrdev initializes the character device interface to - * the ide tape drive. - */ - -void idetape_register_chrdev (void); - -#endif /* CONFIG_BLK_DEV_IDETAPE */ - -#ifdef CONFIG_BLK_DEV_TRITON -void ide_init_triton (byte, byte); -#endif /* CONFIG_BLK_DEV_TRITON */ diff --git a/i386/i386at/gpl/linux/block/ide_modes.h b/i386/i386at/gpl/linux/block/ide_modes.h deleted file mode 100644 index e174d5d..0000000 --- a/i386/i386at/gpl/linux/block/ide_modes.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef _IDE_MODES_H -#define _IDE_MODES_H -/* - * linux/drivers/block/ide_modes.h - * - * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord - */ - -/* - * Shared data/functions for determining best PIO mode for an IDE drive. - * Most of this stuff originally lived in cmd640.c, and changes to the - * ide_pio_blacklist[] table should be made with EXTREME CAUTION to avoid - * breaking the fragile cmd640.c support. - */ - -#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) - -#ifndef _IDE_C - -int ide_scan_pio_blacklist (char *model); -unsigned int ide_get_best_pio_mode (ide_drive_t *drive); - -#else /* _IDE_C */ - -/* - * Black list. Some drives incorrectly report their maximal PIO mode, - * at least in respect to CMD640. Here we keep info on some known drives. - */ -static struct ide_pio_info { - const char *name; - int pio; -} ide_pio_blacklist [] = { -/* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */ - - { "WDC AC2700", 3 }, - { "WDC AC2540", 3 }, - { "WDC AC2420", 3 }, - { "WDC AC2340", 3 }, - { "WDC AC2250", 0 }, - { "WDC AC2200", 0 }, - { "WDC AC2120", 0 }, - { "WDC AC2850", 3 }, - { "WDC AC1270", 3 }, - { "WDC AC1170", 3 }, - { "WDC AC1210", 1 }, - { "WDC AC280", 0 }, -/* { "WDC AC21000", 4 }, */ - { "WDC AC31000", 3 }, -/* { "WDC AC21200", 4 }, */ - { "WDC AC31200", 3 }, -/* { "WDC AC31600", 4 }, */ - - { "Maxtor 7131 AT", 1 }, - { "Maxtor 7171 AT", 1 }, - { "Maxtor 7213 AT", 1 }, - { "Maxtor 7245 AT", 1 }, - { "Maxtor 7345 AT", 1 }, - { "Maxtor 7546 AT", 3 }, - { "Maxtor 7540 AV", 3 }, - - { "SAMSUNG SHD-3121A", 1 }, - { "SAMSUNG SHD-3122A", 1 }, - { "SAMSUNG SHD-3172A", 1 }, - -/* { "ST51080A", 4 }, - * { "ST51270A", 4 }, - * { "ST31220A", 4 }, - * { "ST31640A", 4 }, - * { "ST32140A", 4 }, - * { "ST3780A", 4 }, - */ - { "ST5660A", 3 }, - { "ST3660A", 3 }, - { "ST3630A", 3 }, - { "ST3655A", 3 }, - { "ST3391A", 3 }, - { "ST3390A", 1 }, - { "ST3600A", 1 }, - { "ST3290A", 0 }, - { "ST3144A", 0 }, - - { "QUANTUM ELS127A", 0 }, - { "QUANTUM ELS170A", 0 }, - { "QUANTUM LPS240A", 0 }, - { "QUANTUM LPS210A", 3 }, - { "QUANTUM LPS270A", 3 }, - { "QUANTUM LPS365A", 3 }, - { "QUANTUM LPS540A", 3 }, - { "QUANTUM FIREBALL", 3 }, /* For models 540/640/1080/1280 */ - /* 1080A works fine in mode4 with triton */ - { NULL, 0 } -}; - -/* - * This routine searches the ide_pio_blacklist for an entry - * matching the start/whole of the supplied model name. - * - * Returns -1 if no match found. - * Otherwise returns the recommended PIO mode from ide_pio_blacklist[]. - */ -int ide_scan_pio_blacklist (char *model) -{ - struct ide_pio_info *p; - - for (p = ide_pio_blacklist; p->name != NULL; p++) { - if (strncmp(p->name, model, strlen(p->name)) == 0) - return p->pio; - } - return -1; -} - -/* - * This routine returns the recommended PIO mode for a given drive, - * based on the drive->id information and the ide_pio_blacklist[]. - * This is used by most chipset support modules when "auto-tuning". - */ -unsigned int ide_get_best_pio_mode (ide_drive_t *drive) -{ - unsigned int pio = 0; - struct hd_driveid *id = drive->id; - - if (id != NULL) { - if (HWIF(drive)->chipset != ide_cmd640 && !strcmp("QUANTUM FIREBALL1080A", id->model)) - pio = 4; - else - pio = ide_scan_pio_blacklist(id->model); - if (pio == -1) { - pio = (id->tPIO < 2) ? id->tPIO : 2; - if (id->field_valid & 2) { - byte modes = id->eide_pio_modes; - if (modes & 4) pio = 5; - else if (modes & 2) pio = 4; - else if (modes & 1) pio = 3; - } - } - } - return pio; -} - -#endif /* _IDE_C */ -#endif /* defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) */ -#endif /* _IDE_MODES_H */ diff --git a/i386/i386at/gpl/linux/block/rz1000.c b/i386/i386at/gpl/linux/block/rz1000.c deleted file mode 100644 index 11f1dbd..0000000 --- a/i386/i386at/gpl/linux/block/rz1000.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * linux/drivers/block/rz1000.c Version 0.02 Feb 08, 1996 - * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) - */ - -/* - * Principal Author/Maintainer: mlord@bnr.ca (Mark Lord) - * - * This file provides support for disabling the buggy read-ahead - * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards. - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <asm/io.h> -#include <linux/bios32.h> -#include <linux/pci.h> -#include "ide.h" - -static void ide_pci_access_error (int rc) -{ - printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); -} - -void init_rz1000 (byte bus, byte fn) -{ - int rc; - unsigned short reg; - - printk("ide: buggy RZ1000 interface: "); - if ((rc = pcibios_read_config_word (bus, fn, PCI_COMMAND, ®))) { - ide_pci_access_error (rc); - } else if (!(reg & 1)) { - printk("not enabled\n"); - } else { - if ((rc = pcibios_read_config_word(bus, fn, 0x40, ®)) - || (rc = pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))) - { - ide_hwifs[0].no_unmask = 1; - ide_hwifs[1].no_unmask = 1; - ide_hwifs[0].serialized = 1; - ide_pci_access_error (rc); - printk("serialized, disabled unmasking\n"); - } else - printk("disabled read-ahead\n"); - } -} diff --git a/i386/i386at/gpl/linux/block/triton.c b/i386/i386at/gpl/linux/block/triton.c deleted file mode 100644 index 4f825f6..0000000 --- a/i386/i386at/gpl/linux/block/triton.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * linux/drivers/block/triton.c Version 1.06 Feb 6, 1996 - * - * Copyright (c) 1995-1996 Mark Lord - * May be copied or modified under the terms of the GNU General Public License - */ - -/* - * This module provides support for the Bus Master IDE DMA function - * of the Intel PCI Triton chipset (82371FB). - * - * DMA is currently supported only for hard disk drives (not cdroms). - * - * Support for cdroms will likely be added at a later date, - * after broader experience has been obtained with hard disks. - * - * Up to four drives may be enabled for DMA, and the Triton chipset will - * (hopefully) arbitrate the PCI bus among them. Note that the 82371FB chip - * provides a single "line buffer" for the BM IDE function, so performance of - * multiple (two) drives doing DMA simultaneously will suffer somewhat, - * as they contest for that resource bottleneck. This is handled transparently - * inside the 82371FB chip. - * - * By default, DMA support is prepared for use, but is currently enabled only - * for drives which support multi-word DMA mode2 (mword2), or which are - * recognized as "good" (see table below). Drives with only mode0 or mode1 - * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A) - * but are not enabled by default. Use "hdparm -i" to view modes supported - * by a given drive. - * - * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling - * DMA support, but must be (re-)compiled against this kernel version or later. - * - * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting. - * If problems arise, ide.c will disable DMA operation after a few retries. - * This error recovery mechanism works and has been extremely well exercised. - * - * IDE drives, depending on their vintage, may support several different modes - * of DMA operation. The boot-time modes are indicated with a "*" in - * the "hdparm -i" listing, and can be changed with *knowledgeable* use of - * the "hdparm -X" feature. There is seldom a need to do this, as drives - * normally power-up with their "best" PIO/DMA modes enabled. - * - * Testing was done with an ASUS P55TP4XE/100 system and the following drives: - * - * Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4. - * - DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer. - * - This drive also does PIO mode4, at about the same speed as DMA mode2. - * An awesome drive for the price! - * - * Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4. - * - DMA mode2 gives horrible performance (1.6MB/sec), despite the good - * size of the on-drive buffer and a boasted 10ms average access time. - * - PIO mode4 was better, but peaked at a mere 4.5MB/sec. - * - * Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2. - * - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer. - * - This older drive can also be tweaked for fastPIO (3.7MB/sec) by using - * maximum clock settings (5,4) and setting all flags except prefetch. - * - * Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3. - * - DMA does not work reliably. The drive appears to be somewhat tardy - * in deasserting DMARQ at the end of a sector. This is evident in - * the observation that WRITEs work most of the time, depending on - * cache-buffer occupancy, but multi-sector reads seldom work. - * - * Testing was done with a Gigabyte GA-586 ATE system and the following drive: - * (Uwe Bonnes - bon@elektron.ikp.physik.th-darmstadt.de) - * - * Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4. - * - much better than its 1Gig cousin, this drive is reported to work - * very well with DMA (7.3MB/sec). - * - * Other drives: - * - * Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3. - * - a budget drive, with budget performance, around 3MB/sec. - * - * Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3. - * - another "caviar" drive, similar to the AC31000, except that this one - * worked with DMA in at least one system. Throughput is about 3.8MB/sec - * for both DMA and PIO. - * - * Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4. - * - like most Conner models, this drive proves that even a fast interface - * cannot improve slow media. Both DMA and PIO peak around 3.5MB/sec. - * - * If you have any drive models to add, email your results to: mlord@bnr.ca - * Keep an eye on /var/adm/messages for "DMA disabled" messages. - * - * Some people have reported trouble with Intel Zappa motherboards. - * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0, - * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe - * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this). - * - * And, yes, Intel Zappa boards really *do* use the Triton IDE ports. - */ -#include <linux/config.h> -#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 <asm/dma.h> - -#include "ide.h" - -/* - * good_dma_drives() lists the model names (from "hdparm -i") - * of drives which do not support mword2 DMA but which are - * known to work fine with this interface under Linux. - */ -const char *good_dma_drives[] = {"Micropolis 2112A", - "CONNER CTMA 4000"}; - -/* - * Our Physical Region Descriptor (PRD) table should be large enough - * to handle the biggest I/O request we are likely to see. Since requests - * can have no more than 256 sectors, and since the typical blocksize is - * two sectors, we could get by with a limit of 128 entries here for the - * usual worst case. Most requests seem to include some contiguous blocks, - * further reducing the number of table entries required. - * - * The driver reverts to PIO mode for individual requests that exceed - * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling - * 100% of all crazy scenarios here is not necessary. - * - * As it turns out though, we must allocate a full 4KB page for this, - * so the two PRD tables (ide0 & ide1) will each get half of that, - * allowing each to have about 256 entries (8 bytes each) from this. - */ -#define PRD_BYTES 8 -#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES)) - -/* - * dma_intr() is the handler for disk read/write DMA interrupts - */ -static void 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; - - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */ - 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 */ - 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 DMA status: 0x%02x\n", drive->name, dma_stat); - } - sti(); - ide_error(drive, "dma_intr", stat); -} - -/* - * build_dmatable() prepares a dma request. - * Returns 0 if all went okay, returns 1 otherwise. - */ -static int build_dmatable (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - struct buffer_head *bh = rq->bh; - unsigned long size, addr, *table = HWIF(drive)->dmatable; - unsigned int count = 0; - - do { - /* - * Determine addr and size of next buffer area. We assume that - * individual virtual buffers are always composed linearly in - * physical memory. For example, we assume that any 8kB buffer - * is always composed of two adjacent physical 4kB pages rather - * than two possibly non-adjacent physical 4kB pages. - */ - if (bh == NULL) { /* paging and tape requests have (rq->bh == NULL) */ - addr = virt_to_bus (rq->buffer); -#ifdef CONFIG_BLK_DEV_IDETAPE - if (drive->media == ide_tape) - size = drive->tape.pc->request_transfer; - else -#endif /* CONFIG_BLK_DEV_IDETAPE */ - size = rq->nr_sectors << 9; - } else { - /* group sequential buffers into one large buffer */ - addr = virt_to_bus (bh->b_data); - size = bh->b_size; - while ((bh = bh->b_reqnext) != NULL) { - if ((addr + size) != virt_to_bus (bh->b_data)) - break; - size += bh->b_size; - } - } - - /* - * Fill in the dma table, without crossing any 64kB boundaries. - * We assume 16-bit alignment of all blocks. - */ - while (size) { - if (++count >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); - return 1; /* revert to PIO for this request */ - } else { - unsigned long bcount = 0x10000 - (addr & 0xffff); - if (bcount > size) - bcount = size; - *table++ = addr; - *table++ = bcount; - addr += bcount; - size -= bcount; - } - } - } while (bh != NULL); - if (count) { - *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */ - return 0; - } - printk("%s: empty DMA table?\n", drive->name); - return 1; /* let the PIO routines handle this weirdness */ -} - -static int config_drive_for_dma (ide_drive_t *drive) -{ - const char **list; - - struct hd_driveid *id = drive->id; - if (id && (id->capability & 1)) { - /* Enable DMA on any drive that supports mword2 DMA */ - if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) { - drive->using_dma = 1; - return 0; /* DMA enabled */ - } - /* Consult the list of known "good" drives */ - list = good_dma_drives; - while (*list) { - if (!strcmp(*list++,id->model)) { - drive->using_dma = 1; - return 0; /* DMA enabled */ - } - } - } - return 1; /* DMA not enabled */ -} - -/* - * triton_dmaproc() initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * For ATAPI devices, we just prepare for DMA and return. The caller should - * then issue the packet command to the drive and call us again with - * ide_dma_begin afterwards. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case - * the caller should revert to PIO for the current request. - */ -static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive) -{ - unsigned long dma_base = HWIF(drive)->dma_base; - unsigned int reading = (1 << 3); - - switch (func) { - 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_write: - reading = 0; - case ide_dma_read: - break; - case ide_dma_status_bad: - return ((inb(dma_base+2) & 7) != 4); /* verify good DMA status */ - case ide_dma_transferred: -#if 0 - return (number of bytes actually transferred); -#else - return (0); -#endif - case ide_dma_begin: - outb(inb(dma_base)|1, dma_base); /* begin DMA */ - return 0; - default: - printk("triton_dmaproc: unsupported func: %d\n", func); - return 1; - } - if (build_dmatable (drive)) - return 1; - outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */ - outb(reading, dma_base); /* specify r/w */ - outb(0x26, dma_base+2); /* clear status bits */ -#ifdef CONFIG_BLK_DEV_IDEATAPI - if (drive->media != ide_disk) - return 0; -#endif /* CONFIG_BLK_DEV_IDEATAPI */ - ide_set_handler(drive, &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 */ - return 0; -} - -/* - * print_triton_drive_flags() displays the currently programmed options - * in the Triton chipset for a given drive. - * - * If fastDMA is "no", then slow ISA timings are used for DMA data xfers. - * If fastPIO is "no", then slow ISA timings are used for PIO data xfers. - * If IORDY is "no", then IORDY is assumed to always be asserted. - * If PreFetch is "no", then data pre-fetch/post are not used. - * - * When "fastPIO" and/or "fastDMA" are "yes", then faster PCI timings and - * back-to-back 16-bit data transfers are enabled, using the sample_CLKs - * and recovery_CLKs (PCI clock cycles) timing parameters for that interface. - */ -static void print_triton_drive_flags (unsigned int unit, byte flags) -{ - printk(" %s ", unit ? "slave :" : "master:"); - printk( "fastDMA=%s", (flags&9) ? "on " : "off"); - printk(" PreFetch=%s", (flags&4) ? "on " : "off"); - printk(" IORDY=%s", (flags&2) ? "on " : "off"); - printk(" fastPIO=%s\n", ((flags&9)==1) ? "on " : "off"); -} - -static void init_triton_dma (ide_hwif_t *hwif, unsigned short base) -{ - static unsigned long dmatable = 0; - -#if 0 - printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7); -#endif - if (check_region(base, 8)) { -#if 0 - printk(" -- ERROR, PORTS ALREADY IN USE"); -#endif - } else { - request_region(base, 8, "triton DMA"); - hwif->dma_base = base; - if (!dmatable) { - /* - * Since we know we are on a PCI bus, we could - * actually use __get_free_pages() here instead - * of __get_dma_pages() -- no ISA limitations. - */ - dmatable = __get_dma_pages(GFP_KERNEL, 0); - } - if (dmatable) { - hwif->dmatable = (unsigned long *) dmatable; - dmatable += (PRD_ENTRIES * PRD_BYTES); - outl(virt_to_bus(hwif->dmatable), base + 4); - hwif->dmaproc = &triton_dmaproc; - } - } -#if 0 - printk("\n"); -#endif -} - -/* - * calc_mode() returns the ATA PIO mode number, based on the number - * of cycle clks passed in. Assumes 33Mhz bus operation (30ns per clk). - */ -byte calc_mode (byte clks) -{ - if (clks == 3) return 5; - if (clks == 4) return 4; - if (clks < 6) return 3; - if (clks < 8) return 2; - if (clks < 13) return 1; - return 0; -} - -/* - * ide_init_triton() prepares the IDE driver for DMA operation. - * This routine is called once, from ide.c during driver initialization, - * for each triton chipset which is found (unlikely to be more than one). - */ -void ide_init_triton (byte bus, byte fn) -{ - int rc = 0, h; - int dma_enabled = 0; - unsigned short bmiba, pcicmd; - unsigned int timings; - - printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn); - /* - * See if IDE and BM-DMA features are enabled: - */ - if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd))) - goto quit; - if ((pcicmd & 1) == 0) { - printk("ide: Triton IDE ports are not enabled\n"); - goto quit; - } - if ((pcicmd & 4) == 0) { - printk("ide: Triton BM-DMA feature is not enabled -- upgrade your BIOS\n"); - } else { - /* - * Get the bmiba base address - */ - if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba))) - goto quit; - bmiba &= 0xfff0; /* extract port base address */ - dma_enabled = 1; - } - - /* - * See if ide port(s) are enabled - */ - if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings))) - goto quit; - if (!(timings & 0x80008000)) { - printk("ide: neither Triton IDE port is enabled\n"); - goto quit; - } - - /* - * Save the dma_base port addr for each interface - */ - for (h = 0; h < MAX_HWIFS; ++h) { - byte s_clks, r_clks; - ide_hwif_t *hwif = &ide_hwifs[h]; - unsigned short time; - if (hwif->io_base == 0x1f0) { - time = timings & 0xffff; - if ((timings & 0x8000) == 0) /* interface enabled? */ - continue; - hwif->chipset = ide_triton; - if (dma_enabled) - init_triton_dma(hwif, bmiba); - } else if (hwif->io_base == 0x170) { - time = timings >> 16; - if ((timings & 0x8000) == 0) /* interface enabled? */ - continue; - hwif->chipset = ide_triton; - if (dma_enabled) - init_triton_dma(hwif, bmiba + 8); - } else - continue; - s_clks = ((~time >> 12) & 3) + 2; - r_clks = ((~time >> 8) & 3) + 1; -#if 0 - printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d (PIO mode%d)\n", - hwif->name, time, s_clks, r_clks, calc_mode(s_clks+r_clks)); - print_triton_drive_flags (0, time & 0xf); - print_triton_drive_flags (1, (time >> 4) & 0xf); -#endif - } - -quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); -} - |