187f6c662SJulian Elischer /* 25b81b6b3SRodney W. Grimes * Copyright (c) 1990 The Regents of the University of California. 35b81b6b3SRodney W. Grimes * All rights reserved. 45b81b6b3SRodney W. Grimes * 55b81b6b3SRodney W. Grimes * This code is derived from software contributed to Berkeley by 65b81b6b3SRodney W. Grimes * Don Ahn. 75b81b6b3SRodney W. Grimes * 8dc16046fSJoerg Wunsch * Copyright (c) 1993, 1994 by 93a2f7427SDavid Greenman * jc@irbs.UUCP (John Capo) 103a2f7427SDavid Greenman * vak@zebub.msk.su (Serge Vakulenko) 113a2f7427SDavid Greenman * ache@astral.msk.su (Andrew A. Chernov) 12dc16046fSJoerg Wunsch * 13dc16046fSJoerg Wunsch * Copyright (c) 1993, 1994, 1995 by 143a2f7427SDavid Greenman * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 15dc5df763SJoerg Wunsch * dufault@hda.com (Peter Dufault) 163a2f7427SDavid Greenman * 175b81b6b3SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 185b81b6b3SRodney W. Grimes * modification, are permitted provided that the following conditions 195b81b6b3SRodney W. Grimes * are met: 205b81b6b3SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 215b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 225b81b6b3SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 235b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 245b81b6b3SRodney W. Grimes * documentation and/or other materials provided with the distribution. 255b81b6b3SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 265b81b6b3SRodney W. Grimes * must display the following acknowledgement: 275b81b6b3SRodney W. Grimes * This product includes software developed by the University of 285b81b6b3SRodney W. Grimes * California, Berkeley and its contributors. 295b81b6b3SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 305b81b6b3SRodney W. Grimes * may be used to endorse or promote products derived from this software 315b81b6b3SRodney W. Grimes * without specific prior written permission. 325b81b6b3SRodney W. Grimes * 335b81b6b3SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 345b81b6b3SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 355b81b6b3SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 365b81b6b3SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 375b81b6b3SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 385b81b6b3SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 395b81b6b3SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 405b81b6b3SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 415b81b6b3SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 425b81b6b3SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 435b81b6b3SRodney W. Grimes * SUCH DAMAGE. 445b81b6b3SRodney W. Grimes * 45dc4ff321SRodney W. Grimes * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 46bb6382faSJoerg Wunsch * $Id: fd.c,v 1.92 1996/09/06 23:07:18 phk Exp $ 475b81b6b3SRodney W. Grimes * 485b81b6b3SRodney W. Grimes */ 495b81b6b3SRodney W. Grimes 50b99f0a4aSAndrew Moore #include "ft.h" 51b99f0a4aSAndrew Moore #if NFT < 1 52b99f0a4aSAndrew Moore #undef NFDC 53b99f0a4aSAndrew Moore #endif 545b81b6b3SRodney W. Grimes #include "fd.h" 555b81b6b3SRodney W. Grimes 56b99f0a4aSAndrew Moore #if NFDC > 0 57b99f0a4aSAndrew Moore 58b99f0a4aSAndrew Moore #include <sys/param.h> 59b99f0a4aSAndrew Moore #include <sys/systm.h> 60b99f0a4aSAndrew Moore #include <sys/kernel.h> 61b99f0a4aSAndrew Moore #include <sys/conf.h> 62b99f0a4aSAndrew Moore #include <sys/file.h> 63b99f0a4aSAndrew Moore #include <sys/ioctl.h> 64671e2ceeSBruce Evans #include <machine/clock.h> 65b99f0a4aSAndrew Moore #include <machine/ioctl_fd.h> 66b99f0a4aSAndrew Moore #include <sys/disklabel.h> 67b99f0a4aSAndrew Moore #include <sys/buf.h> 68b99f0a4aSAndrew Moore #include <sys/uio.h> 69b99f0a4aSAndrew Moore #include <sys/malloc.h> 703a2f7427SDavid Greenman #include <sys/proc.h> 71b99f0a4aSAndrew Moore #include <sys/syslog.h> 7292200632SGarrett Wollman #include <sys/dkstat.h> 73f540b106SGarrett Wollman #include <i386/isa/isa.h> 74f540b106SGarrett Wollman #include <i386/isa/isa_device.h> 75f540b106SGarrett Wollman #include <i386/isa/fdreg.h> 76f540b106SGarrett Wollman #include <i386/isa/fdc.h> 77f540b106SGarrett Wollman #include <i386/isa/rtc.h> 78dc5df763SJoerg Wunsch #include <machine/stdarg.h> 7987eafbcaSPoul-Henning Kamp #if NFT > 0 8087eafbcaSPoul-Henning Kamp #include <sys/ftape.h> 8187eafbcaSPoul-Henning Kamp #include <i386/isa/ftreg.h> 8287eafbcaSPoul-Henning Kamp #endif 838af5d536SJulian Elischer #ifdef DEVFS 848af5d536SJulian Elischer #include <sys/devfsext.h> 858af5d536SJulian Elischer #endif 865b81b6b3SRodney W. Grimes 87b39c878eSAndrey A. Chernov /* misuse a flag to identify format operation */ 88b39c878eSAndrey A. Chernov #define B_FORMAT B_XXX 895b81b6b3SRodney W. Grimes 903a2f7427SDavid Greenman /* 913a2f7427SDavid Greenman * this biotab field doubles as a field for the physical unit number 923a2f7427SDavid Greenman * on the controller 933a2f7427SDavid Greenman */ 943a2f7427SDavid Greenman #define id_physid id_scsiid 953a2f7427SDavid Greenman 96dc5df763SJoerg Wunsch /* error returns for fd_cmd() */ 97dc5df763SJoerg Wunsch #define FD_FAILED -1 98dc5df763SJoerg Wunsch #define FD_NOT_VALID -2 99dc5df763SJoerg Wunsch #define FDC_ERRMAX 100 /* do not log more */ 100dc5df763SJoerg Wunsch 101b39c878eSAndrey A. Chernov #define NUMTYPES 14 102b39c878eSAndrey A. Chernov #define NUMDENS (NUMTYPES - 6) 1037ca0641bSAndrey A. Chernov 1043a2f7427SDavid Greenman /* These defines (-1) must match index for fd_types */ 105b99f0a4aSAndrew Moore #define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */ 106b99f0a4aSAndrew Moore #define NO_TYPE 0 /* must match NO_TYPE in ft.c */ 107b99f0a4aSAndrew Moore #define FD_1720 1 108b99f0a4aSAndrew Moore #define FD_1480 2 109b99f0a4aSAndrew Moore #define FD_1440 3 110b99f0a4aSAndrew Moore #define FD_1200 4 111b99f0a4aSAndrew Moore #define FD_820 5 112b99f0a4aSAndrew Moore #define FD_800 6 113b99f0a4aSAndrew Moore #define FD_720 7 114b99f0a4aSAndrew Moore #define FD_360 8 115ed2fa05eSAndrey A. Chernov 116b99f0a4aSAndrew Moore #define FD_1480in5_25 9 117b99f0a4aSAndrew Moore #define FD_1440in5_25 10 118b99f0a4aSAndrew Moore #define FD_820in5_25 11 119b99f0a4aSAndrew Moore #define FD_800in5_25 12 120b99f0a4aSAndrew Moore #define FD_720in5_25 13 121b99f0a4aSAndrew Moore #define FD_360in5_25 14 122b99f0a4aSAndrew Moore 1237ca0641bSAndrey A. Chernov 1246f4e0bebSPoul-Henning Kamp static struct fd_type fd_types[NUMTYPES] = 1255b81b6b3SRodney W. Grimes { 126126518a1SAndrey A. Chernov { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */ 127126518a1SAndrey A. Chernov { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */ 128126518a1SAndrey A. Chernov { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */ 129126518a1SAndrey A. Chernov { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */ 130126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */ 131126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */ 132126518a1SAndrey A. Chernov { 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */ 133b0568305SAndrey A. Chernov { 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */ 134ed2fa05eSAndrey A. Chernov 135126518a1SAndrey A. Chernov { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */ 136126518a1SAndrey A. Chernov { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */ 137126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */ 138126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */ 139126518a1SAndrey A. Chernov { 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */ 140126518a1SAndrey A. Chernov { 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */ 1415b81b6b3SRodney W. Grimes }; 1425b81b6b3SRodney W. Grimes 143b99f0a4aSAndrew Moore #define DRVS_PER_CTLR 2 /* 2 floppies */ 144dc16046fSJoerg Wunsch 1455b81b6b3SRodney W. Grimes /***********************************************************************\ 1465b81b6b3SRodney W. Grimes * Per controller structure. * 1475b81b6b3SRodney W. Grimes \***********************************************************************/ 148b99f0a4aSAndrew Moore struct fdc_data fdc_data[NFDC]; 1495b81b6b3SRodney W. Grimes 1505b81b6b3SRodney W. Grimes /***********************************************************************\ 1515b81b6b3SRodney W. Grimes * Per drive structure. * 152b99f0a4aSAndrew Moore * N per controller (DRVS_PER_CTLR) * 1535b81b6b3SRodney W. Grimes \***********************************************************************/ 1546f4e0bebSPoul-Henning Kamp static struct fd_data { 155b99f0a4aSAndrew Moore struct fdc_data *fdc; /* pointer to controller structure */ 1565b81b6b3SRodney W. Grimes int fdsu; /* this units number on this controller */ 1573a2f7427SDavid Greenman int type; /* Drive type (FD_1440...) */ 1585b81b6b3SRodney W. Grimes struct fd_type *ft; /* pointer to the type descriptor */ 1595b81b6b3SRodney W. Grimes int flags; 1605b81b6b3SRodney W. Grimes #define FD_OPEN 0x01 /* it's open */ 1615b81b6b3SRodney W. Grimes #define FD_ACTIVE 0x02 /* it's active */ 1625b81b6b3SRodney W. Grimes #define FD_MOTOR 0x04 /* motor should be on */ 1635b81b6b3SRodney W. Grimes #define FD_MOTOR_WAIT 0x08 /* motor coming up */ 1645b81b6b3SRodney W. Grimes int skip; 1655b81b6b3SRodney W. Grimes int hddrv; 166dc5df763SJoerg Wunsch #define FD_NO_TRACK -2 1675b81b6b3SRodney W. Grimes int track; /* where we think the head is */ 1683a2f7427SDavid Greenman int options; /* user configurable options, see ioctl_fd.h */ 16992200632SGarrett Wollman int dkunit; /* disk stats unit number */ 17087f6c662SJulian Elischer #ifdef DEVFS 17121519754SBruce Evans void *bdevs[1 + NUMDENS + MAXPARTITIONS]; 17221519754SBruce Evans void *cdevs[1 + NUMDENS + MAXPARTITIONS]; 17387f6c662SJulian Elischer #endif 1745b81b6b3SRodney W. Grimes } fd_data[NFD]; 1755b81b6b3SRodney W. Grimes 1765b81b6b3SRodney W. Grimes /***********************************************************************\ 1775b81b6b3SRodney W. Grimes * Throughout this file the following conventions will be used: * 1785b81b6b3SRodney W. Grimes * fd is a pointer to the fd_data struct for the drive in question * 1795b81b6b3SRodney W. Grimes * fdc is a pointer to the fdc_data struct for the controller * 1805b81b6b3SRodney W. Grimes * fdu is the floppy drive unit number * 1815b81b6b3SRodney W. Grimes * fdcu is the floppy controller unit number * 1825b81b6b3SRodney W. Grimes * fdsu is the floppy drive unit number on that controller. (sub-unit) * 1835b81b6b3SRodney W. Grimes \***********************************************************************/ 184b99f0a4aSAndrew Moore 1853a2f7427SDavid Greenman #if NFT > 0 1863a2f7427SDavid Greenman int ftopen(dev_t, int); 1873a2f7427SDavid Greenman int ftintr(ftu_t ftu); 1883a2f7427SDavid Greenman int ftclose(dev_t, int); 1893a2f7427SDavid Greenman void ftstrategy(struct buf *); 1903a2f7427SDavid Greenman int ftioctl(dev_t, int, caddr_t, int, struct proc *); 1913a2f7427SDavid Greenman int ftdump(dev_t); 1923a2f7427SDavid Greenman int ftsize(dev_t); 19374fa89f4SRodney W. Grimes int ftattach(struct isa_device *, struct isa_device *, int); 1943a2f7427SDavid Greenman #endif 1955b81b6b3SRodney W. Grimes 1963a2f7427SDavid Greenman /* autoconfig functions */ 1973a2f7427SDavid Greenman static int fdprobe(struct isa_device *); 1983a2f7427SDavid Greenman static int fdattach(struct isa_device *); 1993a2f7427SDavid Greenman 2003a2f7427SDavid Greenman /* needed for ft driver, thus exported */ 2013a2f7427SDavid Greenman int in_fdc(fdcu_t); 2023a2f7427SDavid Greenman int out_fdc(fdcu_t, int); 2033a2f7427SDavid Greenman 2043a2f7427SDavid Greenman /* internal functions */ 2053a2f7427SDavid Greenman static void set_motor(fdcu_t, int, int); 2063a2f7427SDavid Greenman # define TURNON 1 2073a2f7427SDavid Greenman # define TURNOFF 0 2083a2f7427SDavid Greenman static timeout_t fd_turnoff; 2093a2f7427SDavid Greenman static timeout_t fd_motor_on; 2103a2f7427SDavid Greenman static void fd_turnon(fdu_t); 2113a2f7427SDavid Greenman static void fdc_reset(fdc_p); 212b5e8ce9fSBruce Evans static int fd_in(fdcu_t, int *); 2133a2f7427SDavid Greenman static void fdstart(fdcu_t); 2143a2f7427SDavid Greenman static timeout_t fd_timeout; 2153a2f7427SDavid Greenman static timeout_t fd_pseudointr; 2163a2f7427SDavid Greenman static int fdstate(fdcu_t, fdc_p); 217aaf08d94SGarrett Wollman static int retrier(fdcu_t); 2183a2f7427SDavid Greenman static int fdformat(dev_t, struct fd_formb *, struct proc *); 2193a2f7427SDavid Greenman 220aaf08d94SGarrett Wollman 2215b81b6b3SRodney W. Grimes #define DEVIDLE 0 2225b81b6b3SRodney W. Grimes #define FINDWORK 1 2235b81b6b3SRodney W. Grimes #define DOSEEK 2 2245b81b6b3SRodney W. Grimes #define SEEKCOMPLETE 3 2255b81b6b3SRodney W. Grimes #define IOCOMPLETE 4 2265b81b6b3SRodney W. Grimes #define RECALCOMPLETE 5 2275b81b6b3SRodney W. Grimes #define STARTRECAL 6 2285b81b6b3SRodney W. Grimes #define RESETCTLR 7 2295b81b6b3SRodney W. Grimes #define SEEKWAIT 8 2305b81b6b3SRodney W. Grimes #define RECALWAIT 9 2315b81b6b3SRodney W. Grimes #define MOTORWAIT 10 2325b81b6b3SRodney W. Grimes #define IOTIMEDOUT 11 2335b81b6b3SRodney W. Grimes 2345b81b6b3SRodney W. Grimes #ifdef DEBUG 235cba2a7c6SBruce Evans static char const * const fdstates[] = 2365b81b6b3SRodney W. Grimes { 2375b81b6b3SRodney W. Grimes "DEVIDLE", 2385b81b6b3SRodney W. Grimes "FINDWORK", 2395b81b6b3SRodney W. Grimes "DOSEEK", 2405b81b6b3SRodney W. Grimes "SEEKCOMPLETE", 2415b81b6b3SRodney W. Grimes "IOCOMPLETE", 2425b81b6b3SRodney W. Grimes "RECALCOMPLETE", 2435b81b6b3SRodney W. Grimes "STARTRECAL", 2445b81b6b3SRodney W. Grimes "RESETCTLR", 2455b81b6b3SRodney W. Grimes "SEEKWAIT", 2465b81b6b3SRodney W. Grimes "RECALWAIT", 2475b81b6b3SRodney W. Grimes "MOTORWAIT", 2485b81b6b3SRodney W. Grimes "IOTIMEDOUT" 2495b81b6b3SRodney W. Grimes }; 2505b81b6b3SRodney W. Grimes 2513a2f7427SDavid Greenman /* CAUTION: fd_debug causes huge amounts of logging output */ 252cba2a7c6SBruce Evans static int volatile fd_debug = 0; 2535b81b6b3SRodney W. Grimes #define TRACE0(arg) if(fd_debug) printf(arg) 2545b81b6b3SRodney W. Grimes #define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2) 255381fe1aaSGarrett Wollman #else /* DEBUG */ 2565b81b6b3SRodney W. Grimes #define TRACE0(arg) 2575b81b6b3SRodney W. Grimes #define TRACE1(arg1, arg2) 258381fe1aaSGarrett Wollman #endif /* DEBUG */ 2595b81b6b3SRodney W. Grimes 260dc16046fSJoerg Wunsch /* autoconfig structure */ 261dc16046fSJoerg Wunsch 262dc16046fSJoerg Wunsch struct isa_driver fdcdriver = { 263dc16046fSJoerg Wunsch fdprobe, fdattach, "fdc", 264dc16046fSJoerg Wunsch }; 265dc16046fSJoerg Wunsch 26687f6c662SJulian Elischer static d_open_t Fdopen; /* NOTE, not fdopen */ 26787f6c662SJulian Elischer static d_close_t fdclose; 26887f6c662SJulian Elischer static d_ioctl_t fdioctl; 26987f6c662SJulian Elischer static d_strategy_t fdstrategy; 27087f6c662SJulian Elischer 27187f6c662SJulian Elischer #define CDEV_MAJOR 9 27287f6c662SJulian Elischer #define BDEV_MAJOR 2 273cba8a5ddSPoul-Henning Kamp static struct cdevsw fd_cdevsw; 274d2f265faSPoul-Henning Kamp static struct bdevsw fd_bdevsw = 27587f6c662SJulian Elischer { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/ 276f332b8a1SBruce Evans nodump, nopsize, 0, "fd", &fd_cdevsw, -1 }; 27787f6c662SJulian Elischer 27887f6c662SJulian Elischer 2796f4e0bebSPoul-Henning Kamp static struct isa_device *fdcdevs[NFDC]; 28092200632SGarrett Wollman 281dc5df763SJoerg Wunsch static int 282dc5df763SJoerg Wunsch fdc_err(fdcu_t fdcu, const char *s) 283dc5df763SJoerg Wunsch { 284dc5df763SJoerg Wunsch fdc_data[fdcu].fdc_errs++; 28516b04b6aSJoerg Wunsch if(s) { 286dc5df763SJoerg Wunsch if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX) 2876a0e6f42SRodney W. Grimes printf("fdc%d: %s", fdcu, s); 288dc5df763SJoerg Wunsch else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX) 289dc5df763SJoerg Wunsch printf("fdc%d: too many errors, not logging any more\n", 290dc5df763SJoerg Wunsch fdcu); 29116b04b6aSJoerg Wunsch } 292dc5df763SJoerg Wunsch 293dc5df763SJoerg Wunsch return FD_FAILED; 294dc5df763SJoerg Wunsch } 295dc5df763SJoerg Wunsch 296dc5df763SJoerg Wunsch /* 297dc5df763SJoerg Wunsch * fd_cmd: Send a command to the chip. Takes a varargs with this structure: 298dc5df763SJoerg Wunsch * Unit number, 299dc5df763SJoerg Wunsch * # of output bytes, output bytes as ints ..., 300dc5df763SJoerg Wunsch * # of input bytes, input bytes as ints ... 301dc5df763SJoerg Wunsch */ 302dc5df763SJoerg Wunsch 3036f4e0bebSPoul-Henning Kamp static int 304dc5df763SJoerg Wunsch fd_cmd(fdcu_t fdcu, int n_out, ...) 305dc5df763SJoerg Wunsch { 306dc5df763SJoerg Wunsch u_char cmd; 307dc5df763SJoerg Wunsch int n_in; 308dc5df763SJoerg Wunsch int n; 309dc5df763SJoerg Wunsch va_list ap; 310dc5df763SJoerg Wunsch 311dc5df763SJoerg Wunsch va_start(ap, n_out); 312dc5df763SJoerg Wunsch cmd = (u_char)(va_arg(ap, int)); 313dc5df763SJoerg Wunsch va_end(ap); 314dc5df763SJoerg Wunsch va_start(ap, n_out); 315dc5df763SJoerg Wunsch for (n = 0; n < n_out; n++) 316dc5df763SJoerg Wunsch { 317dc5df763SJoerg Wunsch if (out_fdc(fdcu, va_arg(ap, int)) < 0) 318dc5df763SJoerg Wunsch { 319dc5df763SJoerg Wunsch char msg[50]; 320dc5df763SJoerg Wunsch sprintf(msg, 321dc5df763SJoerg Wunsch "cmd %x failed at out byte %d of %d\n", 322dc5df763SJoerg Wunsch cmd, n + 1, n_out); 323dc5df763SJoerg Wunsch return fdc_err(fdcu, msg); 324dc5df763SJoerg Wunsch } 325dc5df763SJoerg Wunsch } 326dc5df763SJoerg Wunsch n_in = va_arg(ap, int); 327dc5df763SJoerg Wunsch for (n = 0; n < n_in; n++) 328dc5df763SJoerg Wunsch { 329dc5df763SJoerg Wunsch int *ptr = va_arg(ap, int *); 330dc5df763SJoerg Wunsch if (fd_in(fdcu, ptr) < 0) 331dc5df763SJoerg Wunsch { 332dc5df763SJoerg Wunsch char msg[50]; 333dc5df763SJoerg Wunsch sprintf(msg, 334dc5df763SJoerg Wunsch "cmd %02x failed at in byte %d of %d\n", 335dc5df763SJoerg Wunsch cmd, n + 1, n_in); 336dc5df763SJoerg Wunsch return fdc_err(fdcu, msg); 337dc5df763SJoerg Wunsch } 338dc5df763SJoerg Wunsch } 339dc5df763SJoerg Wunsch 340dc5df763SJoerg Wunsch return 0; 341dc5df763SJoerg Wunsch } 342dc5df763SJoerg Wunsch 3436f4e0bebSPoul-Henning Kamp static int 344dc5df763SJoerg Wunsch fd_sense_drive_status(fdc_p fdc, int *st3p) 345dc5df763SJoerg Wunsch { 346dc5df763SJoerg Wunsch int st3; 347dc5df763SJoerg Wunsch 348dc5df763SJoerg Wunsch if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3)) 349dc5df763SJoerg Wunsch { 3506a0e6f42SRodney W. Grimes return fdc_err(fdc->fdcu, "Sense Drive Status failed\n"); 351dc5df763SJoerg Wunsch } 352dc5df763SJoerg Wunsch if (st3p) 353dc5df763SJoerg Wunsch *st3p = st3; 354dc5df763SJoerg Wunsch 355dc5df763SJoerg Wunsch return 0; 356dc5df763SJoerg Wunsch } 357dc5df763SJoerg Wunsch 3586f4e0bebSPoul-Henning Kamp static int 359dc5df763SJoerg Wunsch fd_sense_int(fdc_p fdc, int *st0p, int *cylp) 360dc5df763SJoerg Wunsch { 361dc5df763SJoerg Wunsch int st0, cyl; 362dc5df763SJoerg Wunsch 363dc5df763SJoerg Wunsch int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0); 364dc5df763SJoerg Wunsch 365dc5df763SJoerg Wunsch if (ret) 366dc5df763SJoerg Wunsch { 367dc5df763SJoerg Wunsch (void)fdc_err(fdc->fdcu, 368dc5df763SJoerg Wunsch "sense intr err reading stat reg 0\n"); 369dc5df763SJoerg Wunsch return ret; 370dc5df763SJoerg Wunsch } 371dc5df763SJoerg Wunsch 372dc5df763SJoerg Wunsch if (st0p) 373dc5df763SJoerg Wunsch *st0p = st0; 374dc5df763SJoerg Wunsch 375dc5df763SJoerg Wunsch if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) 376dc5df763SJoerg Wunsch { 377dc5df763SJoerg Wunsch /* 378dc5df763SJoerg Wunsch * There doesn't seem to have been an interrupt. 379dc5df763SJoerg Wunsch */ 380dc5df763SJoerg Wunsch return FD_NOT_VALID; 381dc5df763SJoerg Wunsch } 382dc5df763SJoerg Wunsch 383dc5df763SJoerg Wunsch if (fd_in(fdc->fdcu, &cyl) < 0) 384dc5df763SJoerg Wunsch { 385dc5df763SJoerg Wunsch return fdc_err(fdc->fdcu, "can't get cyl num\n"); 386dc5df763SJoerg Wunsch } 387dc5df763SJoerg Wunsch 388dc5df763SJoerg Wunsch if (cylp) 389dc5df763SJoerg Wunsch *cylp = cyl; 390dc5df763SJoerg Wunsch 391dc5df763SJoerg Wunsch return 0; 392dc5df763SJoerg Wunsch } 393dc5df763SJoerg Wunsch 394dc5df763SJoerg Wunsch 3956f4e0bebSPoul-Henning Kamp static int 396dc5df763SJoerg Wunsch fd_read_status(fdc_p fdc, int fdsu) 397dc5df763SJoerg Wunsch { 398dc5df763SJoerg Wunsch int i, ret; 399b5e8ce9fSBruce Evans 400dc5df763SJoerg Wunsch for (i = 0; i < 7; i++) 401dc5df763SJoerg Wunsch { 402b5e8ce9fSBruce Evans /* 403b5e8ce9fSBruce Evans * XXX types are poorly chosen. Only bytes can by read 404b5e8ce9fSBruce Evans * from the hardware, but fdc_status wants u_longs and 405b5e8ce9fSBruce Evans * fd_in() gives ints. 406b5e8ce9fSBruce Evans */ 407b5e8ce9fSBruce Evans int status; 408b5e8ce9fSBruce Evans 409b5e8ce9fSBruce Evans ret = fd_in(fdc->fdcu, &status); 410b5e8ce9fSBruce Evans fdc->status[i] = status; 411b5e8ce9fSBruce Evans if (ret != 0) 412dc5df763SJoerg Wunsch break; 413dc5df763SJoerg Wunsch } 414dc5df763SJoerg Wunsch 415dc5df763SJoerg Wunsch if (ret == 0) 416dc5df763SJoerg Wunsch fdc->flags |= FDC_STAT_VALID; 417dc5df763SJoerg Wunsch else 418dc5df763SJoerg Wunsch fdc->flags &= ~FDC_STAT_VALID; 419dc5df763SJoerg Wunsch 420dc5df763SJoerg Wunsch return ret; 421dc5df763SJoerg Wunsch } 422dc5df763SJoerg Wunsch 4235b81b6b3SRodney W. Grimes /****************************************************************************/ 4245b81b6b3SRodney W. Grimes /* autoconfiguration stuff */ 4255b81b6b3SRodney W. Grimes /****************************************************************************/ 426dc5df763SJoerg Wunsch 4275b81b6b3SRodney W. Grimes /* 4285b81b6b3SRodney W. Grimes * probe for existance of controller 4295b81b6b3SRodney W. Grimes */ 4303a2f7427SDavid Greenman static int 431dc5df763SJoerg Wunsch fdprobe(struct isa_device *dev) 4325b81b6b3SRodney W. Grimes { 4335b81b6b3SRodney W. Grimes fdcu_t fdcu = dev->id_unit; 4345b81b6b3SRodney W. Grimes if(fdc_data[fdcu].flags & FDC_ATTACHED) 4355b81b6b3SRodney W. Grimes { 4366a0e6f42SRodney W. Grimes printf("fdc%d: unit used multiple times\n", fdcu); 4375b81b6b3SRodney W. Grimes return 0; 4385b81b6b3SRodney W. Grimes } 4395b81b6b3SRodney W. Grimes 44092200632SGarrett Wollman fdcdevs[fdcu] = dev; 4415b81b6b3SRodney W. Grimes fdc_data[fdcu].baseport = dev->id_iobase; 4425b81b6b3SRodney W. Grimes 44316111cedSAndrew Moore /* First - lets reset the floppy controller */ 4443a2f7427SDavid Greenman outb(dev->id_iobase+FDOUT, 0); 44516111cedSAndrew Moore DELAY(100); 4463a2f7427SDavid Greenman outb(dev->id_iobase+FDOUT, FDO_FRST); 44716111cedSAndrew Moore 4485b81b6b3SRodney W. Grimes /* see if it can handle a command */ 449dc5df763SJoerg Wunsch if (fd_cmd(fdcu, 450dc5df763SJoerg Wunsch 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 451dc5df763SJoerg Wunsch 0)) 4525b81b6b3SRodney W. Grimes { 4535b81b6b3SRodney W. Grimes return(0); 4545b81b6b3SRodney W. Grimes } 4555b81b6b3SRodney W. Grimes return (IO_FDCSIZE); 4565b81b6b3SRodney W. Grimes } 4575b81b6b3SRodney W. Grimes 4585b81b6b3SRodney W. Grimes /* 4595b81b6b3SRodney W. Grimes * wire controller into system, look for floppy units 4605b81b6b3SRodney W. Grimes */ 4613a2f7427SDavid Greenman static int 462dc5df763SJoerg Wunsch fdattach(struct isa_device *dev) 4635b81b6b3SRodney W. Grimes { 4643a2f7427SDavid Greenman unsigned fdt; 4655b81b6b3SRodney W. Grimes fdu_t fdu; 4665b81b6b3SRodney W. Grimes fdcu_t fdcu = dev->id_unit; 4675b81b6b3SRodney W. Grimes fdc_p fdc = fdc_data + fdcu; 4685b81b6b3SRodney W. Grimes fd_p fd; 469cba2a7c6SBruce Evans int fdsu, st0, st3, i; 470cba2a7c6SBruce Evans #if NFT > 0 471cba2a7c6SBruce Evans int unithasfd; 472cba2a7c6SBruce Evans #endif 473b99f0a4aSAndrew Moore struct isa_device *fdup; 474dc5df763SJoerg Wunsch int ic_type = 0; 475999422d7SJulian Elischer #ifdef DEVFS 476c8f2fe8dSBruce Evans int mynor; 47721519754SBruce Evans int typemynor; 47821519754SBruce Evans int typesize; 47921519754SBruce Evans #endif 48092200632SGarrett Wollman 4815b81b6b3SRodney W. Grimes fdc->fdcu = fdcu; 4825b81b6b3SRodney W. Grimes fdc->flags |= FDC_ATTACHED; 4835b81b6b3SRodney W. Grimes fdc->dmachan = dev->id_drq; 484100f78bbSSujal Patel /* Acquire the DMA channel forever, The driver will do the rest */ 485100f78bbSSujal Patel isa_dma_acquire(fdc->dmachan); 486dd87702aSBruce Evans isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */); 4875b81b6b3SRodney W. Grimes fdc->state = DEVIDLE; 4883a2f7427SDavid Greenman /* reset controller, turn motor off, clear fdout mirror reg */ 4893a2f7427SDavid Greenman outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); 49017542807SPoul-Henning Kamp TAILQ_INIT(&fdc->head); 4915b81b6b3SRodney W. Grimes 4925b81b6b3SRodney W. Grimes /* check for each floppy drive */ 493b99f0a4aSAndrew Moore for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) { 494b99f0a4aSAndrew Moore if (fdup->id_iobase != dev->id_iobase) 495b99f0a4aSAndrew Moore continue; 496b99f0a4aSAndrew Moore fdu = fdup->id_unit; 497b99f0a4aSAndrew Moore fd = &fd_data[fdu]; 498b99f0a4aSAndrew Moore if (fdu >= (NFD+NFT)) 499b99f0a4aSAndrew Moore continue; 500b99f0a4aSAndrew Moore fdsu = fdup->id_physid; 501b99f0a4aSAndrew Moore /* look up what bios thinks we have */ 502b99f0a4aSAndrew Moore switch (fdu) { 503b99f0a4aSAndrew Moore case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0); 504b99f0a4aSAndrew Moore break; 505b99f0a4aSAndrew Moore case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0); 506b99f0a4aSAndrew Moore break; 507b99f0a4aSAndrew Moore default: fdt = RTCFDT_NONE; 508b99f0a4aSAndrew Moore break; 509b99f0a4aSAndrew Moore } 5105b81b6b3SRodney W. Grimes /* is there a unit? */ 511b99f0a4aSAndrew Moore if ((fdt == RTCFDT_NONE) 512b99f0a4aSAndrew Moore #if NFT > 0 513b99f0a4aSAndrew Moore || (fdsu >= DRVS_PER_CTLR)) { 514b99f0a4aSAndrew Moore #else 515b99f0a4aSAndrew Moore ) { 51656ef0285SAndrew Moore fd->type = NO_TYPE; 517b99f0a4aSAndrew Moore #endif 518b99f0a4aSAndrew Moore #if NFT > 0 519b99f0a4aSAndrew Moore /* If BIOS says no floppy, or > 2nd device */ 520b99f0a4aSAndrew Moore /* Probe for and attach a floppy tape. */ 52174fa89f4SRodney W. Grimes /* Tell FT if there was already a disk */ 52274fa89f4SRodney W. Grimes /* with this unit number found. */ 52374fa89f4SRodney W. Grimes 52474fa89f4SRodney W. Grimes unithasfd = 0; 52574fa89f4SRodney W. Grimes if (fdu < NFD && fd->type != NO_TYPE) 52674fa89f4SRodney W. Grimes unithasfd = 1; 52785827d9cSJoerg Wunsch if (ftattach(dev, fdup, unithasfd)) 528b99f0a4aSAndrew Moore continue; 52956ef0285SAndrew Moore if (fdsu < DRVS_PER_CTLR) 530b99f0a4aSAndrew Moore fd->type = NO_TYPE; 53156ef0285SAndrew Moore #endif 5325b81b6b3SRodney W. Grimes continue; 533f5f7ba03SJordan K. Hubbard } 5345b81b6b3SRodney W. Grimes 5355b81b6b3SRodney W. Grimes /* select it */ 5363a2f7427SDavid Greenman set_motor(fdcu, fdsu, TURNON); 5376b7bd95bSJoerg Wunsch DELAY(1000000); /* 1 sec */ 538dc5df763SJoerg Wunsch 539dc5df763SJoerg Wunsch if (ic_type == 0 && 540dc5df763SJoerg Wunsch fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0) 541dc5df763SJoerg Wunsch { 5426a0e6f42SRodney W. Grimes printf("fdc%d: ", fdcu); 543dc5df763SJoerg Wunsch ic_type = (u_char)ic_type; 544dc5df763SJoerg Wunsch switch( ic_type ) { 545dc5df763SJoerg Wunsch case 0x80: 5466a0e6f42SRodney W. Grimes printf("NEC 765\n"); 547dc5df763SJoerg Wunsch fdc->fdct = FDC_NE765; 548dc5df763SJoerg Wunsch break; 549dc5df763SJoerg Wunsch case 0x81: 5506a0e6f42SRodney W. Grimes printf("Intel 82077\n"); 551dc5df763SJoerg Wunsch fdc->fdct = FDC_I82077; 552dc5df763SJoerg Wunsch break; 553dc5df763SJoerg Wunsch case 0x90: 5546a0e6f42SRodney W. Grimes printf("NEC 72065B\n"); 555dc5df763SJoerg Wunsch fdc->fdct = FDC_NE72065; 556dc5df763SJoerg Wunsch break; 557dc5df763SJoerg Wunsch default: 5586a0e6f42SRodney W. Grimes printf("unknown IC type %02x\n", ic_type); 559dc5df763SJoerg Wunsch fdc->fdct = FDC_UNKNOWN; 560dc5df763SJoerg Wunsch break; 5616b7bd95bSJoerg Wunsch } 562dc5df763SJoerg Wunsch } 563dc5df763SJoerg Wunsch if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && 564dc5df763SJoerg Wunsch (st3 & NE7_ST3_T0)) { 565dc5df763SJoerg Wunsch /* if at track 0, first seek inwards */ 566dc5df763SJoerg Wunsch /* seek some steps: */ 567dc5df763SJoerg Wunsch (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); 568dc5df763SJoerg Wunsch DELAY(300000); /* ...wait a moment... */ 569dc5df763SJoerg Wunsch (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ 570dc5df763SJoerg Wunsch } 571dc5df763SJoerg Wunsch 572dc5df763SJoerg Wunsch /* If we're at track 0 first seek inwards. */ 573dc5df763SJoerg Wunsch if ((fd_sense_drive_status(fdc, &st3) == 0) && 574dc5df763SJoerg Wunsch (st3 & NE7_ST3_T0)) { 575dc5df763SJoerg Wunsch /* Seek some steps... */ 576dc5df763SJoerg Wunsch if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { 577dc5df763SJoerg Wunsch /* ...wait a moment... */ 578dc5df763SJoerg Wunsch DELAY(300000); 579dc5df763SJoerg Wunsch /* make ctrlr happy: */ 580dc5df763SJoerg Wunsch (void)fd_sense_int(fdc, 0, 0); 581dc5df763SJoerg Wunsch } 582dc5df763SJoerg Wunsch } 583dc5df763SJoerg Wunsch 5846b7bd95bSJoerg Wunsch for(i = 0; i < 2; i++) { 5856b7bd95bSJoerg Wunsch /* 5866b7bd95bSJoerg Wunsch * we must recalibrate twice, just in case the 5876b7bd95bSJoerg Wunsch * heads have been beyond cylinder 76, since most 5886b7bd95bSJoerg Wunsch * FDCs still barf when attempting to recalibrate 5896b7bd95bSJoerg Wunsch * more than 77 steps 5906b7bd95bSJoerg Wunsch */ 591dc5df763SJoerg Wunsch /* go back to 0: */ 592dc5df763SJoerg Wunsch if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { 5936b7bd95bSJoerg Wunsch /* a second being enough for full stroke seek*/ 5946b7bd95bSJoerg Wunsch DELAY(i == 0? 1000000: 300000); 5955b81b6b3SRodney W. Grimes 5966b7bd95bSJoerg Wunsch /* anything responding? */ 597dc5df763SJoerg Wunsch if (fd_sense_int(fdc, &st0, 0) == 0 && 598dc5df763SJoerg Wunsch (st0 & NE7_ST0_EC) == 0) 5996b7bd95bSJoerg Wunsch break; /* already probed succesfully */ 6006b7bd95bSJoerg Wunsch } 601dc5df763SJoerg Wunsch } 6026b7bd95bSJoerg Wunsch 6033a2f7427SDavid Greenman set_motor(fdcu, fdsu, TURNOFF); 6043a2f7427SDavid Greenman 6053a2f7427SDavid Greenman if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ 6065b81b6b3SRodney W. Grimes continue; 6075b81b6b3SRodney W. Grimes 608dc5df763SJoerg Wunsch fd->track = FD_NO_TRACK; 609b99f0a4aSAndrew Moore fd->fdc = fdc; 610b99f0a4aSAndrew Moore fd->fdsu = fdsu; 6113a2f7427SDavid Greenman fd->options = 0; 6122d9d0204SRodney W. Grimes printf("fd%d: ", fdu); 6135b81b6b3SRodney W. Grimes 614b99f0a4aSAndrew Moore switch (fdt) { 6157ca0641bSAndrey A. Chernov case RTCFDT_12M: 6166a0e6f42SRodney W. Grimes printf("1.2MB 5.25in\n"); 617b99f0a4aSAndrew Moore fd->type = FD_1200; 6187ca0641bSAndrey A. Chernov break; 6197ca0641bSAndrey A. Chernov case RTCFDT_144M: 6206a0e6f42SRodney W. Grimes printf("1.44MB 3.5in\n"); 621b99f0a4aSAndrew Moore fd->type = FD_1440; 6227ca0641bSAndrey A. Chernov break; 623290dd077SJoerg Wunsch case RTCFDT_288M: 62486a727d9SJoerg Wunsch case RTCFDT_288M_1: 6256a0e6f42SRodney W. Grimes printf("2.88MB 3.5in - 1.44MB mode\n"); 626290dd077SJoerg Wunsch fd->type = FD_1440; 627290dd077SJoerg Wunsch break; 6287ca0641bSAndrey A. Chernov case RTCFDT_360K: 6296a0e6f42SRodney W. Grimes printf("360KB 5.25in\n"); 630b99f0a4aSAndrew Moore fd->type = FD_360; 6317ca0641bSAndrey A. Chernov break; 632ed2fa05eSAndrey A. Chernov case RTCFDT_720K: 6336a0e6f42SRodney W. Grimes printf("720KB 3.5in\n"); 634b99f0a4aSAndrew Moore fd->type = FD_720; 635ed2fa05eSAndrey A. Chernov break; 6367ca0641bSAndrey A. Chernov default: 6376a0e6f42SRodney W. Grimes printf("unknown\n"); 638b99f0a4aSAndrew Moore fd->type = NO_TYPE; 63921519754SBruce Evans continue; 6405b81b6b3SRodney W. Grimes } 641999422d7SJulian Elischer #ifdef DEVFS 64221519754SBruce Evans mynor = fdu << 6; 64321519754SBruce Evans fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK, 644f85120acSBruce Evans UID_ROOT, GID_OPERATOR, 0640, 64521519754SBruce Evans "fd%d", fdu); 64621519754SBruce Evans fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, 647f85120acSBruce Evans UID_ROOT, GID_OPERATOR, 0640, 64821519754SBruce Evans "rfd%d", fdu); 64921519754SBruce Evans for (i = 1; i < 1 + NUMDENS; i++) { 65021519754SBruce Evans /* 65121519754SBruce Evans * XXX this and the lookup in Fdopen() should be 65221519754SBruce Evans * data driven. 65321519754SBruce Evans */ 65421519754SBruce Evans switch (fd->type) { 65521519754SBruce Evans case FD_360: 65621519754SBruce Evans if (i != FD_360) 65721519754SBruce Evans continue; 65821519754SBruce Evans break; 65921519754SBruce Evans case FD_720: 66021519754SBruce Evans if (i != FD_720 && i != FD_800 && i != FD_820) 66121519754SBruce Evans continue; 66221519754SBruce Evans break; 66321519754SBruce Evans case FD_1200: 66421519754SBruce Evans if (i != FD_360 && i != FD_720 && i != FD_800 66521519754SBruce Evans && i != FD_820 && i != FD_1200 66621519754SBruce Evans && i != FD_1440 && i != FD_1480) 66721519754SBruce Evans continue; 66821519754SBruce Evans break; 66921519754SBruce Evans case FD_1440: 67021519754SBruce Evans if (i != FD_720 && i != FD_800 && i != FD_820 67121519754SBruce Evans && i != FD_1200 && i != FD_1440 67221519754SBruce Evans && i != FD_1480 && i != FD_1720) 67321519754SBruce Evans continue; 67421519754SBruce Evans break; 67521519754SBruce Evans } 67621519754SBruce Evans typemynor = mynor | i; 67721519754SBruce Evans typesize = fd_types[i - 1].size / 2; 67821519754SBruce Evans /* 67921519754SBruce Evans * XXX all these conversions give bloated code and 68021519754SBruce Evans * confusing names. 68121519754SBruce Evans */ 68221519754SBruce Evans if (typesize == 1476) 68321519754SBruce Evans typesize = 1480; 68421519754SBruce Evans if (typesize == 1722) 68521519754SBruce Evans typesize = 1720; 68621519754SBruce Evans fd->bdevs[i] = 68721519754SBruce Evans devfs_add_devswf(&fd_bdevsw, typemynor, DV_BLK, 68821519754SBruce Evans UID_ROOT, GID_OPERATOR, 0640, 68921519754SBruce Evans "fd%d.%d", fdu, typesize); 69021519754SBruce Evans fd->cdevs[i] = 69121519754SBruce Evans devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR, 69221519754SBruce Evans UID_ROOT, GID_OPERATOR, 0640, 69321519754SBruce Evans "rfd%d.%d", fdu, typesize); 69421519754SBruce Evans } 69521519754SBruce Evans for (i = 0; i < MAXPARTITIONS; i++) { 69621519754SBruce Evans fd->bdevs[1 + NUMDENS + i] = 69721519754SBruce Evans devfs_link(fd->bdevs[0], 69821519754SBruce Evans "fd%d%c", fdu, 'a' + i); 69921519754SBruce Evans fd->cdevs[1 + NUMDENS + i] = 70021519754SBruce Evans devfs_link(fd->cdevs[0], 70121519754SBruce Evans "rfd%d%c", fdu, 'a' + i); 70221519754SBruce Evans } 703999422d7SJulian Elischer #endif /* DEVFS */ 70492200632SGarrett Wollman if (dk_ndrive < DK_NDRIVE) { 70592200632SGarrett Wollman sprintf(dk_names[dk_ndrive], "fd%d", fdu); 7066a0e6f42SRodney W. Grimes fd->dkunit = dk_ndrive++; 707671e2ceeSBruce Evans /* 708671e2ceeSBruce Evans * XXX assume rate is FDC_500KBPS. 709671e2ceeSBruce Evans */ 710671e2ceeSBruce Evans dk_wpms[dk_ndrive] = 500000 / 8 / 2; 71192200632SGarrett Wollman } else { 71292200632SGarrett Wollman fd->dkunit = -1; 71392200632SGarrett Wollman } 7145b81b6b3SRodney W. Grimes } 7155b81b6b3SRodney W. Grimes 7163a2f7427SDavid Greenman return (1); 7175b81b6b3SRodney W. Grimes } 7185b81b6b3SRodney W. Grimes 7195b81b6b3SRodney W. Grimes /****************************************************************************/ 7205b81b6b3SRodney W. Grimes /* motor control stuff */ 7215e235068SJordan K. Hubbard /* remember to not deselect the drive we're working on */ 7225b81b6b3SRodney W. Grimes /****************************************************************************/ 7233a2f7427SDavid Greenman static void 724dc5df763SJoerg Wunsch set_motor(fdcu_t fdcu, int fdsu, int turnon) 7255b81b6b3SRodney W. Grimes { 7263a2f7427SDavid Greenman int fdout = fdc_data[fdcu].fdout; 7273a2f7427SDavid Greenman int needspecify = 0; 7283a2f7427SDavid Greenman 7293a2f7427SDavid Greenman if(turnon) { 7303a2f7427SDavid Greenman fdout &= ~FDO_FDSEL; 7313a2f7427SDavid Greenman fdout |= (FDO_MOEN0 << fdsu) + fdsu; 7323a2f7427SDavid Greenman } else 7333a2f7427SDavid Greenman fdout &= ~(FDO_MOEN0 << fdsu); 7343a2f7427SDavid Greenman 7355e235068SJordan K. Hubbard if(!turnon 7365e235068SJordan K. Hubbard && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) 7375e235068SJordan K. Hubbard /* gonna turn off the last drive, put FDC to bed */ 7385e235068SJordan K. Hubbard fdout &= ~ (FDO_FRST|FDO_FDMAEN); 7395e235068SJordan K. Hubbard else { 7403a2f7427SDavid Greenman /* make sure controller is selected and specified */ 7413a2f7427SDavid Greenman if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) 7423a2f7427SDavid Greenman needspecify = 1; 7433a2f7427SDavid Greenman fdout |= (FDO_FRST|FDO_FDMAEN); 7445b81b6b3SRodney W. Grimes } 7455b81b6b3SRodney W. Grimes 7463a2f7427SDavid Greenman outb(fdc_data[fdcu].baseport+FDOUT, fdout); 7473a2f7427SDavid Greenman fdc_data[fdcu].fdout = fdout; 7483a2f7427SDavid Greenman TRACE1("[0x%x->FDOUT]", fdout); 7493a2f7427SDavid Greenman 7503a2f7427SDavid Greenman if(needspecify) { 751dc8603e3SJoerg Wunsch /* 752dc5df763SJoerg Wunsch * XXX 753dc8603e3SJoerg Wunsch * special case: since we have just woken up the FDC 754dc8603e3SJoerg Wunsch * from its sleep, we silently assume the command will 755dc8603e3SJoerg Wunsch * be accepted, and do not test for a timeout 756dc8603e3SJoerg Wunsch */ 757dc5df763SJoerg Wunsch (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, 758dc5df763SJoerg Wunsch NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 759dc5df763SJoerg Wunsch 0); 7603a2f7427SDavid Greenman } 7613a2f7427SDavid Greenman } 7623a2f7427SDavid Greenman 763381fe1aaSGarrett Wollman static void 764d0917939SPaul Richards fd_turnoff(void *arg1) 7655b81b6b3SRodney W. Grimes { 766381fe1aaSGarrett Wollman fdu_t fdu = (fdu_t)arg1; 767f5f7ba03SJordan K. Hubbard int s; 7685b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 769dc16046fSJoerg Wunsch 770dc16046fSJoerg Wunsch TRACE1("[fd%d: turnoff]", fdu); 7718335c1b8SBruce Evans 7728335c1b8SBruce Evans /* 7738335c1b8SBruce Evans * Don't turn off the motor yet if the drive is active. 7748335c1b8SBruce Evans * XXX shouldn't even schedule turnoff until drive is inactive 7758335c1b8SBruce Evans * and nothing is queued on it. 7768335c1b8SBruce Evans */ 7778335c1b8SBruce Evans if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) { 7788335c1b8SBruce Evans timeout(fd_turnoff, arg1, 4 * hz); 7798335c1b8SBruce Evans return; 7808335c1b8SBruce Evans } 7818335c1b8SBruce Evans 782f5f7ba03SJordan K. Hubbard s = splbio(); 7835b81b6b3SRodney W. Grimes fd->flags &= ~FD_MOTOR; 7843a2f7427SDavid Greenman set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF); 785f5f7ba03SJordan K. Hubbard splx(s); 7865b81b6b3SRodney W. Grimes } 7875b81b6b3SRodney W. Grimes 7883a2f7427SDavid Greenman static void 789d0917939SPaul Richards fd_motor_on(void *arg1) 7905b81b6b3SRodney W. Grimes { 791381fe1aaSGarrett Wollman fdu_t fdu = (fdu_t)arg1; 792f5f7ba03SJordan K. Hubbard int s; 793f5f7ba03SJordan K. Hubbard 7945b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 795f5f7ba03SJordan K. Hubbard s = splbio(); 7965b81b6b3SRodney W. Grimes fd->flags &= ~FD_MOTOR_WAIT; 7975b81b6b3SRodney W. Grimes if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) 7985b81b6b3SRodney W. Grimes { 799f5f7ba03SJordan K. Hubbard fdintr(fd->fdc->fdcu); 8005b81b6b3SRodney W. Grimes } 801f5f7ba03SJordan K. Hubbard splx(s); 8025b81b6b3SRodney W. Grimes } 8035b81b6b3SRodney W. Grimes 8043a2f7427SDavid Greenman static void 805dc5df763SJoerg Wunsch fd_turnon(fdu_t fdu) 8065b81b6b3SRodney W. Grimes { 8075b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 8085b81b6b3SRodney W. Grimes if(!(fd->flags & FD_MOTOR)) 8095b81b6b3SRodney W. Grimes { 8103a2f7427SDavid Greenman fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); 8113a2f7427SDavid Greenman set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); 8125e235068SJordan K. Hubbard timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ 8135b81b6b3SRodney W. Grimes } 8145b81b6b3SRodney W. Grimes } 8155b81b6b3SRodney W. Grimes 816381fe1aaSGarrett Wollman static void 817dc5df763SJoerg Wunsch fdc_reset(fdc_p fdc) 8185b81b6b3SRodney W. Grimes { 8193a2f7427SDavid Greenman fdcu_t fdcu = fdc->fdcu; 8203a2f7427SDavid Greenman 8213a2f7427SDavid Greenman /* Try a reset, keep motor on */ 8223a2f7427SDavid Greenman outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 8233a2f7427SDavid Greenman TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 8243a2f7427SDavid Greenman DELAY(100); 8253a2f7427SDavid Greenman /* enable FDC, but defer interrupts a moment */ 8263a2f7427SDavid Greenman outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN); 8273a2f7427SDavid Greenman TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); 8283a2f7427SDavid Greenman DELAY(100); 8293a2f7427SDavid Greenman outb(fdc->baseport + FDOUT, fdc->fdout); 8303a2f7427SDavid Greenman TRACE1("[0x%x->FDOUT]", fdc->fdout); 8313a2f7427SDavid Greenman 832dc5df763SJoerg Wunsch /* XXX after a reset, silently believe the FDC will accept commands */ 833dc5df763SJoerg Wunsch (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, 834dc5df763SJoerg Wunsch NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 835dc5df763SJoerg Wunsch 0); 8365b81b6b3SRodney W. Grimes } 8375b81b6b3SRodney W. Grimes 8385b81b6b3SRodney W. Grimes /****************************************************************************/ 8395b81b6b3SRodney W. Grimes /* fdc in/out */ 8405b81b6b3SRodney W. Grimes /****************************************************************************/ 8415b81b6b3SRodney W. Grimes int 842dc5df763SJoerg Wunsch in_fdc(fdcu_t fdcu) 8435b81b6b3SRodney W. Grimes { 8445b81b6b3SRodney W. Grimes int baseport = fdc_data[fdcu].baseport; 8455b81b6b3SRodney W. Grimes int i, j = 100000; 8463a2f7427SDavid Greenman while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 8475b81b6b3SRodney W. Grimes != (NE7_DIO|NE7_RQM) && j-- > 0) 848dc5df763SJoerg Wunsch if (i == NE7_RQM) 8496a0e6f42SRodney W. Grimes return fdc_err(fdcu, "ready for output in input\n"); 8505b81b6b3SRodney W. Grimes if (j <= 0) 85116b04b6aSJoerg Wunsch return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); 8525b81b6b3SRodney W. Grimes #ifdef DEBUG 8533a2f7427SDavid Greenman i = inb(baseport+FDDATA); 8543a2f7427SDavid Greenman TRACE1("[FDDATA->0x%x]", (unsigned char)i); 8555b81b6b3SRodney W. Grimes return(i); 8565b81b6b3SRodney W. Grimes #else 8573a2f7427SDavid Greenman return inb(baseport+FDDATA); 8585b81b6b3SRodney W. Grimes #endif 8595b81b6b3SRodney W. Grimes } 8605b81b6b3SRodney W. Grimes 861dc5df763SJoerg Wunsch /* 862dc5df763SJoerg Wunsch * fd_in: Like in_fdc, but allows you to see if it worked. 863dc5df763SJoerg Wunsch */ 864b5e8ce9fSBruce Evans static int 865dc5df763SJoerg Wunsch fd_in(fdcu_t fdcu, int *ptr) 866dc5df763SJoerg Wunsch { 867dc5df763SJoerg Wunsch int baseport = fdc_data[fdcu].baseport; 868dc5df763SJoerg Wunsch int i, j = 100000; 869dc5df763SJoerg Wunsch while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 870dc5df763SJoerg Wunsch != (NE7_DIO|NE7_RQM) && j-- > 0) 871dc5df763SJoerg Wunsch if (i == NE7_RQM) 8726a0e6f42SRodney W. Grimes return fdc_err(fdcu, "ready for output in input\n"); 873dc5df763SJoerg Wunsch if (j <= 0) 87416b04b6aSJoerg Wunsch return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); 875dc5df763SJoerg Wunsch #ifdef DEBUG 876dc5df763SJoerg Wunsch i = inb(baseport+FDDATA); 877dc5df763SJoerg Wunsch TRACE1("[FDDATA->0x%x]", (unsigned char)i); 878dc5df763SJoerg Wunsch *ptr = i; 879dc5df763SJoerg Wunsch return 0; 880dc5df763SJoerg Wunsch #else 881dc5df763SJoerg Wunsch i = inb(baseport+FDDATA); 882dc5df763SJoerg Wunsch if (ptr) 883dc5df763SJoerg Wunsch *ptr = i; 884dc5df763SJoerg Wunsch return 0; 885dc5df763SJoerg Wunsch #endif 886dc5df763SJoerg Wunsch } 887dc5df763SJoerg Wunsch 888dc5df763SJoerg Wunsch int 889dc5df763SJoerg Wunsch out_fdc(fdcu_t fdcu, int x) 8905b81b6b3SRodney W. Grimes { 8915b81b6b3SRodney W. Grimes int baseport = fdc_data[fdcu].baseport; 8923b3837dbSRodney W. Grimes int i; 8935b81b6b3SRodney W. Grimes 8943b3837dbSRodney W. Grimes /* Check that the direction bit is set */ 8953b3837dbSRodney W. Grimes i = 100000; 8963a2f7427SDavid Greenman while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0); 8976a0e6f42SRodney W. Grimes if (i <= 0) return fdc_err(fdcu, "direction bit not set\n"); 8983b3837dbSRodney W. Grimes 8993b3837dbSRodney W. Grimes /* Check that the floppy controller is ready for a command */ 9003b3837dbSRodney W. Grimes i = 100000; 9013a2f7427SDavid Greenman while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0); 90216b04b6aSJoerg Wunsch if (i <= 0) 90316b04b6aSJoerg Wunsch return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0); 9043b3837dbSRodney W. Grimes 9053b3837dbSRodney W. Grimes /* Send the command and return */ 9063a2f7427SDavid Greenman outb(baseport+FDDATA, x); 9073a2f7427SDavid Greenman TRACE1("[0x%x->FDDATA]", x); 9085b81b6b3SRodney W. Grimes return (0); 9095b81b6b3SRodney W. Grimes } 9105b81b6b3SRodney W. Grimes 9115b81b6b3SRodney W. Grimes /****************************************************************************/ 9125b81b6b3SRodney W. Grimes /* fdopen/fdclose */ 9135b81b6b3SRodney W. Grimes /****************************************************************************/ 914381fe1aaSGarrett Wollman int 915671e2ceeSBruce Evans Fdopen(dev_t dev, int flags, int mode, struct proc *p) 9165b81b6b3SRodney W. Grimes { 9175b81b6b3SRodney W. Grimes fdu_t fdu = FDUNIT(minor(dev)); 91820a29168SAndrey A. Chernov int type = FDTYPE(minor(dev)); 919b99f0a4aSAndrew Moore fdc_p fdc; 9205b81b6b3SRodney W. Grimes 921b99f0a4aSAndrew Moore #if NFT > 0 922b99f0a4aSAndrew Moore /* check for a tape open */ 923b99f0a4aSAndrew Moore if (type & F_TAPE_TYPE) 924b99f0a4aSAndrew Moore return(ftopen(dev, flags)); 925b99f0a4aSAndrew Moore #endif 9265b81b6b3SRodney W. Grimes /* check bounds */ 927b99f0a4aSAndrew Moore if (fdu >= NFD) 928b99f0a4aSAndrew Moore return(ENXIO); 929b99f0a4aSAndrew Moore fdc = fd_data[fdu].fdc; 930b99f0a4aSAndrew Moore if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE)) 931b99f0a4aSAndrew Moore return(ENXIO); 932b99f0a4aSAndrew Moore if (type > NUMDENS) 933b99f0a4aSAndrew Moore return(ENXIO); 9347ca0641bSAndrey A. Chernov if (type == 0) 9357ca0641bSAndrey A. Chernov type = fd_data[fdu].type; 9367ca0641bSAndrey A. Chernov else { 9377ca0641bSAndrey A. Chernov if (type != fd_data[fdu].type) { 938fa4700b4SAndrey A. Chernov switch (fd_data[fdu].type) { 9397ca0641bSAndrey A. Chernov case FD_360: 9407ca0641bSAndrey A. Chernov return(ENXIO); 941ed2fa05eSAndrey A. Chernov case FD_720: 942b39c878eSAndrey A. Chernov if ( type != FD_820 943b39c878eSAndrey A. Chernov && type != FD_800 944ed2fa05eSAndrey A. Chernov ) 945ed2fa05eSAndrey A. Chernov return(ENXIO); 946ed2fa05eSAndrey A. Chernov break; 9477ca0641bSAndrey A. Chernov case FD_1200: 948b39c878eSAndrey A. Chernov switch (type) { 949b39c878eSAndrey A. Chernov case FD_1480: 950b39c878eSAndrey A. Chernov type = FD_1480in5_25; 951fa4700b4SAndrey A. Chernov break; 9527ca0641bSAndrey A. Chernov case FD_1440: 953b39c878eSAndrey A. Chernov type = FD_1440in5_25; 954b39c878eSAndrey A. Chernov break; 955b39c878eSAndrey A. Chernov case FD_820: 956b39c878eSAndrey A. Chernov type = FD_820in5_25; 957b39c878eSAndrey A. Chernov break; 958b39c878eSAndrey A. Chernov case FD_800: 959b39c878eSAndrey A. Chernov type = FD_800in5_25; 960b39c878eSAndrey A. Chernov break; 961b39c878eSAndrey A. Chernov case FD_720: 962b39c878eSAndrey A. Chernov type = FD_720in5_25; 963b39c878eSAndrey A. Chernov break; 964b39c878eSAndrey A. Chernov case FD_360: 965b39c878eSAndrey A. Chernov type = FD_360in5_25; 966b39c878eSAndrey A. Chernov break; 967b39c878eSAndrey A. Chernov default: 968b39c878eSAndrey A. Chernov return(ENXIO); 969b39c878eSAndrey A. Chernov } 970b39c878eSAndrey A. Chernov break; 971b39c878eSAndrey A. Chernov case FD_1440: 972b39c878eSAndrey A. Chernov if ( type != FD_1720 973b39c878eSAndrey A. Chernov && type != FD_1480 974ed2fa05eSAndrey A. Chernov && type != FD_1200 975b39c878eSAndrey A. Chernov && type != FD_820 976b39c878eSAndrey A. Chernov && type != FD_800 977b39c878eSAndrey A. Chernov && type != FD_720 9787ca0641bSAndrey A. Chernov ) 979dffff499SAndrey A. Chernov return(ENXIO); 980fa4700b4SAndrey A. Chernov break; 9817ca0641bSAndrey A. Chernov } 9827ca0641bSAndrey A. Chernov } 983fa4700b4SAndrey A. Chernov } 984b99f0a4aSAndrew Moore fd_data[fdu].ft = fd_types + type - 1; 9855b81b6b3SRodney W. Grimes fd_data[fdu].flags |= FD_OPEN; 9865b81b6b3SRodney W. Grimes 9875b81b6b3SRodney W. Grimes return 0; 9885b81b6b3SRodney W. Grimes } 9895b81b6b3SRodney W. Grimes 990381fe1aaSGarrett Wollman int 991671e2ceeSBruce Evans fdclose(dev_t dev, int flags, int mode, struct proc *p) 9925b81b6b3SRodney W. Grimes { 9935b81b6b3SRodney W. Grimes fdu_t fdu = FDUNIT(minor(dev)); 994b99f0a4aSAndrew Moore 995b99f0a4aSAndrew Moore #if NFT > 0 9963a2f7427SDavid Greenman int type = FDTYPE(minor(dev)); 9973a2f7427SDavid Greenman 998b99f0a4aSAndrew Moore if (type & F_TAPE_TYPE) 9993a2f7427SDavid Greenman return ftclose(dev, flags); 1000b99f0a4aSAndrew Moore #endif 10015b81b6b3SRodney W. Grimes fd_data[fdu].flags &= ~FD_OPEN; 10023a2f7427SDavid Greenman fd_data[fdu].options &= ~FDOPT_NORETRY; 1003dc16046fSJoerg Wunsch 10045b81b6b3SRodney W. Grimes return(0); 10055b81b6b3SRodney W. Grimes } 10065b81b6b3SRodney W. Grimes 10075b81b6b3SRodney W. Grimes 10083a2f7427SDavid Greenman /****************************************************************************/ 10093a2f7427SDavid Greenman /* fdstrategy */ 10103a2f7427SDavid Greenman /****************************************************************************/ 10113a2f7427SDavid Greenman void 10123a2f7427SDavid Greenman fdstrategy(struct buf *bp) 10133a2f7427SDavid Greenman { 1014bb6382faSJoerg Wunsch unsigned nblocks, blknum, cando; 10153a2f7427SDavid Greenman int s; 10163a2f7427SDavid Greenman fdcu_t fdcu; 10173a2f7427SDavid Greenman fdu_t fdu; 10183a2f7427SDavid Greenman fdc_p fdc; 10193a2f7427SDavid Greenman fd_p fd; 10203a2f7427SDavid Greenman size_t fdblk; 10213a2f7427SDavid Greenman 10223a2f7427SDavid Greenman fdu = FDUNIT(minor(bp->b_dev)); 10233a2f7427SDavid Greenman fd = &fd_data[fdu]; 10243a2f7427SDavid Greenman fdc = fd->fdc; 10253a2f7427SDavid Greenman fdcu = fdc->fdcu; 10263a2f7427SDavid Greenman 10273a2f7427SDavid Greenman #if NFT > 0 10283a2f7427SDavid Greenman if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) { 10293a2f7427SDavid Greenman /* ft tapes do not (yet) support strategy i/o */ 1030d3628763SRodney W. Grimes bp->b_error = ENODEV; 10313a2f7427SDavid Greenman bp->b_flags |= B_ERROR; 10323a2f7427SDavid Greenman goto bad; 10333a2f7427SDavid Greenman } 10343a2f7427SDavid Greenman /* check for controller already busy with tape */ 10353a2f7427SDavid Greenman if (fdc->flags & FDC_TAPE_BUSY) { 10363a2f7427SDavid Greenman bp->b_error = EBUSY; 10373a2f7427SDavid Greenman bp->b_flags |= B_ERROR; 10383a2f7427SDavid Greenman goto bad; 10393a2f7427SDavid Greenman } 10403a2f7427SDavid Greenman #endif 1041d3628763SRodney W. Grimes fdblk = 128 << (fd->ft->secsize); 10423a2f7427SDavid Greenman if (!(bp->b_flags & B_FORMAT)) { 10433a2f7427SDavid Greenman if ((fdu >= NFD) || (bp->b_blkno < 0)) { 1044dc5df763SJoerg Wunsch printf( 10456a0e6f42SRodney W. Grimes "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n", 1046702c623aSPoul-Henning Kamp fdu, (u_long)bp->b_blkno, bp->b_bcount); 10473a2f7427SDavid Greenman bp->b_error = EINVAL; 10483a2f7427SDavid Greenman bp->b_flags |= B_ERROR; 10493a2f7427SDavid Greenman goto bad; 10503a2f7427SDavid Greenman } 10513a2f7427SDavid Greenman if ((bp->b_bcount % fdblk) != 0) { 10523a2f7427SDavid Greenman bp->b_error = EINVAL; 10533a2f7427SDavid Greenman bp->b_flags |= B_ERROR; 10543a2f7427SDavid Greenman goto bad; 10553a2f7427SDavid Greenman } 10563a2f7427SDavid Greenman } 10573a2f7427SDavid Greenman 10583a2f7427SDavid Greenman /* 10593a2f7427SDavid Greenman * Set up block calculations. 10603a2f7427SDavid Greenman */ 1061bb6382faSJoerg Wunsch if (bp->b_blkno > 20000000) { 1062bb6382faSJoerg Wunsch /* 1063bb6382faSJoerg Wunsch * Reject unreasonably high block number, prevent the 1064bb6382faSJoerg Wunsch * multiplication below from overflowing. 1065bb6382faSJoerg Wunsch */ 1066bb6382faSJoerg Wunsch bp->b_error = EINVAL; 10673a2f7427SDavid Greenman bp->b_flags |= B_ERROR; 10683a2f7427SDavid Greenman goto bad; 10693a2f7427SDavid Greenman } 1070bb6382faSJoerg Wunsch blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk; 1071bb6382faSJoerg Wunsch nblocks = fd->ft->size; 1072bb6382faSJoerg Wunsch bp->b_resid = 0; 1073bb6382faSJoerg Wunsch if (blknum + (bp->b_bcount / fdblk) > nblocks) { 1074bb6382faSJoerg Wunsch if (blknum <= nblocks) { 1075bb6382faSJoerg Wunsch cando = (nblocks - blknum) * fdblk; 1076bb6382faSJoerg Wunsch bp->b_resid = bp->b_bcount - cando; 1077bb6382faSJoerg Wunsch if (cando == 0) 1078bb6382faSJoerg Wunsch goto bad; /* not actually bad but EOF */ 1079bb6382faSJoerg Wunsch } else { 1080bb6382faSJoerg Wunsch bp->b_error = EINVAL; 1081bb6382faSJoerg Wunsch bp->b_flags |= B_ERROR; 1082bb6382faSJoerg Wunsch goto bad; 1083bb6382faSJoerg Wunsch } 1084bb6382faSJoerg Wunsch } 108527513ca7SBruce Evans bp->b_pblkno = bp->b_blkno; 10863a2f7427SDavid Greenman s = splbio(); 108717542807SPoul-Henning Kamp tqdisksort(&fdc->head, bp); 10885e235068SJordan K. Hubbard untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */ 10893a2f7427SDavid Greenman fdstart(fdcu); 10903a2f7427SDavid Greenman splx(s); 10913a2f7427SDavid Greenman return; 10923a2f7427SDavid Greenman 10933a2f7427SDavid Greenman bad: 10943a2f7427SDavid Greenman biodone(bp); 10953a2f7427SDavid Greenman } 10963a2f7427SDavid Greenman 10975b81b6b3SRodney W. Grimes /***************************************************************\ 10985b81b6b3SRodney W. Grimes * fdstart * 10995b81b6b3SRodney W. Grimes * We have just queued something.. if the controller is not busy * 11005b81b6b3SRodney W. Grimes * then simulate the case where it has just finished a command * 11015b81b6b3SRodney W. Grimes * So that it (the interrupt routine) looks on the queue for more* 11025b81b6b3SRodney W. Grimes * work to do and picks up what we just added. * 11035b81b6b3SRodney W. Grimes * If the controller is already busy, we need do nothing, as it * 11045b81b6b3SRodney W. Grimes * will pick up our work when the present work completes * 11055b81b6b3SRodney W. Grimes \***************************************************************/ 1106381fe1aaSGarrett Wollman static void 1107dc5df763SJoerg Wunsch fdstart(fdcu_t fdcu) 11085b81b6b3SRodney W. Grimes { 11095b81b6b3SRodney W. Grimes int s; 11105b81b6b3SRodney W. Grimes 11115b81b6b3SRodney W. Grimes s = splbio(); 11125b81b6b3SRodney W. Grimes if(fdc_data[fdcu].state == DEVIDLE) 11135b81b6b3SRodney W. Grimes { 11145b81b6b3SRodney W. Grimes fdintr(fdcu); 11155b81b6b3SRodney W. Grimes } 11165b81b6b3SRodney W. Grimes splx(s); 11175b81b6b3SRodney W. Grimes } 11185b81b6b3SRodney W. Grimes 1119381fe1aaSGarrett Wollman static void 1120d0917939SPaul Richards fd_timeout(void *arg1) 11215b81b6b3SRodney W. Grimes { 1122381fe1aaSGarrett Wollman fdcu_t fdcu = (fdcu_t)arg1; 11235b81b6b3SRodney W. Grimes fdu_t fdu = fdc_data[fdcu].fdu; 11243a2f7427SDavid Greenman int baseport = fdc_data[fdcu].baseport; 112517542807SPoul-Henning Kamp struct buf *bp; 1126f5f7ba03SJordan K. Hubbard int s; 11275b81b6b3SRodney W. Grimes 112817542807SPoul-Henning Kamp bp = TAILQ_FIRST(&fdc_data[fdcu].head); 11295b81b6b3SRodney W. Grimes 11303a2f7427SDavid Greenman /* 11313a2f7427SDavid Greenman * Due to IBM's brain-dead design, the FDC has a faked ready 11323a2f7427SDavid Greenman * signal, hardwired to ready == true. Thus, any command 11333a2f7427SDavid Greenman * issued if there's no diskette in the drive will _never_ 11343a2f7427SDavid Greenman * complete, and must be aborted by resetting the FDC. 11353a2f7427SDavid Greenman * Many thanks, Big Blue! 11363a2f7427SDavid Greenman */ 11375b81b6b3SRodney W. Grimes 11383a2f7427SDavid Greenman s = splbio(); 11393a2f7427SDavid Greenman 11403a2f7427SDavid Greenman TRACE1("fd%d[fd_timeout()]", fdu); 11413a2f7427SDavid Greenman /* See if the controller is still busy (patiently awaiting data) */ 11423a2f7427SDavid Greenman if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB) 11433a2f7427SDavid Greenman { 11443a2f7427SDavid Greenman TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS)); 11453a2f7427SDavid Greenman /* yup, it is; kill it now */ 11463a2f7427SDavid Greenman fdc_reset(&fdc_data[fdcu]); 11473a2f7427SDavid Greenman printf("fd%d: Operation timeout\n", fdu); 11483a2f7427SDavid Greenman } 11495b81b6b3SRodney W. Grimes 11505b81b6b3SRodney W. Grimes if (bp) 11515b81b6b3SRodney W. Grimes { 11525b81b6b3SRodney W. Grimes retrier(fdcu); 11533a2f7427SDavid Greenman fdc_data[fdcu].status[0] = NE7_ST0_IC_RC; 11545b81b6b3SRodney W. Grimes fdc_data[fdcu].state = IOTIMEDOUT; 11555b81b6b3SRodney W. Grimes if( fdc_data[fdcu].retry < 6) 11565b81b6b3SRodney W. Grimes fdc_data[fdcu].retry = 6; 11575b81b6b3SRodney W. Grimes } 11585b81b6b3SRodney W. Grimes else 11595b81b6b3SRodney W. Grimes { 11605b81b6b3SRodney W. Grimes fdc_data[fdcu].fd = (fd_p) 0; 11615b81b6b3SRodney W. Grimes fdc_data[fdcu].fdu = -1; 11625b81b6b3SRodney W. Grimes fdc_data[fdcu].state = DEVIDLE; 11635b81b6b3SRodney W. Grimes } 1164f5f7ba03SJordan K. Hubbard fdintr(fdcu); 1165f5f7ba03SJordan K. Hubbard splx(s); 11665b81b6b3SRodney W. Grimes } 11675b81b6b3SRodney W. Grimes 11685b81b6b3SRodney W. Grimes /* just ensure it has the right spl */ 1169381fe1aaSGarrett Wollman static void 1170d0917939SPaul Richards fd_pseudointr(void *arg1) 11715b81b6b3SRodney W. Grimes { 1172381fe1aaSGarrett Wollman fdcu_t fdcu = (fdcu_t)arg1; 11735b81b6b3SRodney W. Grimes int s; 11743a2f7427SDavid Greenman 11755b81b6b3SRodney W. Grimes s = splbio(); 11765b81b6b3SRodney W. Grimes fdintr(fdcu); 11775b81b6b3SRodney W. Grimes splx(s); 11785b81b6b3SRodney W. Grimes } 11795b81b6b3SRodney W. Grimes 11805b81b6b3SRodney W. Grimes /***********************************************************************\ 11815b81b6b3SRodney W. Grimes * fdintr * 11825b81b6b3SRodney W. Grimes * keep calling the state machine until it returns a 0 * 11835b81b6b3SRodney W. Grimes * ALWAYS called at SPLBIO * 11845b81b6b3SRodney W. Grimes \***********************************************************************/ 1185381fe1aaSGarrett Wollman void 1186381fe1aaSGarrett Wollman fdintr(fdcu_t fdcu) 11875b81b6b3SRodney W. Grimes { 11885b81b6b3SRodney W. Grimes fdc_p fdc = fdc_data + fdcu; 1189b99f0a4aSAndrew Moore #if NFT > 0 1190b99f0a4aSAndrew Moore fdu_t fdu = fdc->fdu; 1191b99f0a4aSAndrew Moore 1192b99f0a4aSAndrew Moore if (fdc->flags & FDC_TAPE_BUSY) 1193b99f0a4aSAndrew Moore (ftintr(fdu)); 1194b99f0a4aSAndrew Moore else 1195b99f0a4aSAndrew Moore #endif 1196381fe1aaSGarrett Wollman while(fdstate(fdcu, fdc)) 1197381fe1aaSGarrett Wollman ; 11985b81b6b3SRodney W. Grimes } 11995b81b6b3SRodney W. Grimes 12005b81b6b3SRodney W. Grimes /***********************************************************************\ 12015b81b6b3SRodney W. Grimes * The controller state machine. * 12025b81b6b3SRodney W. Grimes * if it returns a non zero value, it should be called again immediatly * 12035b81b6b3SRodney W. Grimes \***********************************************************************/ 12043a2f7427SDavid Greenman static int 1205dc5df763SJoerg Wunsch fdstate(fdcu_t fdcu, fdc_p fdc) 12065b81b6b3SRodney W. Grimes { 12074ccc87c5SPoul-Henning Kamp int read, format, head, sec = 0, sectrac, st0, cyl, st3; 1208bb6382faSJoerg Wunsch unsigned blknum = 0, b_cylinder = 0; 12095b81b6b3SRodney W. Grimes fdu_t fdu = fdc->fdu; 12105b81b6b3SRodney W. Grimes fd_p fd; 121117542807SPoul-Henning Kamp register struct buf *bp; 1212b39c878eSAndrey A. Chernov struct fd_formb *finfo = NULL; 12133a2f7427SDavid Greenman size_t fdblk; 12145b81b6b3SRodney W. Grimes 121514212c9dSPoul-Henning Kamp bp = TAILQ_FIRST(&fdc->head); 121617542807SPoul-Henning Kamp if(!bp) { 12175b81b6b3SRodney W. Grimes /***********************************************\ 12185b81b6b3SRodney W. Grimes * nothing left for this controller to do * 12195b81b6b3SRodney W. Grimes * Force into the IDLE state, * 12205b81b6b3SRodney W. Grimes \***********************************************/ 12215b81b6b3SRodney W. Grimes fdc->state = DEVIDLE; 12225b81b6b3SRodney W. Grimes if(fdc->fd) 12235b81b6b3SRodney W. Grimes { 12246a0e6f42SRodney W. Grimes printf("fd%d: unexpected valid fd pointer\n", 12253a2f7427SDavid Greenman fdc->fdu); 12265b81b6b3SRodney W. Grimes fdc->fd = (fd_p) 0; 12275b81b6b3SRodney W. Grimes fdc->fdu = -1; 12285b81b6b3SRodney W. Grimes } 12295b81b6b3SRodney W. Grimes TRACE1("[fdc%d IDLE]", fdcu); 12305b81b6b3SRodney W. Grimes return(0); 12315b81b6b3SRodney W. Grimes } 12325b81b6b3SRodney W. Grimes fdu = FDUNIT(minor(bp->b_dev)); 12335b81b6b3SRodney W. Grimes fd = fd_data + fdu; 12343a2f7427SDavid Greenman fdblk = 128 << fd->ft->secsize; 12355b81b6b3SRodney W. Grimes if (fdc->fd && (fd != fdc->fd)) 12365b81b6b3SRodney W. Grimes { 12376a0e6f42SRodney W. Grimes printf("fd%d: confused fd pointers\n", fdu); 12385b81b6b3SRodney W. Grimes } 12395b81b6b3SRodney W. Grimes read = bp->b_flags & B_READ; 1240b39c878eSAndrey A. Chernov format = bp->b_flags & B_FORMAT; 1241bb6382faSJoerg Wunsch if(format) { 1242b39c878eSAndrey A. Chernov finfo = (struct fd_formb *)bp->b_un.b_addr; 1243bb6382faSJoerg Wunsch fd->skip = (char *)&(finfo->fd_formb_cylno(0)) 1244bb6382faSJoerg Wunsch - (char *)finfo; 1245bb6382faSJoerg Wunsch } 1246bb6382faSJoerg Wunsch if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { 1247bb6382faSJoerg Wunsch blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk + 1248bb6382faSJoerg Wunsch fd->skip/fdblk; 1249bb6382faSJoerg Wunsch b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); 1250bb6382faSJoerg Wunsch } 12515b81b6b3SRodney W. Grimes TRACE1("fd%d", fdu); 12525b81b6b3SRodney W. Grimes TRACE1("[%s]", fdstates[fdc->state]); 12535b81b6b3SRodney W. Grimes TRACE1("(0x%x)", fd->flags); 12545e235068SJordan K. Hubbard untimeout(fd_turnoff, (caddr_t)fdu); 12555e235068SJordan K. Hubbard timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); 12565b81b6b3SRodney W. Grimes switch (fdc->state) 12575b81b6b3SRodney W. Grimes { 12585b81b6b3SRodney W. Grimes case DEVIDLE: 12595b81b6b3SRodney W. Grimes case FINDWORK: /* we have found new work */ 12605b81b6b3SRodney W. Grimes fdc->retry = 0; 12615b81b6b3SRodney W. Grimes fd->skip = 0; 12625b81b6b3SRodney W. Grimes fdc->fd = fd; 12635b81b6b3SRodney W. Grimes fdc->fdu = fdu; 12643a2f7427SDavid Greenman outb(fdc->baseport+FDCTL, fd->ft->trans); 12653a2f7427SDavid Greenman TRACE1("[0x%x->FDCTL]", fd->ft->trans); 12665b81b6b3SRodney W. Grimes /*******************************************************\ 12675b81b6b3SRodney W. Grimes * If the next drive has a motor startup pending, then * 12685b81b6b3SRodney W. Grimes * it will start up in it's own good time * 12695b81b6b3SRodney W. Grimes \*******************************************************/ 12705b81b6b3SRodney W. Grimes if(fd->flags & FD_MOTOR_WAIT) 12715b81b6b3SRodney W. Grimes { 12725b81b6b3SRodney W. Grimes fdc->state = MOTORWAIT; 12735b81b6b3SRodney W. Grimes return(0); /* come back later */ 12745b81b6b3SRodney W. Grimes } 12755b81b6b3SRodney W. Grimes /*******************************************************\ 12765b81b6b3SRodney W. Grimes * Maybe if it's not starting, it SHOULD be starting * 12775b81b6b3SRodney W. Grimes \*******************************************************/ 12785b81b6b3SRodney W. Grimes if (!(fd->flags & FD_MOTOR)) 12795b81b6b3SRodney W. Grimes { 12805b81b6b3SRodney W. Grimes fdc->state = MOTORWAIT; 12815b81b6b3SRodney W. Grimes fd_turnon(fdu); 12825b81b6b3SRodney W. Grimes return(0); 12835b81b6b3SRodney W. Grimes } 12845b81b6b3SRodney W. Grimes else /* at least make sure we are selected */ 12855b81b6b3SRodney W. Grimes { 12863a2f7427SDavid Greenman set_motor(fdcu, fd->fdsu, TURNON); 12875b81b6b3SRodney W. Grimes } 12885e235068SJordan K. Hubbard fdc->state = DOSEEK; 12895b81b6b3SRodney W. Grimes break; 12905b81b6b3SRodney W. Grimes case DOSEEK: 1291bb6382faSJoerg Wunsch if (b_cylinder == (unsigned)fd->track) 12925b81b6b3SRodney W. Grimes { 12935b81b6b3SRodney W. Grimes fdc->state = SEEKCOMPLETE; 12945b81b6b3SRodney W. Grimes break; 12955b81b6b3SRodney W. Grimes } 1296dc5df763SJoerg Wunsch if (fd_cmd(fdcu, 3, NE7CMD_SEEK, 1297bb6382faSJoerg Wunsch fd->fdsu, b_cylinder * fd->ft->steptrac, 1298dc5df763SJoerg Wunsch 0)) 1299dc8603e3SJoerg Wunsch { 1300dc8603e3SJoerg Wunsch /* 1301dc8603e3SJoerg Wunsch * seek command not accepted, looks like 1302dc8603e3SJoerg Wunsch * the FDC went off to the Saints... 1303dc8603e3SJoerg Wunsch */ 1304dc8603e3SJoerg Wunsch fdc->retry = 6; /* try a reset */ 1305dc8603e3SJoerg Wunsch return(retrier(fdcu)); 1306dc8603e3SJoerg Wunsch } 1307dc5df763SJoerg Wunsch fd->track = FD_NO_TRACK; 13085b81b6b3SRodney W. Grimes fdc->state = SEEKWAIT; 13095b81b6b3SRodney W. Grimes return(0); /* will return later */ 13105b81b6b3SRodney W. Grimes case SEEKWAIT: 13115b81b6b3SRodney W. Grimes /* allow heads to settle */ 131204b734cfSPoul-Henning Kamp timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16); 13135b81b6b3SRodney W. Grimes fdc->state = SEEKCOMPLETE; 13145b81b6b3SRodney W. Grimes return(0); /* will return later */ 13155b81b6b3SRodney W. Grimes case SEEKCOMPLETE : /* SEEK DONE, START DMA */ 13165b81b6b3SRodney W. Grimes /* Make sure seek really happened*/ 1317dc5df763SJoerg Wunsch if(fd->track == FD_NO_TRACK) 13185b81b6b3SRodney W. Grimes { 1319bb6382faSJoerg Wunsch int descyl = b_cylinder * fd->ft->steptrac; 13203a2f7427SDavid Greenman do { 13213a2f7427SDavid Greenman /* 1322dc5df763SJoerg Wunsch * This might be a "ready changed" interrupt, 1323dc5df763SJoerg Wunsch * which cannot really happen since the 1324dc5df763SJoerg Wunsch * RDY pin is hardwired to + 5 volts. This 1325dc5df763SJoerg Wunsch * generally indicates a "bouncing" intr 1326dc5df763SJoerg Wunsch * line, so do one of the following: 1327dc5df763SJoerg Wunsch * 1328dc5df763SJoerg Wunsch * When running on an enhanced FDC that is 1329dc5df763SJoerg Wunsch * known to not go stuck after responding 1330dc5df763SJoerg Wunsch * with INVALID, fetch all interrupt states 1331dc5df763SJoerg Wunsch * until seeing either an INVALID or a 1332dc5df763SJoerg Wunsch * real interrupt condition. 1333dc5df763SJoerg Wunsch * 1334dc5df763SJoerg Wunsch * When running on a dumb old NE765, give 1335dc5df763SJoerg Wunsch * up immediately. The controller will 1336dc5df763SJoerg Wunsch * provide up to four dummy RC interrupt 1337dc5df763SJoerg Wunsch * conditions right after reset (for the 1338dc5df763SJoerg Wunsch * corresponding four drives), so this is 1339dc5df763SJoerg Wunsch * our only chance to get notice that it 1340dc5df763SJoerg Wunsch * was not the FDC that caused the interrupt. 13413a2f7427SDavid Greenman */ 1342dc5df763SJoerg Wunsch if (fd_sense_int(fdc, &st0, &cyl) 1343dc5df763SJoerg Wunsch == FD_NOT_VALID) 1344dc5df763SJoerg Wunsch return 0; 1345dc5df763SJoerg Wunsch if(fdc->fdct == FDC_NE765 1346dc5df763SJoerg Wunsch && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 1347dc5df763SJoerg Wunsch return 0; /* hope for a real intr */ 13483a2f7427SDavid Greenman } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 1349dc5df763SJoerg Wunsch 13503a2f7427SDavid Greenman if (0 == descyl) 13513a2f7427SDavid Greenman { 1352dc5df763SJoerg Wunsch int failed = 0; 13533a2f7427SDavid Greenman /* 13543a2f7427SDavid Greenman * seek to cyl 0 requested; make sure we are 13553a2f7427SDavid Greenman * really there 13563a2f7427SDavid Greenman */ 1357dc5df763SJoerg Wunsch if (fd_sense_drive_status(fdc, &st3)) 1358dc5df763SJoerg Wunsch failed = 1; 13593a2f7427SDavid Greenman if ((st3 & NE7_ST3_T0) == 0) { 13603a2f7427SDavid Greenman printf( 13613a2f7427SDavid Greenman "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", 13623a2f7427SDavid Greenman fdu, st3, NE7_ST3BITS); 1363dc5df763SJoerg Wunsch failed = 1; 1364dc5df763SJoerg Wunsch } 1365dc5df763SJoerg Wunsch 1366dc5df763SJoerg Wunsch if (failed) 1367dc5df763SJoerg Wunsch { 13683a2f7427SDavid Greenman if(fdc->retry < 3) 13693a2f7427SDavid Greenman fdc->retry = 3; 13703a2f7427SDavid Greenman return(retrier(fdcu)); 13713a2f7427SDavid Greenman } 13723a2f7427SDavid Greenman } 1373dc5df763SJoerg Wunsch 13745b81b6b3SRodney W. Grimes if (cyl != descyl) 13755b81b6b3SRodney W. Grimes { 13763a2f7427SDavid Greenman printf( 13773a2f7427SDavid Greenman "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", 13782d9d0204SRodney W. Grimes fdu, descyl, cyl, st0); 13795b81b6b3SRodney W. Grimes return(retrier(fdcu)); 13805b81b6b3SRodney W. Grimes } 13815b81b6b3SRodney W. Grimes } 13825b81b6b3SRodney W. Grimes 1383bb6382faSJoerg Wunsch fd->track = b_cylinder; 13845b81b6b3SRodney W. Grimes isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, 13853a2f7427SDavid Greenman format ? bp->b_bcount : fdblk, fdc->dmachan); 13865b81b6b3SRodney W. Grimes sectrac = fd->ft->sectrac; 13875b81b6b3SRodney W. Grimes sec = blknum % (sectrac * fd->ft->heads); 13885b81b6b3SRodney W. Grimes head = sec / sectrac; 13895b81b6b3SRodney W. Grimes sec = sec % sectrac + 1; 13903a2f7427SDavid Greenman fd->hddrv = ((head&1)<<2)+fdu; 13913a2f7427SDavid Greenman 13923a2f7427SDavid Greenman if(format || !read) 13933a2f7427SDavid Greenman { 13943a2f7427SDavid Greenman /* make sure the drive is writable */ 1395dc5df763SJoerg Wunsch if(fd_sense_drive_status(fdc, &st3) != 0) 1396dc8603e3SJoerg Wunsch { 1397dc8603e3SJoerg Wunsch /* stuck controller? */ 1398dc8603e3SJoerg Wunsch fdc->retry = 6; /* reset the beast */ 1399dc8603e3SJoerg Wunsch return(retrier(fdcu)); 1400dc8603e3SJoerg Wunsch } 14013a2f7427SDavid Greenman if(st3 & NE7_ST3_WP) 14023a2f7427SDavid Greenman { 14033a2f7427SDavid Greenman /* 14043a2f7427SDavid Greenman * XXX YES! this is ugly. 14053a2f7427SDavid Greenman * in order to force the current operation 14063a2f7427SDavid Greenman * to fail, we will have to fake an FDC 14073a2f7427SDavid Greenman * error - all error handling is done 14083a2f7427SDavid Greenman * by the retrier() 14093a2f7427SDavid Greenman */ 14103a2f7427SDavid Greenman fdc->status[0] = NE7_ST0_IC_AT; 14113a2f7427SDavid Greenman fdc->status[1] = NE7_ST1_NW; 14123a2f7427SDavid Greenman fdc->status[2] = 0; 14133a2f7427SDavid Greenman fdc->status[3] = fd->track; 14143a2f7427SDavid Greenman fdc->status[4] = head; 14153a2f7427SDavid Greenman fdc->status[5] = sec; 14163a2f7427SDavid Greenman fdc->retry = 8; /* break out immediately */ 14173a2f7427SDavid Greenman fdc->state = IOTIMEDOUT; /* not really... */ 14183a2f7427SDavid Greenman return (1); 14193a2f7427SDavid Greenman } 14203a2f7427SDavid Greenman } 14215b81b6b3SRodney W. Grimes 1422b39c878eSAndrey A. Chernov if(format) 1423b39c878eSAndrey A. Chernov { 1424b39c878eSAndrey A. Chernov /* formatting */ 1425dc5df763SJoerg Wunsch if(fd_cmd(fdcu, 6, 1426dc5df763SJoerg Wunsch NE7CMD_FORMAT, 1427dc5df763SJoerg Wunsch head << 2 | fdu, 1428dc5df763SJoerg Wunsch finfo->fd_formb_secshift, 1429dc5df763SJoerg Wunsch finfo->fd_formb_nsecs, 1430dc5df763SJoerg Wunsch finfo->fd_formb_gaplen, 1431dc5df763SJoerg Wunsch finfo->fd_formb_fillbyte, 1432dc5df763SJoerg Wunsch 0)) 1433dc8603e3SJoerg Wunsch { 1434dc8603e3SJoerg Wunsch /* controller fell over */ 1435dc8603e3SJoerg Wunsch fdc->retry = 6; 1436dc8603e3SJoerg Wunsch return(retrier(fdcu)); 1437dc8603e3SJoerg Wunsch } 1438b39c878eSAndrey A. Chernov } 1439b39c878eSAndrey A. Chernov else 1440b39c878eSAndrey A. Chernov { 1441dc5df763SJoerg Wunsch if (fd_cmd(fdcu, 9, 1442dc5df763SJoerg Wunsch (read ? NE7CMD_READ : NE7CMD_WRITE), 1443dc5df763SJoerg Wunsch head << 2 | fdu, /* head & unit */ 1444dc5df763SJoerg Wunsch fd->track, /* track */ 1445dc5df763SJoerg Wunsch head, 1446dc5df763SJoerg Wunsch sec, /* sector + 1 */ 1447dc5df763SJoerg Wunsch fd->ft->secsize, /* sector size */ 1448dc5df763SJoerg Wunsch sectrac, /* sectors/track */ 1449dc5df763SJoerg Wunsch fd->ft->gap, /* gap size */ 1450dc5df763SJoerg Wunsch fd->ft->datalen, /* data length */ 1451dc5df763SJoerg Wunsch 0)) 14525b81b6b3SRodney W. Grimes { 1453dc8603e3SJoerg Wunsch /* the beast is sleeping again */ 1454dc8603e3SJoerg Wunsch fdc->retry = 6; 1455dc8603e3SJoerg Wunsch return(retrier(fdcu)); 14565b81b6b3SRodney W. Grimes } 1457b39c878eSAndrey A. Chernov } 14585b81b6b3SRodney W. Grimes fdc->state = IOCOMPLETE; 14595e235068SJordan K. Hubbard timeout(fd_timeout, (caddr_t)fdcu, hz); 14605b81b6b3SRodney W. Grimes return(0); /* will return later */ 14615b81b6b3SRodney W. Grimes case IOCOMPLETE: /* IO DONE, post-analyze */ 14625e235068SJordan K. Hubbard untimeout(fd_timeout, (caddr_t)fdcu); 1463dc5df763SJoerg Wunsch 1464dc5df763SJoerg Wunsch if (fd_read_status(fdc, fd->fdsu)) 14655b81b6b3SRodney W. Grimes { 1466dc5df763SJoerg Wunsch if (fdc->retry < 6) 1467dc5df763SJoerg Wunsch fdc->retry = 6; /* force a reset */ 1468dc5df763SJoerg Wunsch return retrier(fdcu); 14695b81b6b3SRodney W. Grimes } 1470dc5df763SJoerg Wunsch 14713a2f7427SDavid Greenman fdc->state = IOTIMEDOUT; 1472dc5df763SJoerg Wunsch 14733a2f7427SDavid Greenman /* FALLTHROUGH */ 1474dc5df763SJoerg Wunsch 14753a2f7427SDavid Greenman case IOTIMEDOUT: 14765b81b6b3SRodney W. Grimes isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, 14773a2f7427SDavid Greenman format ? bp->b_bcount : fdblk, fdc->dmachan); 14783a2f7427SDavid Greenman if (fdc->status[0] & NE7_ST0_IC) 14795b81b6b3SRodney W. Grimes { 14803a2f7427SDavid Greenman if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 14813a2f7427SDavid Greenman && fdc->status[1] & NE7_ST1_OR) { 1482b39c878eSAndrey A. Chernov /* 14833a2f7427SDavid Greenman * DMA overrun. Someone hogged the bus 14843a2f7427SDavid Greenman * and didn't release it in time for the 14853a2f7427SDavid Greenman * next FDC transfer. 14863a2f7427SDavid Greenman * Just restart it, don't increment retry 14873a2f7427SDavid Greenman * count. (vak) 1488b39c878eSAndrey A. Chernov */ 1489b39c878eSAndrey A. Chernov fdc->state = SEEKCOMPLETE; 1490b39c878eSAndrey A. Chernov return (1); 1491b39c878eSAndrey A. Chernov } 14923a2f7427SDavid Greenman else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV 14933a2f7427SDavid Greenman && fdc->retry < 6) 14943a2f7427SDavid Greenman fdc->retry = 6; /* force a reset */ 14953a2f7427SDavid Greenman else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 14963a2f7427SDavid Greenman && fdc->status[2] & NE7_ST2_WC 14973a2f7427SDavid Greenman && fdc->retry < 3) 14983a2f7427SDavid Greenman fdc->retry = 3; /* force recalibrate */ 14995b81b6b3SRodney W. Grimes return(retrier(fdcu)); 15005b81b6b3SRodney W. Grimes } 15015b81b6b3SRodney W. Grimes /* All OK */ 15023a2f7427SDavid Greenman fd->skip += fdblk; 1503bb6382faSJoerg Wunsch if (!format && fd->skip < bp->b_bcount - bp->b_resid) 15045b81b6b3SRodney W. Grimes { 15055b81b6b3SRodney W. Grimes /* set up next transfer */ 15065b81b6b3SRodney W. Grimes fdc->state = DOSEEK; 15075b81b6b3SRodney W. Grimes } 15085b81b6b3SRodney W. Grimes else 15095b81b6b3SRodney W. Grimes { 15105b81b6b3SRodney W. Grimes /* ALL DONE */ 15115b81b6b3SRodney W. Grimes fd->skip = 0; 151217542807SPoul-Henning Kamp TAILQ_REMOVE(&fdc->head, bp, b_act); 15135b81b6b3SRodney W. Grimes biodone(bp); 15145b81b6b3SRodney W. Grimes fdc->fd = (fd_p) 0; 15155b81b6b3SRodney W. Grimes fdc->fdu = -1; 15165b81b6b3SRodney W. Grimes fdc->state = FINDWORK; 15175b81b6b3SRodney W. Grimes } 15185b81b6b3SRodney W. Grimes return(1); 15195b81b6b3SRodney W. Grimes case RESETCTLR: 15203a2f7427SDavid Greenman fdc_reset(fdc); 15215b81b6b3SRodney W. Grimes fdc->retry++; 15225b81b6b3SRodney W. Grimes fdc->state = STARTRECAL; 15235b81b6b3SRodney W. Grimes break; 15245b81b6b3SRodney W. Grimes case STARTRECAL: 15250e317d05SJoerg Wunsch /* XXX clear the fdc results from the last reset, if any. */ 15260e317d05SJoerg Wunsch { 15270e317d05SJoerg Wunsch int i; 15280e317d05SJoerg Wunsch for (i = 0; i < 4; i++) 15290e317d05SJoerg Wunsch (void)fd_sense_int(fdc, &st0, &cyl); 15300e317d05SJoerg Wunsch } 15310e317d05SJoerg Wunsch 1532dc5df763SJoerg Wunsch if(fd_cmd(fdcu, 1533dc5df763SJoerg Wunsch 2, NE7CMD_RECAL, fdu, 1534dc5df763SJoerg Wunsch 0)) /* Recalibrate Function */ 1535dc8603e3SJoerg Wunsch { 1536dc8603e3SJoerg Wunsch /* arrgl */ 1537dc8603e3SJoerg Wunsch fdc->retry = 6; 1538dc8603e3SJoerg Wunsch return(retrier(fdcu)); 1539dc8603e3SJoerg Wunsch } 15405b81b6b3SRodney W. Grimes fdc->state = RECALWAIT; 15415b81b6b3SRodney W. Grimes return(0); /* will return later */ 15425b81b6b3SRodney W. Grimes case RECALWAIT: 15435b81b6b3SRodney W. Grimes /* allow heads to settle */ 154404b734cfSPoul-Henning Kamp timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8); 15455b81b6b3SRodney W. Grimes fdc->state = RECALCOMPLETE; 15465b81b6b3SRodney W. Grimes return(0); /* will return later */ 15475b81b6b3SRodney W. Grimes case RECALCOMPLETE: 15483a2f7427SDavid Greenman do { 15493a2f7427SDavid Greenman /* 1550dc5df763SJoerg Wunsch * See SEEKCOMPLETE for a comment on this: 15513a2f7427SDavid Greenman */ 1552dc5df763SJoerg Wunsch if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID) 1553dc5df763SJoerg Wunsch return 0; 1554dc5df763SJoerg Wunsch if(fdc->fdct == FDC_NE765 1555dc5df763SJoerg Wunsch && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 1556dc5df763SJoerg Wunsch return 0; /* hope for a real intr */ 15573a2f7427SDavid Greenman } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 15583a2f7427SDavid Greenman if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) 15595b81b6b3SRodney W. Grimes { 1560dc8603e3SJoerg Wunsch if(fdc->retry > 3) 1561dc8603e3SJoerg Wunsch /* 1562dc8603e3SJoerg Wunsch * a recalibrate from beyond cylinder 77 1563dc8603e3SJoerg Wunsch * will "fail" due to the FDC limitations; 1564dc8603e3SJoerg Wunsch * since people used to complain much about 1565dc8603e3SJoerg Wunsch * the failure message, try not logging 1566dc8603e3SJoerg Wunsch * this one if it seems to be the first 1567dc8603e3SJoerg Wunsch * time in a line 1568dc8603e3SJoerg Wunsch */ 1569dc8603e3SJoerg Wunsch printf("fd%d: recal failed ST0 %b cyl %d\n", 1570dc8603e3SJoerg Wunsch fdu, st0, NE7_ST0BITS, cyl); 15713a2f7427SDavid Greenman if(fdc->retry < 3) fdc->retry = 3; 15725b81b6b3SRodney W. Grimes return(retrier(fdcu)); 15735b81b6b3SRodney W. Grimes } 15745b81b6b3SRodney W. Grimes fd->track = 0; 15755b81b6b3SRodney W. Grimes /* Seek (probably) necessary */ 15765b81b6b3SRodney W. Grimes fdc->state = DOSEEK; 15775b81b6b3SRodney W. Grimes return(1); /* will return immediatly */ 15785b81b6b3SRodney W. Grimes case MOTORWAIT: 15795b81b6b3SRodney W. Grimes if(fd->flags & FD_MOTOR_WAIT) 15805b81b6b3SRodney W. Grimes { 15815b81b6b3SRodney W. Grimes return(0); /* time's not up yet */ 15825b81b6b3SRodney W. Grimes } 15835e235068SJordan K. Hubbard /* 15845e235068SJordan K. Hubbard * since the controller was off, it has lost its 15855e235068SJordan K. Hubbard * idea about the current track it were; thus, 15865e235068SJordan K. Hubbard * recalibrate the bastard 15875e235068SJordan K. Hubbard */ 15885e235068SJordan K. Hubbard fdc->state = STARTRECAL; 15895b81b6b3SRodney W. Grimes return(1); /* will return immediatly */ 15905b81b6b3SRodney W. Grimes default: 1591dc5df763SJoerg Wunsch printf("fdc%d: Unexpected FD int->", fdcu); 1592dc5df763SJoerg Wunsch if (fd_read_status(fdc, fd->fdsu) == 0) 1593dac0f2dbSJoerg Wunsch printf("FDC status :%lx %lx %lx %lx %lx %lx %lx ", 15945b81b6b3SRodney W. Grimes fdc->status[0], 15955b81b6b3SRodney W. Grimes fdc->status[1], 15965b81b6b3SRodney W. Grimes fdc->status[2], 15975b81b6b3SRodney W. Grimes fdc->status[3], 15985b81b6b3SRodney W. Grimes fdc->status[4], 15995b81b6b3SRodney W. Grimes fdc->status[5], 16005b81b6b3SRodney W. Grimes fdc->status[6] ); 16013a2f7427SDavid Greenman else 1602dac0f2dbSJoerg Wunsch printf("No status available "); 1603dac0f2dbSJoerg Wunsch if (fd_sense_int(fdc, &st0, &cyl) != 0) 1604dac0f2dbSJoerg Wunsch { 1605dac0f2dbSJoerg Wunsch printf("[controller is dead now]\n"); 16065b81b6b3SRodney W. Grimes return(0); 16075b81b6b3SRodney W. Grimes } 1608dac0f2dbSJoerg Wunsch printf("ST0 = %x, PCN = %x\n", st0, cyl); 1609dac0f2dbSJoerg Wunsch return(0); 1610dac0f2dbSJoerg Wunsch } 1611dac0f2dbSJoerg Wunsch /*XXX confusing: some branches return immediately, others end up here*/ 16125b81b6b3SRodney W. Grimes return(1); /* Come back immediatly to new state */ 16135b81b6b3SRodney W. Grimes } 16145b81b6b3SRodney W. Grimes 1615aaf08d94SGarrett Wollman static int 1616f5f7ba03SJordan K. Hubbard retrier(fdcu) 1617f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 16185b81b6b3SRodney W. Grimes { 16195b81b6b3SRodney W. Grimes fdc_p fdc = fdc_data + fdcu; 162017542807SPoul-Henning Kamp register struct buf *bp; 16215b81b6b3SRodney W. Grimes 162217542807SPoul-Henning Kamp bp = TAILQ_FIRST(&fdc->head); 16235b81b6b3SRodney W. Grimes 16243a2f7427SDavid Greenman if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) 16253a2f7427SDavid Greenman goto fail; 16265b81b6b3SRodney W. Grimes switch(fdc->retry) 16275b81b6b3SRodney W. Grimes { 16285b81b6b3SRodney W. Grimes case 0: case 1: case 2: 16295b81b6b3SRodney W. Grimes fdc->state = SEEKCOMPLETE; 16305b81b6b3SRodney W. Grimes break; 16315b81b6b3SRodney W. Grimes case 3: case 4: case 5: 16325b81b6b3SRodney W. Grimes fdc->state = STARTRECAL; 16335b81b6b3SRodney W. Grimes break; 16345b81b6b3SRodney W. Grimes case 6: 16355b81b6b3SRodney W. Grimes fdc->state = RESETCTLR; 16365b81b6b3SRodney W. Grimes break; 16375b81b6b3SRodney W. Grimes case 7: 16385b81b6b3SRodney W. Grimes break; 16395b81b6b3SRodney W. Grimes default: 16403a2f7427SDavid Greenman fail: 16415b81b6b3SRodney W. Grimes { 16427ca0641bSAndrey A. Chernov dev_t sav_b_dev = bp->b_dev; 16437ca0641bSAndrey A. Chernov /* Trick diskerr */ 16443a2f7427SDavid Greenman bp->b_dev = makedev(major(bp->b_dev), 16453a2f7427SDavid Greenman (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); 164692ed385aSRodney W. Grimes diskerr(bp, "fd", "hard error", LOG_PRINTF, 16473a2f7427SDavid Greenman fdc->fd->skip / DEV_BSIZE, 16483a2f7427SDavid Greenman (struct disklabel *)NULL); 16497ca0641bSAndrey A. Chernov bp->b_dev = sav_b_dev; 1650dc5df763SJoerg Wunsch if (fdc->flags & FDC_STAT_VALID) 1651dc5df763SJoerg Wunsch { 1652dc5df763SJoerg Wunsch printf( 1653dc5df763SJoerg Wunsch " (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n", 1654dc5df763SJoerg Wunsch fdc->status[0], NE7_ST0BITS, 1655dc5df763SJoerg Wunsch fdc->status[1], NE7_ST1BITS, 1656dc5df763SJoerg Wunsch fdc->status[2], NE7_ST2BITS, 1657dc5df763SJoerg Wunsch fdc->status[3], fdc->status[4], 1658dc5df763SJoerg Wunsch fdc->status[5]); 1659dc5df763SJoerg Wunsch } 1660dc5df763SJoerg Wunsch else 1661dc5df763SJoerg Wunsch printf(" (No status)\n"); 16625b81b6b3SRodney W. Grimes } 16635b81b6b3SRodney W. Grimes bp->b_flags |= B_ERROR; 16645b81b6b3SRodney W. Grimes bp->b_error = EIO; 1665bb6382faSJoerg Wunsch bp->b_resid += bp->b_bcount - fdc->fd->skip; 166617542807SPoul-Henning Kamp TAILQ_REMOVE(&fdc->head, bp, b_act); 16675b81b6b3SRodney W. Grimes fdc->fd->skip = 0; 16685b81b6b3SRodney W. Grimes biodone(bp); 166992ed385aSRodney W. Grimes fdc->state = FINDWORK; 16705b81b6b3SRodney W. Grimes fdc->fd = (fd_p) 0; 16715b81b6b3SRodney W. Grimes fdc->fdu = -1; 1672f5f7ba03SJordan K. Hubbard /* XXX abort current command, if any. */ 167392ed385aSRodney W. Grimes return(1); 16745b81b6b3SRodney W. Grimes } 16755b81b6b3SRodney W. Grimes fdc->retry++; 16765b81b6b3SRodney W. Grimes return(1); 16775b81b6b3SRodney W. Grimes } 16785b81b6b3SRodney W. Grimes 1679b39c878eSAndrey A. Chernov static int 1680b39c878eSAndrey A. Chernov fdformat(dev, finfo, p) 1681b39c878eSAndrey A. Chernov dev_t dev; 1682b39c878eSAndrey A. Chernov struct fd_formb *finfo; 1683b39c878eSAndrey A. Chernov struct proc *p; 1684b39c878eSAndrey A. Chernov { 1685b39c878eSAndrey A. Chernov fdu_t fdu; 1686b39c878eSAndrey A. Chernov fd_p fd; 1687b39c878eSAndrey A. Chernov 1688b39c878eSAndrey A. Chernov struct buf *bp; 1689b39c878eSAndrey A. Chernov int rv = 0, s; 16903a2f7427SDavid Greenman size_t fdblk; 1691b39c878eSAndrey A. Chernov 1692b39c878eSAndrey A. Chernov fdu = FDUNIT(minor(dev)); 1693b39c878eSAndrey A. Chernov fd = &fd_data[fdu]; 16943a2f7427SDavid Greenman fdblk = 128 << fd->ft->secsize; 1695b39c878eSAndrey A. Chernov 1696b39c878eSAndrey A. Chernov /* set up a buffer header for fdstrategy() */ 1697b39c878eSAndrey A. Chernov bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1698b39c878eSAndrey A. Chernov if(bp == 0) 1699b39c878eSAndrey A. Chernov return ENOBUFS; 170082f5379bSJoerg Wunsch /* 170182f5379bSJoerg Wunsch * keep the process from being swapped 170282f5379bSJoerg Wunsch */ 170382f5379bSJoerg Wunsch p->p_flag |= P_PHYSIO; 1704b39c878eSAndrey A. Chernov bzero((void *)bp, sizeof(struct buf)); 1705b39c878eSAndrey A. Chernov bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1706b39c878eSAndrey A. Chernov bp->b_proc = p; 1707b39c878eSAndrey A. Chernov bp->b_dev = dev; 1708b39c878eSAndrey A. Chernov 1709b39c878eSAndrey A. Chernov /* 1710b39c878eSAndrey A. Chernov * calculate a fake blkno, so fdstrategy() would initiate a 1711b39c878eSAndrey A. Chernov * seek to the requested cylinder 1712b39c878eSAndrey A. Chernov */ 1713b39c878eSAndrey A. Chernov bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) 17143a2f7427SDavid Greenman + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; 1715b39c878eSAndrey A. Chernov 1716b39c878eSAndrey A. Chernov bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 17175e235068SJordan K. Hubbard bp->b_un.b_addr = (caddr_t)finfo; 1718b39c878eSAndrey A. Chernov 1719b39c878eSAndrey A. Chernov /* now do the format */ 1720b39c878eSAndrey A. Chernov fdstrategy(bp); 1721b39c878eSAndrey A. Chernov 1722b39c878eSAndrey A. Chernov /* ...and wait for it to complete */ 1723b39c878eSAndrey A. Chernov s = splbio(); 1724b39c878eSAndrey A. Chernov while(!(bp->b_flags & B_DONE)) 1725b39c878eSAndrey A. Chernov { 17265e235068SJordan K. Hubbard rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1727b39c878eSAndrey A. Chernov if(rv == EWOULDBLOCK) 1728b39c878eSAndrey A. Chernov break; 1729b39c878eSAndrey A. Chernov } 1730b39c878eSAndrey A. Chernov splx(s); 1731b39c878eSAndrey A. Chernov 173282f5379bSJoerg Wunsch if(rv == EWOULDBLOCK) { 1733b39c878eSAndrey A. Chernov /* timed out */ 1734b39c878eSAndrey A. Chernov rv = EIO; 173582f5379bSJoerg Wunsch biodone(bp); 173682f5379bSJoerg Wunsch } 17373a2f7427SDavid Greenman if(bp->b_flags & B_ERROR) 17383a2f7427SDavid Greenman rv = bp->b_error; 173982f5379bSJoerg Wunsch /* 174082f5379bSJoerg Wunsch * allow the process to be swapped 174182f5379bSJoerg Wunsch */ 174282f5379bSJoerg Wunsch p->p_flag &= ~P_PHYSIO; 1743b39c878eSAndrey A. Chernov free(bp, M_TEMP); 1744b39c878eSAndrey A. Chernov return rv; 1745b39c878eSAndrey A. Chernov } 1746b39c878eSAndrey A. Chernov 1747f5f7ba03SJordan K. Hubbard /* 1748671e2ceeSBruce Evans * TODO: don't allocate buffer on stack. 1749f5f7ba03SJordan K. Hubbard */ 17505b81b6b3SRodney W. Grimes 1751f5f7ba03SJordan K. Hubbard int 1752b39c878eSAndrey A. Chernov fdioctl(dev, cmd, addr, flag, p) 1753f5f7ba03SJordan K. Hubbard dev_t dev; 1754f5f7ba03SJordan K. Hubbard int cmd; 1755f5f7ba03SJordan K. Hubbard caddr_t addr; 1756f5f7ba03SJordan K. Hubbard int flag; 1757b39c878eSAndrey A. Chernov struct proc *p; 1758f5f7ba03SJordan K. Hubbard { 17593a2f7427SDavid Greenman fdu_t fdu = FDUNIT(minor(dev)); 17603a2f7427SDavid Greenman fd_p fd = &fd_data[fdu]; 17613a2f7427SDavid Greenman size_t fdblk; 17623a2f7427SDavid Greenman 1763f5f7ba03SJordan K. Hubbard struct fd_type *fdt; 1764f5f7ba03SJordan K. Hubbard struct disklabel *dl; 1765f5f7ba03SJordan K. Hubbard char buffer[DEV_BSIZE]; 17663a2f7427SDavid Greenman int error = 0; 1767f5f7ba03SJordan K. Hubbard 1768b99f0a4aSAndrew Moore #if NFT > 0 1769a60eff27SNate Williams int type = FDTYPE(minor(dev)); 1770a60eff27SNate Williams 1771a60eff27SNate Williams /* check for a tape ioctl */ 1772a60eff27SNate Williams if (type & F_TAPE_TYPE) 1773b99f0a4aSAndrew Moore return ftioctl(dev, cmd, addr, flag, p); 1774b99f0a4aSAndrew Moore #endif 1775b99f0a4aSAndrew Moore 17763a2f7427SDavid Greenman fdblk = 128 << fd->ft->secsize; 1777f5f7ba03SJordan K. Hubbard 1778f5f7ba03SJordan K. Hubbard switch (cmd) 1779f5f7ba03SJordan K. Hubbard { 1780f5f7ba03SJordan K. Hubbard case DIOCGDINFO: 1781f5f7ba03SJordan K. Hubbard bzero(buffer, sizeof (buffer)); 1782f5f7ba03SJordan K. Hubbard dl = (struct disklabel *)buffer; 17833a2f7427SDavid Greenman dl->d_secsize = fdblk; 178492ed385aSRodney W. Grimes fdt = fd_data[FDUNIT(minor(dev))].ft; 1785f5f7ba03SJordan K. Hubbard dl->d_secpercyl = fdt->size / fdt->tracks; 1786f5f7ba03SJordan K. Hubbard dl->d_type = DTYPE_FLOPPY; 1787f5f7ba03SJordan K. Hubbard 1788191e1a59SBruce Evans if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl) 1789191e1a59SBruce Evans == NULL) 1790f5f7ba03SJordan K. Hubbard error = 0; 1791f5f7ba03SJordan K. Hubbard else 1792f5f7ba03SJordan K. Hubbard error = EINVAL; 1793f5f7ba03SJordan K. Hubbard 1794f5f7ba03SJordan K. Hubbard *(struct disklabel *)addr = *dl; 1795f5f7ba03SJordan K. Hubbard break; 1796f5f7ba03SJordan K. Hubbard 1797f5f7ba03SJordan K. Hubbard case DIOCSDINFO: 1798f5f7ba03SJordan K. Hubbard if ((flag & FWRITE) == 0) 1799f5f7ba03SJordan K. Hubbard error = EBADF; 1800f5f7ba03SJordan K. Hubbard break; 1801f5f7ba03SJordan K. Hubbard 1802f5f7ba03SJordan K. Hubbard case DIOCWLABEL: 1803f5f7ba03SJordan K. Hubbard if ((flag & FWRITE) == 0) 1804f5f7ba03SJordan K. Hubbard error = EBADF; 1805f5f7ba03SJordan K. Hubbard break; 1806f5f7ba03SJordan K. Hubbard 1807f5f7ba03SJordan K. Hubbard case DIOCWDINFO: 1808f5f7ba03SJordan K. Hubbard if ((flag & FWRITE) == 0) 1809f5f7ba03SJordan K. Hubbard { 1810f5f7ba03SJordan K. Hubbard error = EBADF; 1811f5f7ba03SJordan K. Hubbard break; 1812f5f7ba03SJordan K. Hubbard } 1813f5f7ba03SJordan K. Hubbard 1814f5f7ba03SJordan K. Hubbard dl = (struct disklabel *)addr; 1815f5f7ba03SJordan K. Hubbard 1816191e1a59SBruce Evans if ((error = setdisklabel((struct disklabel *)buffer, dl, 1817191e1a59SBruce Evans (u_long)0)) != 0) 1818f5f7ba03SJordan K. Hubbard break; 1819f5f7ba03SJordan K. Hubbard 1820b39c878eSAndrey A. Chernov error = writedisklabel(dev, fdstrategy, 182154c7241bSJordan K. Hubbard (struct disklabel *)buffer); 1822b39c878eSAndrey A. Chernov break; 1823b39c878eSAndrey A. Chernov 1824b39c878eSAndrey A. Chernov case FD_FORM: 1825b39c878eSAndrey A. Chernov if((flag & FWRITE) == 0) 1826b39c878eSAndrey A. Chernov error = EBADF; /* must be opened for writing */ 1827b39c878eSAndrey A. Chernov else if(((struct fd_formb *)addr)->format_version != 1828b39c878eSAndrey A. Chernov FD_FORMAT_VERSION) 1829b39c878eSAndrey A. Chernov error = EINVAL; /* wrong version of formatting prog */ 1830b39c878eSAndrey A. Chernov else 1831b39c878eSAndrey A. Chernov error = fdformat(dev, (struct fd_formb *)addr, p); 1832b39c878eSAndrey A. Chernov break; 1833b39c878eSAndrey A. Chernov 1834b39c878eSAndrey A. Chernov case FD_GTYPE: /* get drive type */ 1835b39c878eSAndrey A. Chernov *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft; 1836f5f7ba03SJordan K. Hubbard break; 1837f5f7ba03SJordan K. Hubbard 18383a2f7427SDavid Greenman case FD_STYPE: /* set drive type */ 18393a2f7427SDavid Greenman /* this is considered harmful; only allow for superuser */ 18403a2f7427SDavid Greenman if(suser(p->p_ucred, &p->p_acflag) != 0) 18413a2f7427SDavid Greenman return EPERM; 18423a2f7427SDavid Greenman *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr; 18433a2f7427SDavid Greenman break; 18443a2f7427SDavid Greenman 18453a2f7427SDavid Greenman case FD_GOPTS: /* get drive options */ 18463a2f7427SDavid Greenman *(int *)addr = fd_data[FDUNIT(minor(dev))].options; 18473a2f7427SDavid Greenman break; 18483a2f7427SDavid Greenman 18493a2f7427SDavid Greenman case FD_SOPTS: /* set drive options */ 18503a2f7427SDavid Greenman fd_data[FDUNIT(minor(dev))].options = *(int *)addr; 18513a2f7427SDavid Greenman break; 18523a2f7427SDavid Greenman 1853f5f7ba03SJordan K. Hubbard default: 18543a2f7427SDavid Greenman error = ENOTTY; 1855f5f7ba03SJordan K. Hubbard break; 1856f5f7ba03SJordan K. Hubbard } 1857f5f7ba03SJordan K. Hubbard return (error); 1858f5f7ba03SJordan K. Hubbard } 1859f5f7ba03SJordan K. Hubbard 18607146c13eSJulian Elischer 18617146c13eSJulian Elischer static fd_devsw_installed = 0; 18627146c13eSJulian Elischer 186387f6c662SJulian Elischer static void fd_drvinit(void *notused ) 18647146c13eSJulian Elischer { 186587f6c662SJulian Elischer 18667146c13eSJulian Elischer if( ! fd_devsw_installed ) { 1867cba8a5ddSPoul-Henning Kamp bdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &fd_bdevsw); 18687146c13eSJulian Elischer fd_devsw_installed = 1; 18697146c13eSJulian Elischer } 18707146c13eSJulian Elischer } 187187f6c662SJulian Elischer 187287f6c662SJulian Elischer SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) 187387f6c662SJulian Elischer 1874f5f7ba03SJordan K. Hubbard #endif 18753a2f7427SDavid Greenman /* 18763a2f7427SDavid Greenman * Hello emacs, these are the 18773a2f7427SDavid Greenman * Local Variables: 18783a2f7427SDavid Greenman * c-indent-level: 8 18793a2f7427SDavid Greenman * c-continued-statement-offset: 8 18803a2f7427SDavid Greenman * c-continued-brace-offset: 0 18813a2f7427SDavid Greenman * c-brace-offset: -8 18823a2f7427SDavid Greenman * c-brace-imaginary-offset: 0 18833a2f7427SDavid Greenman * c-argdecl-indent: 8 18843a2f7427SDavid Greenman * c-label-offset: -8 18853a2f7427SDavid Greenman * c++-hanging-braces: 1 18863a2f7427SDavid Greenman * c++-access-specifier-offset: -8 18873a2f7427SDavid Greenman * c++-empty-arglist-indent: 8 18883a2f7427SDavid Greenman * c++-friend-offset: 0 18893a2f7427SDavid Greenman * End: 18903a2f7427SDavid Greenman */ 1891