15b81b6b3SRodney W. Grimes /*#define DEBUG 1*/ 25b81b6b3SRodney W. Grimes /*- 35b81b6b3SRodney W. Grimes * Copyright (c) 1990 The Regents of the University of California. 45b81b6b3SRodney W. Grimes * All rights reserved. 55b81b6b3SRodney W. Grimes * 65b81b6b3SRodney W. Grimes * This code is derived from software contributed to Berkeley by 75b81b6b3SRodney W. Grimes * Don Ahn. 85b81b6b3SRodney W. Grimes * 95b81b6b3SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 105b81b6b3SRodney W. Grimes * modification, are permitted provided that the following conditions 115b81b6b3SRodney W. Grimes * are met: 125b81b6b3SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 135b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 145b81b6b3SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 155b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 165b81b6b3SRodney W. Grimes * documentation and/or other materials provided with the distribution. 175b81b6b3SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 185b81b6b3SRodney W. Grimes * must display the following acknowledgement: 195b81b6b3SRodney W. Grimes * This product includes software developed by the University of 205b81b6b3SRodney W. Grimes * California, Berkeley and its contributors. 215b81b6b3SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 225b81b6b3SRodney W. Grimes * may be used to endorse or promote products derived from this software 235b81b6b3SRodney W. Grimes * without specific prior written permission. 245b81b6b3SRodney W. Grimes * 255b81b6b3SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 265b81b6b3SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 275b81b6b3SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 285b81b6b3SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 295b81b6b3SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 305b81b6b3SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 315b81b6b3SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 325b81b6b3SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 335b81b6b3SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 345b81b6b3SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 355b81b6b3SRodney W. Grimes * SUCH DAMAGE. 365b81b6b3SRodney W. Grimes * 37dc4ff321SRodney W. Grimes * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 3892ed385aSRodney W. Grimes * $Id: fd.c,v 1.5 1993/09/15 23:27:45 rgrimes Exp $ 395b81b6b3SRodney W. Grimes * 405b81b6b3SRodney W. Grimes */ 415b81b6b3SRodney W. Grimes 425b81b6b3SRodney W. Grimes #include "fd.h" 435b81b6b3SRodney W. Grimes #if NFD > 0 445b81b6b3SRodney W. Grimes 455b81b6b3SRodney W. Grimes #include "param.h" 465b81b6b3SRodney W. Grimes #include "dkbad.h" 475b81b6b3SRodney W. Grimes #include "systm.h" 485b81b6b3SRodney W. Grimes #include "conf.h" 495b81b6b3SRodney W. Grimes #include "file.h" 505b81b6b3SRodney W. Grimes #include "ioctl.h" 51f5f7ba03SJordan K. Hubbard #include "disklabel.h" 525b81b6b3SRodney W. Grimes #include "buf.h" 535b81b6b3SRodney W. Grimes #include "uio.h" 5492ed385aSRodney W. Grimes #include "syslog.h" 555b81b6b3SRodney W. Grimes #include "i386/isa/isa.h" 565b81b6b3SRodney W. Grimes #include "i386/isa/isa_device.h" 575b81b6b3SRodney W. Grimes #include "i386/isa/fdreg.h" 585b81b6b3SRodney W. Grimes #include "i386/isa/icu.h" 595b81b6b3SRodney W. Grimes #include "i386/isa/rtc.h" 605b81b6b3SRodney W. Grimes #undef NFD 615b81b6b3SRodney W. Grimes #define NFD 2 625b81b6b3SRodney W. Grimes 635b81b6b3SRodney W. Grimes #define FDUNIT(s) ((s>>3)&1) 645b81b6b3SRodney W. Grimes #define FDTYPE(s) ((s)&7) 655b81b6b3SRodney W. Grimes 665b81b6b3SRodney W. Grimes #define b_cylin b_resid 675b81b6b3SRodney W. Grimes #define FDBLK 512 685b81b6b3SRodney W. Grimes #define NUMTYPES 4 695b81b6b3SRodney W. Grimes 705b81b6b3SRodney W. Grimes struct fd_type { 715b81b6b3SRodney W. Grimes int sectrac; /* sectors per track */ 725b81b6b3SRodney W. Grimes int secsize; /* size code for sectors */ 735b81b6b3SRodney W. Grimes int datalen; /* data len when secsize = 0 */ 745b81b6b3SRodney W. Grimes int gap; /* gap len between sectors */ 755b81b6b3SRodney W. Grimes int tracks; /* total num of tracks */ 765b81b6b3SRodney W. Grimes int size; /* size of disk in sectors */ 775b81b6b3SRodney W. Grimes int steptrac; /* steps per cylinder */ 785b81b6b3SRodney W. Grimes int trans; /* transfer speed code */ 795b81b6b3SRodney W. Grimes int heads; /* number of heads */ 805b81b6b3SRodney W. Grimes }; 815b81b6b3SRodney W. Grimes 825b81b6b3SRodney W. Grimes struct fd_type fd_types[NUMTYPES] = 835b81b6b3SRodney W. Grimes { 845b81b6b3SRodney W. Grimes { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */ 855b81b6b3SRodney W. Grimes { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */ 865b81b6b3SRodney W. Grimes { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */ 875b81b6b3SRodney W. Grimes { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */ 885b81b6b3SRodney W. Grimes }; 895b81b6b3SRodney W. Grimes 905b81b6b3SRodney W. Grimes #define DRVS_PER_CTLR 2 915b81b6b3SRodney W. Grimes /***********************************************************************\ 925b81b6b3SRodney W. Grimes * Per controller structure. * 935b81b6b3SRodney W. Grimes \***********************************************************************/ 945b81b6b3SRodney W. Grimes struct fdc_data 955b81b6b3SRodney W. Grimes { 965b81b6b3SRodney W. Grimes int fdcu; /* our unit number */ 975b81b6b3SRodney W. Grimes int baseport; 985b81b6b3SRodney W. Grimes int dmachan; 995b81b6b3SRodney W. Grimes int flags; 1005b81b6b3SRodney W. Grimes #define FDC_ATTACHED 0x01 1015b81b6b3SRodney W. Grimes struct fd_data *fd; 1025b81b6b3SRodney W. Grimes int fdu; /* the active drive */ 1035b81b6b3SRodney W. Grimes struct buf head; /* Head of buf chain */ 1045b81b6b3SRodney W. Grimes struct buf rhead; /* Raw head of buf chain */ 1055b81b6b3SRodney W. Grimes int state; 1065b81b6b3SRodney W. Grimes int retry; 1075b81b6b3SRodney W. Grimes int status[7]; /* copy of the registers */ 1085b81b6b3SRodney W. Grimes }fdc_data[(NFD+1)/DRVS_PER_CTLR]; 1095b81b6b3SRodney W. Grimes 1105b81b6b3SRodney W. Grimes /***********************************************************************\ 1115b81b6b3SRodney W. Grimes * Per drive structure. * 1125b81b6b3SRodney W. Grimes * N per controller (presently 2) (DRVS_PER_CTLR) * 1135b81b6b3SRodney W. Grimes \***********************************************************************/ 1145b81b6b3SRodney W. Grimes struct fd_data { 1155b81b6b3SRodney W. Grimes struct fdc_data *fdc; 1165b81b6b3SRodney W. Grimes int fdu; /* this unit number */ 1175b81b6b3SRodney W. Grimes int fdsu; /* this units number on this controller */ 1185b81b6b3SRodney W. Grimes int type; /* Drive type (HD, DD */ 1195b81b6b3SRodney W. Grimes struct fd_type *ft; /* pointer to the type descriptor */ 1205b81b6b3SRodney W. Grimes int flags; 1215b81b6b3SRodney W. Grimes #define FD_OPEN 0x01 /* it's open */ 1225b81b6b3SRodney W. Grimes #define FD_ACTIVE 0x02 /* it's active */ 1235b81b6b3SRodney W. Grimes #define FD_MOTOR 0x04 /* motor should be on */ 1245b81b6b3SRodney W. Grimes #define FD_MOTOR_WAIT 0x08 /* motor coming up */ 1255b81b6b3SRodney W. Grimes int skip; 1265b81b6b3SRodney W. Grimes int hddrv; 1275b81b6b3SRodney W. Grimes int track; /* where we think the head is */ 1285b81b6b3SRodney W. Grimes } fd_data[NFD]; 1295b81b6b3SRodney W. Grimes 1305b81b6b3SRodney W. Grimes /***********************************************************************\ 1315b81b6b3SRodney W. Grimes * Throughout this file the following conventions will be used: * 1325b81b6b3SRodney W. Grimes * fd is a pointer to the fd_data struct for the drive in question * 1335b81b6b3SRodney W. Grimes * fdc is a pointer to the fdc_data struct for the controller * 1345b81b6b3SRodney W. Grimes * fdu is the floppy drive unit number * 1355b81b6b3SRodney W. Grimes * fdcu is the floppy controller unit number * 1365b81b6b3SRodney W. Grimes * fdsu is the floppy drive unit number on that controller. (sub-unit) * 1375b81b6b3SRodney W. Grimes \***********************************************************************/ 1385b81b6b3SRodney W. Grimes typedef int fdu_t; 1395b81b6b3SRodney W. Grimes typedef int fdcu_t; 1405b81b6b3SRodney W. Grimes typedef int fdsu_t; 1415b81b6b3SRodney W. Grimes typedef struct fd_data *fd_p; 1425b81b6b3SRodney W. Grimes typedef struct fdc_data *fdc_p; 1435b81b6b3SRodney W. Grimes 1445b81b6b3SRodney W. Grimes #define DEVIDLE 0 1455b81b6b3SRodney W. Grimes #define FINDWORK 1 1465b81b6b3SRodney W. Grimes #define DOSEEK 2 1475b81b6b3SRodney W. Grimes #define SEEKCOMPLETE 3 1485b81b6b3SRodney W. Grimes #define IOCOMPLETE 4 1495b81b6b3SRodney W. Grimes #define RECALCOMPLETE 5 1505b81b6b3SRodney W. Grimes #define STARTRECAL 6 1515b81b6b3SRodney W. Grimes #define RESETCTLR 7 1525b81b6b3SRodney W. Grimes #define SEEKWAIT 8 1535b81b6b3SRodney W. Grimes #define RECALWAIT 9 1545b81b6b3SRodney W. Grimes #define MOTORWAIT 10 1555b81b6b3SRodney W. Grimes #define IOTIMEDOUT 11 1565b81b6b3SRodney W. Grimes 1575b81b6b3SRodney W. Grimes #ifdef DEBUG 1585b81b6b3SRodney W. Grimes char *fdstates[] = 1595b81b6b3SRodney W. Grimes { 1605b81b6b3SRodney W. Grimes "DEVIDLE", 1615b81b6b3SRodney W. Grimes "FINDWORK", 1625b81b6b3SRodney W. Grimes "DOSEEK", 1635b81b6b3SRodney W. Grimes "SEEKCOMPLETE", 1645b81b6b3SRodney W. Grimes "IOCOMPLETE", 1655b81b6b3SRodney W. Grimes "RECALCOMPLETE", 1665b81b6b3SRodney W. Grimes "STARTRECAL", 1675b81b6b3SRodney W. Grimes "RESETCTLR", 1685b81b6b3SRodney W. Grimes "SEEKWAIT", 1695b81b6b3SRodney W. Grimes "RECALWAIT", 1705b81b6b3SRodney W. Grimes "MOTORWAIT", 1715b81b6b3SRodney W. Grimes "IOTIMEDOUT" 1725b81b6b3SRodney W. Grimes }; 1735b81b6b3SRodney W. Grimes 1745b81b6b3SRodney W. Grimes 1755b81b6b3SRodney W. Grimes int fd_debug = 1; 1765b81b6b3SRodney W. Grimes #define TRACE0(arg) if(fd_debug) printf(arg) 1775b81b6b3SRodney W. Grimes #define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2) 1785b81b6b3SRodney W. Grimes #else DEBUG 1795b81b6b3SRodney W. Grimes #define TRACE0(arg) 1805b81b6b3SRodney W. Grimes #define TRACE1(arg1,arg2) 1815b81b6b3SRodney W. Grimes #endif DEBUG 1825b81b6b3SRodney W. Grimes 1835b81b6b3SRodney W. Grimes extern int hz; 1845b81b6b3SRodney W. Grimes /* state needed for current transfer */ 1855b81b6b3SRodney W. Grimes 1865b81b6b3SRodney W. Grimes /****************************************************************************/ 1875b81b6b3SRodney W. Grimes /* autoconfiguration stuff */ 1885b81b6b3SRodney W. Grimes /****************************************************************************/ 1895b81b6b3SRodney W. Grimes int fdprobe(), fdattach(), fd_turnoff(); 1905b81b6b3SRodney W. Grimes 1915b81b6b3SRodney W. Grimes struct isa_driver fddriver = { 1925b81b6b3SRodney W. Grimes fdprobe, fdattach, "fd", 1935b81b6b3SRodney W. Grimes }; 1945b81b6b3SRodney W. Grimes 1955b81b6b3SRodney W. Grimes /* 1965b81b6b3SRodney W. Grimes * probe for existance of controller 1975b81b6b3SRodney W. Grimes */ 1985b81b6b3SRodney W. Grimes fdprobe(dev) 1995b81b6b3SRodney W. Grimes struct isa_device *dev; 2005b81b6b3SRodney W. Grimes { 2015b81b6b3SRodney W. Grimes fdcu_t fdcu = dev->id_unit; 2025b81b6b3SRodney W. Grimes if(fdc_data[fdcu].flags & FDC_ATTACHED) 2035b81b6b3SRodney W. Grimes { 2045b81b6b3SRodney W. Grimes printf("fdc: same unit (%d) used multiple times\n",fdcu); 2055b81b6b3SRodney W. Grimes return 0; 2065b81b6b3SRodney W. Grimes } 2075b81b6b3SRodney W. Grimes 2085b81b6b3SRodney W. Grimes fdc_data[fdcu].baseport = dev->id_iobase; 2095b81b6b3SRodney W. Grimes 2105b81b6b3SRodney W. Grimes /* see if it can handle a command */ 2115b81b6b3SRodney W. Grimes if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0) 2125b81b6b3SRodney W. Grimes { 2135b81b6b3SRodney W. Grimes return(0); 2145b81b6b3SRodney W. Grimes } 2155b81b6b3SRodney W. Grimes out_fdc(fdcu,0xDF); 2165b81b6b3SRodney W. Grimes out_fdc(fdcu,2); 2175b81b6b3SRodney W. Grimes return (IO_FDCSIZE); 2185b81b6b3SRodney W. Grimes } 2195b81b6b3SRodney W. Grimes 2205b81b6b3SRodney W. Grimes /* 2215b81b6b3SRodney W. Grimes * wire controller into system, look for floppy units 2225b81b6b3SRodney W. Grimes */ 2235b81b6b3SRodney W. Grimes fdattach(dev) 2245b81b6b3SRodney W. Grimes struct isa_device *dev; 2255b81b6b3SRodney W. Grimes { 2265b81b6b3SRodney W. Grimes unsigned fdt,st0, cyl; 2275b81b6b3SRodney W. Grimes int hdr; 2285b81b6b3SRodney W. Grimes fdu_t fdu; 2295b81b6b3SRodney W. Grimes fdcu_t fdcu = dev->id_unit; 2305b81b6b3SRodney W. Grimes fdc_p fdc = fdc_data + fdcu; 2315b81b6b3SRodney W. Grimes fd_p fd; 2325b81b6b3SRodney W. Grimes int fdsu; 2335b81b6b3SRodney W. Grimes 2345b81b6b3SRodney W. Grimes fdc->fdcu = fdcu; 2355b81b6b3SRodney W. Grimes fdc->flags |= FDC_ATTACHED; 2365b81b6b3SRodney W. Grimes fdc->dmachan = dev->id_drq; 2375b81b6b3SRodney W. Grimes fdc->state = DEVIDLE; 2385b81b6b3SRodney W. Grimes 2395b81b6b3SRodney W. Grimes fdt = rtcin(RTC_FDISKETTE); 2405b81b6b3SRodney W. Grimes hdr = 0; 2415b81b6b3SRodney W. Grimes 2425b81b6b3SRodney W. Grimes /* check for each floppy drive */ 2435b81b6b3SRodney W. Grimes for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0; 2445b81b6b3SRodney W. Grimes ((fdu < NFD) && (fdsu < DRVS_PER_CTLR)); 2455b81b6b3SRodney W. Grimes fdu++,fdsu++) 2465b81b6b3SRodney W. Grimes { 2475b81b6b3SRodney W. Grimes /* is there a unit? */ 248f5f7ba03SJordan K. Hubbard if ((fdt & 0xf0) == RTCFDT_NONE) { 249f5f7ba03SJordan K. Hubbard #define NO_TYPE NUMTYPES 250f5f7ba03SJordan K. Hubbard fd_data[fdu].type = NO_TYPE; 2515b81b6b3SRodney W. Grimes continue; 252f5f7ba03SJordan K. Hubbard } 2535b81b6b3SRodney W. Grimes 2545b81b6b3SRodney W. Grimes #ifdef notyet 2555b81b6b3SRodney W. Grimes /* select it */ 2565b81b6b3SRodney W. Grimes fd_turnon1(fdu); 2575b81b6b3SRodney W. Grimes spinwait(1000); /* 1 sec */ 2585b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ 2595b81b6b3SRodney W. Grimes out_fdc(fdcu,fdsu); 2605b81b6b3SRodney W. Grimes spinwait(1000); /* 1 sec */ 2615b81b6b3SRodney W. Grimes 2625b81b6b3SRodney W. Grimes /* anything responding */ 2635b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SENSEI); 2645b81b6b3SRodney W. Grimes st0 = in_fdc(fdcu); 2655b81b6b3SRodney W. Grimes cyl = in_fdc(fdcu); 2665b81b6b3SRodney W. Grimes if (st0 & 0xd0) 2675b81b6b3SRodney W. Grimes continue; 2685b81b6b3SRodney W. Grimes 2695b81b6b3SRodney W. Grimes #endif 2705b81b6b3SRodney W. Grimes fd_data[fdu].track = -2; 2715b81b6b3SRodney W. Grimes fd_data[fdu].fdc = fdc; 2725b81b6b3SRodney W. Grimes fd_data[fdu].fdsu = fdsu; 2732a6c8980SDavid Greenman printf("fd%d: unit %d type ", fdcu, fdu); 2745b81b6b3SRodney W. Grimes 2755b81b6b3SRodney W. Grimes if ((fdt & 0xf0) == RTCFDT_12M) { 2762a6c8980SDavid Greenman printf("1.2MB 5.25in\n"); 2775b81b6b3SRodney W. Grimes fd_data[fdu].type = 1; 2785b81b6b3SRodney W. Grimes fd_data[fdu].ft = fd_types + 1; 2795b81b6b3SRodney W. Grimes 2805b81b6b3SRodney W. Grimes } 2815b81b6b3SRodney W. Grimes if ((fdt & 0xf0) == RTCFDT_144M) { 2822a6c8980SDavid Greenman printf("1.44MB 3.5in\n"); 2835b81b6b3SRodney W. Grimes fd_data[fdu].type = 0; 2845b81b6b3SRodney W. Grimes fd_data[fdu].ft = fd_types + 0; 2855b81b6b3SRodney W. Grimes } 2865b81b6b3SRodney W. Grimes 2875b81b6b3SRodney W. Grimes fdt <<= 4; 2885b81b6b3SRodney W. Grimes fd_turnoff(fdu); 2895b81b6b3SRodney W. Grimes hdr = 1; 2905b81b6b3SRodney W. Grimes } 2915b81b6b3SRodney W. Grimes 2925b81b6b3SRodney W. Grimes /* Set transfer to 500kbps */ 2935b81b6b3SRodney W. Grimes outb(fdc->baseport+fdctl,0); /*XXX*/ 2945b81b6b3SRodney W. Grimes } 2955b81b6b3SRodney W. Grimes 2965b81b6b3SRodney W. Grimes int 2975b81b6b3SRodney W. Grimes fdsize(dev) 2985b81b6b3SRodney W. Grimes dev_t dev; 2995b81b6b3SRodney W. Grimes { 3005b81b6b3SRodney W. Grimes return(0); 3015b81b6b3SRodney W. Grimes } 3025b81b6b3SRodney W. Grimes 3035b81b6b3SRodney W. Grimes /****************************************************************************/ 3045b81b6b3SRodney W. Grimes /* fdstrategy */ 3055b81b6b3SRodney W. Grimes /****************************************************************************/ 3065b81b6b3SRodney W. Grimes fdstrategy(bp) 3075b81b6b3SRodney W. Grimes register struct buf *bp; /* IO operation to perform */ 3085b81b6b3SRodney W. Grimes { 3095b81b6b3SRodney W. Grimes register struct buf *dp,*dp0,*dp1; 3105b81b6b3SRodney W. Grimes long nblocks,blknum; 3115b81b6b3SRodney W. Grimes int s; 3125b81b6b3SRodney W. Grimes fdcu_t fdcu; 3135b81b6b3SRodney W. Grimes fdu_t fdu; 3145b81b6b3SRodney W. Grimes fdc_p fdc; 3155b81b6b3SRodney W. Grimes fd_p fd; 3165b81b6b3SRodney W. Grimes 3175b81b6b3SRodney W. Grimes fdu = FDUNIT(minor(bp->b_dev)); 3185b81b6b3SRodney W. Grimes fd = &fd_data[fdu]; 3195b81b6b3SRodney W. Grimes fdc = fd->fdc; 3205b81b6b3SRodney W. Grimes fdcu = fdc->fdcu; 3215b81b6b3SRodney W. Grimes /*type = FDTYPE(minor(bp->b_dev));*/ 3225b81b6b3SRodney W. Grimes 3235b81b6b3SRodney W. Grimes if ((fdu >= NFD) || (bp->b_blkno < 0)) { 3245b81b6b3SRodney W. Grimes printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n", 3255b81b6b3SRodney W. Grimes fdu, bp->b_blkno, bp->b_bcount); 3265b81b6b3SRodney W. Grimes pg("fd:error in fdstrategy"); 3275b81b6b3SRodney W. Grimes bp->b_error = EINVAL; 3285b81b6b3SRodney W. Grimes bp->b_flags |= B_ERROR; 3295b81b6b3SRodney W. Grimes goto bad; 3305b81b6b3SRodney W. Grimes } 3315b81b6b3SRodney W. Grimes /* 3325b81b6b3SRodney W. Grimes * Set up block calculations. 3335b81b6b3SRodney W. Grimes */ 3345b81b6b3SRodney W. Grimes blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; 3355b81b6b3SRodney W. Grimes nblocks = fd->ft->size; 3365b81b6b3SRodney W. Grimes if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 3375b81b6b3SRodney W. Grimes if (blknum == nblocks) { 3385b81b6b3SRodney W. Grimes bp->b_resid = bp->b_bcount; 3395b81b6b3SRodney W. Grimes } else { 3405b81b6b3SRodney W. Grimes bp->b_error = ENOSPC; 3415b81b6b3SRodney W. Grimes bp->b_flags |= B_ERROR; 3425b81b6b3SRodney W. Grimes } 3435b81b6b3SRodney W. Grimes goto bad; 3445b81b6b3SRodney W. Grimes } 3455b81b6b3SRodney W. Grimes bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); 3465b81b6b3SRodney W. Grimes dp = &(fdc->head); 3475b81b6b3SRodney W. Grimes s = splbio(); 3485b81b6b3SRodney W. Grimes disksort(dp, bp); 3495b81b6b3SRodney W. Grimes untimeout(fd_turnoff,fdu); /* a good idea */ 3505b81b6b3SRodney W. Grimes fdstart(fdcu); 3515b81b6b3SRodney W. Grimes splx(s); 3525b81b6b3SRodney W. Grimes return; 3535b81b6b3SRodney W. Grimes 3545b81b6b3SRodney W. Grimes bad: 3555b81b6b3SRodney W. Grimes biodone(bp); 3565b81b6b3SRodney W. Grimes } 3575b81b6b3SRodney W. Grimes 3585b81b6b3SRodney W. Grimes /****************************************************************************/ 3595b81b6b3SRodney W. Grimes /* motor control stuff */ 3605b81b6b3SRodney W. Grimes /* remember to not deselect the drive we're working on */ 3615b81b6b3SRodney W. Grimes /****************************************************************************/ 362f5f7ba03SJordan K. Hubbard set_motor(fdcu, fdu, reset) 363f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 364f5f7ba03SJordan K. Hubbard fdu_t fdu; 365f5f7ba03SJordan K. Hubbard int reset; 3665b81b6b3SRodney W. Grimes { 3675b81b6b3SRodney W. Grimes int m0,m1; 3685b81b6b3SRodney W. Grimes int selunit; 3695b81b6b3SRodney W. Grimes fd_p fd; 3705b81b6b3SRodney W. Grimes if(fd = fdc_data[fdcu].fd)/* yes an assign! */ 3715b81b6b3SRodney W. Grimes { 3725b81b6b3SRodney W. Grimes selunit = fd->fdsu; 3735b81b6b3SRodney W. Grimes } 3745b81b6b3SRodney W. Grimes else 3755b81b6b3SRodney W. Grimes { 3765b81b6b3SRodney W. Grimes selunit = 0; 3775b81b6b3SRodney W. Grimes } 3785b81b6b3SRodney W. Grimes m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR; 3795b81b6b3SRodney W. Grimes m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR; 3805b81b6b3SRodney W. Grimes outb(fdc_data[fdcu].baseport+fdout, 3815b81b6b3SRodney W. Grimes selunit 3825b81b6b3SRodney W. Grimes | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) 3835b81b6b3SRodney W. Grimes | (m0 ? FDO_MOEN0 : 0) 3845b81b6b3SRodney W. Grimes | (m1 ? FDO_MOEN1 : 0)); 3855b81b6b3SRodney W. Grimes TRACE1("[0x%x->fdout]",( 3865b81b6b3SRodney W. Grimes selunit 3875b81b6b3SRodney W. Grimes | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) 3885b81b6b3SRodney W. Grimes | (m0 ? FDO_MOEN0 : 0) 3895b81b6b3SRodney W. Grimes | (m1 ? FDO_MOEN1 : 0))); 3905b81b6b3SRodney W. Grimes } 3915b81b6b3SRodney W. Grimes 392f5f7ba03SJordan K. Hubbard fd_turnoff(fdu) 393f5f7ba03SJordan K. Hubbard fdu_t fdu; 3945b81b6b3SRodney W. Grimes { 395f5f7ba03SJordan K. Hubbard int s; 396f5f7ba03SJordan K. Hubbard 3975b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 398f5f7ba03SJordan K. Hubbard s = splbio(); 3995b81b6b3SRodney W. Grimes fd->flags &= ~FD_MOTOR; 4005b81b6b3SRodney W. Grimes set_motor(fd->fdc->fdcu,fd->fdsu,0); 401f5f7ba03SJordan K. Hubbard splx(s); 4025b81b6b3SRodney W. Grimes } 4035b81b6b3SRodney W. Grimes 404f5f7ba03SJordan K. Hubbard fd_motor_on(fdu) 405f5f7ba03SJordan K. Hubbard fdu_t fdu; 4065b81b6b3SRodney W. Grimes { 407f5f7ba03SJordan K. Hubbard int s; 408f5f7ba03SJordan K. Hubbard 4095b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 410f5f7ba03SJordan K. Hubbard s = splbio(); 4115b81b6b3SRodney W. Grimes fd->flags &= ~FD_MOTOR_WAIT; 4125b81b6b3SRodney W. Grimes if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) 4135b81b6b3SRodney W. Grimes { 414f5f7ba03SJordan K. Hubbard fdintr(fd->fdc->fdcu); 4155b81b6b3SRodney W. Grimes } 416f5f7ba03SJordan K. Hubbard splx(s); 4175b81b6b3SRodney W. Grimes } 4185b81b6b3SRodney W. Grimes 419f5f7ba03SJordan K. Hubbard fd_turnon(fdu) 420f5f7ba03SJordan K. Hubbard fdu_t fdu; 4215b81b6b3SRodney W. Grimes { 4225b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 4235b81b6b3SRodney W. Grimes if(!(fd->flags & FD_MOTOR)) 4245b81b6b3SRodney W. Grimes { 4255b81b6b3SRodney W. Grimes fd_turnon1(fdu); 4265b81b6b3SRodney W. Grimes fd->flags |= FD_MOTOR_WAIT; 4275b81b6b3SRodney W. Grimes timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */ 4285b81b6b3SRodney W. Grimes } 4295b81b6b3SRodney W. Grimes } 4305b81b6b3SRodney W. Grimes 431f5f7ba03SJordan K. Hubbard fd_turnon1(fdu) 432f5f7ba03SJordan K. Hubbard fdu_t fdu; 4335b81b6b3SRodney W. Grimes { 4345b81b6b3SRodney W. Grimes fd_p fd = fd_data + fdu; 4355b81b6b3SRodney W. Grimes fd->flags |= FD_MOTOR; 4365b81b6b3SRodney W. Grimes set_motor(fd->fdc->fdcu,fd->fdsu,0); 4375b81b6b3SRodney W. Grimes } 4385b81b6b3SRodney W. Grimes 4395b81b6b3SRodney W. Grimes /****************************************************************************/ 4405b81b6b3SRodney W. Grimes /* fdc in/out */ 4415b81b6b3SRodney W. Grimes /****************************************************************************/ 4425b81b6b3SRodney W. Grimes int 443f5f7ba03SJordan K. Hubbard in_fdc(fdcu) 444f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 4455b81b6b3SRodney W. Grimes { 4465b81b6b3SRodney W. Grimes int baseport = fdc_data[fdcu].baseport; 4475b81b6b3SRodney W. Grimes int i, j = 100000; 4485b81b6b3SRodney W. Grimes while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM)) 4495b81b6b3SRodney W. Grimes != (NE7_DIO|NE7_RQM) && j-- > 0) 4505b81b6b3SRodney W. Grimes if (i == NE7_RQM) return -1; 4515b81b6b3SRodney W. Grimes if (j <= 0) 4525b81b6b3SRodney W. Grimes return(-1); 4535b81b6b3SRodney W. Grimes #ifdef DEBUG 4545b81b6b3SRodney W. Grimes i = inb(baseport+fddata); 4555b81b6b3SRodney W. Grimes TRACE1("[fddata->0x%x]",(unsigned char)i); 4565b81b6b3SRodney W. Grimes return(i); 4575b81b6b3SRodney W. Grimes #else 4585b81b6b3SRodney W. Grimes return inb(baseport+fddata); 4595b81b6b3SRodney W. Grimes #endif 4605b81b6b3SRodney W. Grimes } 4615b81b6b3SRodney W. Grimes 462f5f7ba03SJordan K. Hubbard out_fdc(fdcu, x) 463f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 464f5f7ba03SJordan K. Hubbard int x; 4655b81b6b3SRodney W. Grimes { 4665b81b6b3SRodney W. Grimes int baseport = fdc_data[fdcu].baseport; 4673b3837dbSRodney W. Grimes int i; 4685b81b6b3SRodney W. Grimes 4693b3837dbSRodney W. Grimes /* Check that the direction bit is set */ 4703b3837dbSRodney W. Grimes i = 100000; 4715b81b6b3SRodney W. Grimes while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0); 4723b3837dbSRodney W. Grimes if (i <= 0) return (-1); /* Floppy timed out */ 4733b3837dbSRodney W. Grimes 4743b3837dbSRodney W. Grimes /* Check that the floppy controller is ready for a command */ 4753b3837dbSRodney W. Grimes i = 100000; 4765b81b6b3SRodney W. Grimes while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0); 4773b3837dbSRodney W. Grimes if (i <= 0) return (-1); /* Floppy timed out */ 4783b3837dbSRodney W. Grimes 4793b3837dbSRodney W. Grimes /* Send the command and return */ 4805b81b6b3SRodney W. Grimes outb(baseport+fddata,x); 4815b81b6b3SRodney W. Grimes TRACE1("[0x%x->fddata]",x); 4825b81b6b3SRodney W. Grimes return (0); 4835b81b6b3SRodney W. Grimes } 4845b81b6b3SRodney W. Grimes 4855b81b6b3SRodney W. Grimes /****************************************************************************/ 4865b81b6b3SRodney W. Grimes /* fdopen/fdclose */ 4875b81b6b3SRodney W. Grimes /****************************************************************************/ 4885b81b6b3SRodney W. Grimes Fdopen(dev, flags) 4895b81b6b3SRodney W. Grimes dev_t dev; 4905b81b6b3SRodney W. Grimes int flags; 4915b81b6b3SRodney W. Grimes { 4925b81b6b3SRodney W. Grimes fdu_t fdu = FDUNIT(minor(dev)); 4935b81b6b3SRodney W. Grimes /*int type = FDTYPE(minor(dev));*/ 4945b81b6b3SRodney W. Grimes int s; 4955b81b6b3SRodney W. Grimes 4965b81b6b3SRodney W. Grimes /* check bounds */ 497f5f7ba03SJordan K. Hubbard if (fdu >= NFD || fd_data[fdu].type == NO_TYPE) return(ENXIO); 4985b81b6b3SRodney W. Grimes /*if (type >= NUMTYPES) return(ENXIO);*/ 4995b81b6b3SRodney W. Grimes fd_data[fdu].flags |= FD_OPEN; 5005b81b6b3SRodney W. Grimes 5015b81b6b3SRodney W. Grimes return 0; 5025b81b6b3SRodney W. Grimes } 5035b81b6b3SRodney W. Grimes 5045b81b6b3SRodney W. Grimes fdclose(dev, flags) 5055b81b6b3SRodney W. Grimes dev_t dev; 5065b81b6b3SRodney W. Grimes { 5075b81b6b3SRodney W. Grimes fdu_t fdu = FDUNIT(minor(dev)); 5085b81b6b3SRodney W. Grimes fd_data[fdu].flags &= ~FD_OPEN; 5095b81b6b3SRodney W. Grimes return(0); 5105b81b6b3SRodney W. Grimes } 5115b81b6b3SRodney W. Grimes 5125b81b6b3SRodney W. Grimes 5135b81b6b3SRodney W. Grimes /***************************************************************\ 5145b81b6b3SRodney W. Grimes * fdstart * 5155b81b6b3SRodney W. Grimes * We have just queued something.. if the controller is not busy * 5165b81b6b3SRodney W. Grimes * then simulate the case where it has just finished a command * 5175b81b6b3SRodney W. Grimes * So that it (the interrupt routine) looks on the queue for more* 5185b81b6b3SRodney W. Grimes * work to do and picks up what we just added. * 5195b81b6b3SRodney W. Grimes * If the controller is already busy, we need do nothing, as it * 5205b81b6b3SRodney W. Grimes * will pick up our work when the present work completes * 5215b81b6b3SRodney W. Grimes \***************************************************************/ 522f5f7ba03SJordan K. Hubbard fdstart(fdcu) 523f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 5245b81b6b3SRodney W. Grimes { 5255b81b6b3SRodney W. Grimes register struct buf *dp,*bp; 5265b81b6b3SRodney W. Grimes int s; 5275b81b6b3SRodney W. Grimes fdu_t fdu; 5285b81b6b3SRodney W. Grimes 5295b81b6b3SRodney W. Grimes s = splbio(); 5305b81b6b3SRodney W. Grimes if(fdc_data[fdcu].state == DEVIDLE) 5315b81b6b3SRodney W. Grimes { 5325b81b6b3SRodney W. Grimes fdintr(fdcu); 5335b81b6b3SRodney W. Grimes } 5345b81b6b3SRodney W. Grimes splx(s); 5355b81b6b3SRodney W. Grimes } 5365b81b6b3SRodney W. Grimes 537f5f7ba03SJordan K. Hubbard fd_timeout(fdcu) 538f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 5395b81b6b3SRodney W. Grimes { 5405b81b6b3SRodney W. Grimes fdu_t fdu = fdc_data[fdcu].fdu; 5415b81b6b3SRodney W. Grimes int st0, st3, cyl; 5425b81b6b3SRodney W. Grimes struct buf *dp,*bp; 543f5f7ba03SJordan K. Hubbard int s; 5445b81b6b3SRodney W. Grimes 5455b81b6b3SRodney W. Grimes dp = &fdc_data[fdcu].head; 546f5f7ba03SJordan K. Hubbard s = splbio(); 5475b81b6b3SRodney W. Grimes bp = dp->b_actf; 5485b81b6b3SRodney W. Grimes 5495b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SENSED); 5505b81b6b3SRodney W. Grimes out_fdc(fdcu,fd_data[fdu].hddrv); 5515b81b6b3SRodney W. Grimes st3 = in_fdc(fdcu); 5525b81b6b3SRodney W. Grimes 5535b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SENSEI); 5545b81b6b3SRodney W. Grimes st0 = in_fdc(fdcu); 5555b81b6b3SRodney W. Grimes cyl = in_fdc(fdcu); 5565b81b6b3SRodney W. Grimes printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n", 5575b81b6b3SRodney W. Grimes fdu, 5585b81b6b3SRodney W. Grimes st0, 5595b81b6b3SRodney W. Grimes NE7_ST0BITS, 5605b81b6b3SRodney W. Grimes cyl, 5615b81b6b3SRodney W. Grimes st3, 5625b81b6b3SRodney W. Grimes NE7_ST3BITS); 5635b81b6b3SRodney W. Grimes 5645b81b6b3SRodney W. Grimes if (bp) 5655b81b6b3SRodney W. Grimes { 5665b81b6b3SRodney W. Grimes retrier(fdcu); 5675b81b6b3SRodney W. Grimes fdc_data[fdcu].status[0] = 0xc0; 5685b81b6b3SRodney W. Grimes fdc_data[fdcu].state = IOTIMEDOUT; 5695b81b6b3SRodney W. Grimes if( fdc_data[fdcu].retry < 6) 5705b81b6b3SRodney W. Grimes fdc_data[fdcu].retry = 6; 5715b81b6b3SRodney W. Grimes } 5725b81b6b3SRodney W. Grimes else 5735b81b6b3SRodney W. Grimes { 5745b81b6b3SRodney W. Grimes fdc_data[fdcu].fd = (fd_p) 0; 5755b81b6b3SRodney W. Grimes fdc_data[fdcu].fdu = -1; 5765b81b6b3SRodney W. Grimes fdc_data[fdcu].state = DEVIDLE; 5775b81b6b3SRodney W. Grimes } 578f5f7ba03SJordan K. Hubbard fdintr(fdcu); 579f5f7ba03SJordan K. Hubbard splx(s); 5805b81b6b3SRodney W. Grimes } 5815b81b6b3SRodney W. Grimes 5825b81b6b3SRodney W. Grimes /* just ensure it has the right spl */ 583f5f7ba03SJordan K. Hubbard fd_pseudointr(fdcu) 584f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 5855b81b6b3SRodney W. Grimes { 5865b81b6b3SRodney W. Grimes int s; 5875b81b6b3SRodney W. Grimes s = splbio(); 5885b81b6b3SRodney W. Grimes fdintr(fdcu); 5895b81b6b3SRodney W. Grimes splx(s); 5905b81b6b3SRodney W. Grimes } 5915b81b6b3SRodney W. Grimes 5925b81b6b3SRodney W. Grimes /***********************************************************************\ 5935b81b6b3SRodney W. Grimes * fdintr * 5945b81b6b3SRodney W. Grimes * keep calling the state machine until it returns a 0 * 5955b81b6b3SRodney W. Grimes * ALWAYS called at SPLBIO * 5965b81b6b3SRodney W. Grimes \***********************************************************************/ 597f5f7ba03SJordan K. Hubbard fdintr(fdcu) 598f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 5995b81b6b3SRodney W. Grimes { 6005b81b6b3SRodney W. Grimes fdc_p fdc = fdc_data + fdcu; 6015b81b6b3SRodney W. Grimes while(fdstate(fdcu, fdc)); 6025b81b6b3SRodney W. Grimes } 6035b81b6b3SRodney W. Grimes 6045b81b6b3SRodney W. Grimes /***********************************************************************\ 6055b81b6b3SRodney W. Grimes * The controller state machine. * 6065b81b6b3SRodney W. Grimes * if it returns a non zero value, it should be called again immediatly * 6075b81b6b3SRodney W. Grimes \***********************************************************************/ 608f5f7ba03SJordan K. Hubbard int fdstate(fdcu, fdc) 609f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 610f5f7ba03SJordan K. Hubbard fdc_p fdc; 6115b81b6b3SRodney W. Grimes { 6125b81b6b3SRodney W. Grimes int read,head,trac,sec,i,s,sectrac,cyl,st0; 6135b81b6b3SRodney W. Grimes unsigned long blknum; 6145b81b6b3SRodney W. Grimes fdu_t fdu = fdc->fdu; 6155b81b6b3SRodney W. Grimes fd_p fd; 6165b81b6b3SRodney W. Grimes register struct buf *dp,*bp; 6175b81b6b3SRodney W. Grimes 6185b81b6b3SRodney W. Grimes dp = &(fdc->head); 6195b81b6b3SRodney W. Grimes bp = dp->b_actf; 6205b81b6b3SRodney W. Grimes if(!bp) 6215b81b6b3SRodney W. Grimes { 6225b81b6b3SRodney W. Grimes /***********************************************\ 6235b81b6b3SRodney W. Grimes * nothing left for this controller to do * 6245b81b6b3SRodney W. Grimes * Force into the IDLE state, * 6255b81b6b3SRodney W. Grimes \***********************************************/ 6265b81b6b3SRodney W. Grimes fdc->state = DEVIDLE; 6275b81b6b3SRodney W. Grimes if(fdc->fd) 6285b81b6b3SRodney W. Grimes { 6295b81b6b3SRodney W. Grimes printf("unexpected valid fd pointer (fdu = %d)\n" 6305b81b6b3SRodney W. Grimes ,fdc->fdu); 6315b81b6b3SRodney W. Grimes fdc->fd = (fd_p) 0; 6325b81b6b3SRodney W. Grimes fdc->fdu = -1; 6335b81b6b3SRodney W. Grimes } 6345b81b6b3SRodney W. Grimes TRACE1("[fdc%d IDLE]",fdcu); 6355b81b6b3SRodney W. Grimes return(0); 6365b81b6b3SRodney W. Grimes } 6375b81b6b3SRodney W. Grimes fdu = FDUNIT(minor(bp->b_dev)); 6385b81b6b3SRodney W. Grimes fd = fd_data + fdu; 6395b81b6b3SRodney W. Grimes if (fdc->fd && (fd != fdc->fd)) 6405b81b6b3SRodney W. Grimes { 6415b81b6b3SRodney W. Grimes printf("confused fd pointers\n"); 6425b81b6b3SRodney W. Grimes } 6435b81b6b3SRodney W. Grimes read = bp->b_flags & B_READ; 6445b81b6b3SRodney W. Grimes TRACE1("fd%d",fdu); 6455b81b6b3SRodney W. Grimes TRACE1("[%s]",fdstates[fdc->state]); 6465b81b6b3SRodney W. Grimes TRACE1("(0x%x)",fd->flags); 6475b81b6b3SRodney W. Grimes untimeout(fd_turnoff, fdu); 6485b81b6b3SRodney W. Grimes timeout(fd_turnoff,fdu,4 * hz); 6495b81b6b3SRodney W. Grimes switch (fdc->state) 6505b81b6b3SRodney W. Grimes { 6515b81b6b3SRodney W. Grimes case DEVIDLE: 6525b81b6b3SRodney W. Grimes case FINDWORK: /* we have found new work */ 6535b81b6b3SRodney W. Grimes fdc->retry = 0; 6545b81b6b3SRodney W. Grimes fd->skip = 0; 6555b81b6b3SRodney W. Grimes fdc->fd = fd; 6565b81b6b3SRodney W. Grimes fdc->fdu = fdu; 6575b81b6b3SRodney W. Grimes /*******************************************************\ 6585b81b6b3SRodney W. Grimes * If the next drive has a motor startup pending, then * 6595b81b6b3SRodney W. Grimes * it will start up in it's own good time * 6605b81b6b3SRodney W. Grimes \*******************************************************/ 6615b81b6b3SRodney W. Grimes if(fd->flags & FD_MOTOR_WAIT) 6625b81b6b3SRodney W. Grimes { 6635b81b6b3SRodney W. Grimes fdc->state = MOTORWAIT; 6645b81b6b3SRodney W. Grimes return(0); /* come back later */ 6655b81b6b3SRodney W. Grimes } 6665b81b6b3SRodney W. Grimes /*******************************************************\ 6675b81b6b3SRodney W. Grimes * Maybe if it's not starting, it SHOULD be starting * 6685b81b6b3SRodney W. Grimes \*******************************************************/ 6695b81b6b3SRodney W. Grimes if (!(fd->flags & FD_MOTOR)) 6705b81b6b3SRodney W. Grimes { 6715b81b6b3SRodney W. Grimes fdc->state = MOTORWAIT; 6725b81b6b3SRodney W. Grimes fd_turnon(fdu); 6735b81b6b3SRodney W. Grimes return(0); 6745b81b6b3SRodney W. Grimes } 6755b81b6b3SRodney W. Grimes else /* at least make sure we are selected */ 6765b81b6b3SRodney W. Grimes { 6775b81b6b3SRodney W. Grimes set_motor(fdcu,fd->fdsu,0); 6785b81b6b3SRodney W. Grimes } 6795b81b6b3SRodney W. Grimes fdc->state = DOSEEK; 6805b81b6b3SRodney W. Grimes break; 6815b81b6b3SRodney W. Grimes case DOSEEK: 6825b81b6b3SRodney W. Grimes if (bp->b_cylin == fd->track) 6835b81b6b3SRodney W. Grimes { 6845b81b6b3SRodney W. Grimes fdc->state = SEEKCOMPLETE; 6855b81b6b3SRodney W. Grimes break; 6865b81b6b3SRodney W. Grimes } 6875b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */ 6885b81b6b3SRodney W. Grimes out_fdc(fdcu,fd->fdsu); /* Drive number */ 6895b81b6b3SRodney W. Grimes out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac); 6905b81b6b3SRodney W. Grimes fd->track = -2; 6915b81b6b3SRodney W. Grimes fdc->state = SEEKWAIT; 692f5f7ba03SJordan K. Hubbard timeout(fd_timeout,fdcu,2 * hz); 6935b81b6b3SRodney W. Grimes return(0); /* will return later */ 6945b81b6b3SRodney W. Grimes case SEEKWAIT: 695f5f7ba03SJordan K. Hubbard untimeout(fd_timeout,fdcu); 6965b81b6b3SRodney W. Grimes /* allow heads to settle */ 6975b81b6b3SRodney W. Grimes timeout(fd_pseudointr,fdcu,hz/50); 6985b81b6b3SRodney W. Grimes fdc->state = SEEKCOMPLETE; 6995b81b6b3SRodney W. Grimes return(0); /* will return later */ 7005b81b6b3SRodney W. Grimes break; 7015b81b6b3SRodney W. Grimes 7025b81b6b3SRodney W. Grimes case SEEKCOMPLETE : /* SEEK DONE, START DMA */ 7035b81b6b3SRodney W. Grimes /* Make sure seek really happened*/ 7045b81b6b3SRodney W. Grimes if(fd->track == -2) 7055b81b6b3SRodney W. Grimes { 7065b81b6b3SRodney W. Grimes int descyl = bp->b_cylin * fd->ft->steptrac; 7075b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SENSEI); 7085b81b6b3SRodney W. Grimes i = in_fdc(fdcu); 7095b81b6b3SRodney W. Grimes cyl = in_fdc(fdcu); 7105b81b6b3SRodney W. Grimes if (cyl != descyl) 7115b81b6b3SRodney W. Grimes { 7125b81b6b3SRodney W. Grimes printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu, 7135b81b6b3SRodney W. Grimes descyl, cyl, i, NE7_ST0BITS); 7145b81b6b3SRodney W. Grimes return(retrier(fdcu)); 7155b81b6b3SRodney W. Grimes } 7165b81b6b3SRodney W. Grimes } 7175b81b6b3SRodney W. Grimes 7185b81b6b3SRodney W. Grimes fd->track = bp->b_cylin; 7195b81b6b3SRodney W. Grimes isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, 7205b81b6b3SRodney W. Grimes FDBLK, fdc->dmachan); 7215b81b6b3SRodney W. Grimes blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 7225b81b6b3SRodney W. Grimes + fd->skip/FDBLK; 7235b81b6b3SRodney W. Grimes sectrac = fd->ft->sectrac; 7245b81b6b3SRodney W. Grimes sec = blknum % (sectrac * fd->ft->heads); 7255b81b6b3SRodney W. Grimes head = sec / sectrac; 7265b81b6b3SRodney W. Grimes sec = sec % sectrac + 1; 7275b81b6b3SRodney W. Grimes /*XXX*/ fd->hddrv = ((head&1)<<2)+fdu; 7285b81b6b3SRodney W. Grimes 7295b81b6b3SRodney W. Grimes if (read) 7305b81b6b3SRodney W. Grimes { 7315b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_READ); /* READ */ 7325b81b6b3SRodney W. Grimes } 7335b81b6b3SRodney W. Grimes else 7345b81b6b3SRodney W. Grimes { 7355b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */ 7365b81b6b3SRodney W. Grimes } 7375b81b6b3SRodney W. Grimes out_fdc(fdcu,head << 2 | fdu); /* head & unit */ 7385b81b6b3SRodney W. Grimes out_fdc(fdcu,fd->track); /* track */ 7395b81b6b3SRodney W. Grimes out_fdc(fdcu,head); 7405b81b6b3SRodney W. Grimes out_fdc(fdcu,sec); /* sector XXX +1? */ 7415b81b6b3SRodney W. Grimes out_fdc(fdcu,fd->ft->secsize); /* sector size */ 7425b81b6b3SRodney W. Grimes out_fdc(fdcu,sectrac); /* sectors/track */ 7435b81b6b3SRodney W. Grimes out_fdc(fdcu,fd->ft->gap); /* gap size */ 7445b81b6b3SRodney W. Grimes out_fdc(fdcu,fd->ft->datalen); /* data length */ 7455b81b6b3SRodney W. Grimes fdc->state = IOCOMPLETE; 7465b81b6b3SRodney W. Grimes timeout(fd_timeout,fdcu,2 * hz); 7475b81b6b3SRodney W. Grimes return(0); /* will return later */ 7485b81b6b3SRodney W. Grimes case IOCOMPLETE: /* IO DONE, post-analyze */ 7495b81b6b3SRodney W. Grimes untimeout(fd_timeout,fdcu); 7505b81b6b3SRodney W. Grimes for(i=0;i<7;i++) 7515b81b6b3SRodney W. Grimes { 7525b81b6b3SRodney W. Grimes fdc->status[i] = in_fdc(fdcu); 7535b81b6b3SRodney W. Grimes } 7545b81b6b3SRodney W. Grimes case IOTIMEDOUT: /*XXX*/ 7555b81b6b3SRodney W. Grimes isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, 7565b81b6b3SRodney W. Grimes FDBLK, fdc->dmachan); 7575b81b6b3SRodney W. Grimes if (fdc->status[0]&0xF8) 7585b81b6b3SRodney W. Grimes { 7595b81b6b3SRodney W. Grimes return(retrier(fdcu)); 7605b81b6b3SRodney W. Grimes } 7615b81b6b3SRodney W. Grimes /* All OK */ 7625b81b6b3SRodney W. Grimes fd->skip += FDBLK; 7635b81b6b3SRodney W. Grimes if (fd->skip < bp->b_bcount) 7645b81b6b3SRodney W. Grimes { 7655b81b6b3SRodney W. Grimes /* set up next transfer */ 7665b81b6b3SRodney W. Grimes blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 7675b81b6b3SRodney W. Grimes + fd->skip/FDBLK; 7685b81b6b3SRodney W. Grimes bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads)); 7695b81b6b3SRodney W. Grimes fdc->state = DOSEEK; 7705b81b6b3SRodney W. Grimes } 7715b81b6b3SRodney W. Grimes else 7725b81b6b3SRodney W. Grimes { 7735b81b6b3SRodney W. Grimes /* ALL DONE */ 7745b81b6b3SRodney W. Grimes fd->skip = 0; 7755b81b6b3SRodney W. Grimes bp->b_resid = 0; 7765b81b6b3SRodney W. Grimes dp->b_actf = bp->av_forw; 7775b81b6b3SRodney W. Grimes biodone(bp); 7785b81b6b3SRodney W. Grimes fdc->fd = (fd_p) 0; 7795b81b6b3SRodney W. Grimes fdc->fdu = -1; 7805b81b6b3SRodney W. Grimes fdc->state = FINDWORK; 7815b81b6b3SRodney W. Grimes } 7825b81b6b3SRodney W. Grimes return(1); 7835b81b6b3SRodney W. Grimes case RESETCTLR: 7845b81b6b3SRodney W. Grimes /* Try a reset, keep motor on */ 7855b81b6b3SRodney W. Grimes set_motor(fdcu,fd->fdsu,1); 7865b81b6b3SRodney W. Grimes DELAY(100); 7875b81b6b3SRodney W. Grimes set_motor(fdcu,fd->fdsu,0); 7885b81b6b3SRodney W. Grimes outb(fdc->baseport+fdctl,fd->ft->trans); 7895b81b6b3SRodney W. Grimes TRACE1("[0x%x->fdctl]",fd->ft->trans); 7905b81b6b3SRodney W. Grimes fdc->retry++; 7915b81b6b3SRodney W. Grimes fdc->state = STARTRECAL; 7925b81b6b3SRodney W. Grimes break; 7935b81b6b3SRodney W. Grimes case STARTRECAL: 7945b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */ 7955b81b6b3SRodney W. Grimes out_fdc(fdcu,0xDF); 7965b81b6b3SRodney W. Grimes out_fdc(fdcu,2); 7975b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ 7985b81b6b3SRodney W. Grimes out_fdc(fdcu,fdu); 7995b81b6b3SRodney W. Grimes fdc->state = RECALWAIT; 8005b81b6b3SRodney W. Grimes return(0); /* will return later */ 8015b81b6b3SRodney W. Grimes case RECALWAIT: 8025b81b6b3SRodney W. Grimes /* allow heads to settle */ 8035b81b6b3SRodney W. Grimes timeout(fd_pseudointr,fdcu,hz/30); 8045b81b6b3SRodney W. Grimes fdc->state = RECALCOMPLETE; 8055b81b6b3SRodney W. Grimes return(0); /* will return later */ 8065b81b6b3SRodney W. Grimes case RECALCOMPLETE: 8075b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SENSEI); 8085b81b6b3SRodney W. Grimes st0 = in_fdc(fdcu); 8095b81b6b3SRodney W. Grimes cyl = in_fdc(fdcu); 8105b81b6b3SRodney W. Grimes if (cyl != 0) 8115b81b6b3SRodney W. Grimes { 8125b81b6b3SRodney W. Grimes printf("fd%d: recal failed ST0 %b cyl %d\n", fdu, 8135b81b6b3SRodney W. Grimes st0, NE7_ST0BITS, cyl); 8145b81b6b3SRodney W. Grimes return(retrier(fdcu)); 8155b81b6b3SRodney W. Grimes } 8165b81b6b3SRodney W. Grimes fd->track = 0; 8175b81b6b3SRodney W. Grimes /* Seek (probably) necessary */ 8185b81b6b3SRodney W. Grimes fdc->state = DOSEEK; 8195b81b6b3SRodney W. Grimes return(1); /* will return immediatly */ 8205b81b6b3SRodney W. Grimes case MOTORWAIT: 8215b81b6b3SRodney W. Grimes if(fd->flags & FD_MOTOR_WAIT) 8225b81b6b3SRodney W. Grimes { 8235b81b6b3SRodney W. Grimes return(0); /* time's not up yet */ 8245b81b6b3SRodney W. Grimes } 8255b81b6b3SRodney W. Grimes fdc->state = DOSEEK; 8265b81b6b3SRodney W. Grimes return(1); /* will return immediatly */ 8275b81b6b3SRodney W. Grimes default: 8285b81b6b3SRodney W. Grimes printf("Unexpected FD int->"); 8295b81b6b3SRodney W. Grimes out_fdc(fdcu,NE7CMD_SENSEI); 8305b81b6b3SRodney W. Grimes st0 = in_fdc(fdcu); 8315b81b6b3SRodney W. Grimes cyl = in_fdc(fdcu); 8325b81b6b3SRodney W. Grimes printf("ST0 = %lx, PCN = %lx\n",i,sec); 8335b81b6b3SRodney W. Grimes out_fdc(fdcu,0x4A); 8345b81b6b3SRodney W. Grimes out_fdc(fdcu,fd->fdsu); 8355b81b6b3SRodney W. Grimes for(i=0;i<7;i++) { 8365b81b6b3SRodney W. Grimes fdc->status[i] = in_fdc(fdcu); 8375b81b6b3SRodney W. Grimes } 8385b81b6b3SRodney W. Grimes printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", 8395b81b6b3SRodney W. Grimes fdc->status[0], 8405b81b6b3SRodney W. Grimes fdc->status[1], 8415b81b6b3SRodney W. Grimes fdc->status[2], 8425b81b6b3SRodney W. Grimes fdc->status[3], 8435b81b6b3SRodney W. Grimes fdc->status[4], 8445b81b6b3SRodney W. Grimes fdc->status[5], 8455b81b6b3SRodney W. Grimes fdc->status[6] ); 8465b81b6b3SRodney W. Grimes return(0); 8475b81b6b3SRodney W. Grimes } 8485b81b6b3SRodney W. Grimes return(1); /* Come back immediatly to new state */ 8495b81b6b3SRodney W. Grimes } 8505b81b6b3SRodney W. Grimes 851f5f7ba03SJordan K. Hubbard retrier(fdcu) 852f5f7ba03SJordan K. Hubbard fdcu_t fdcu; 8535b81b6b3SRodney W. Grimes { 8545b81b6b3SRodney W. Grimes fdc_p fdc = fdc_data + fdcu; 8555b81b6b3SRodney W. Grimes register struct buf *dp,*bp; 8565b81b6b3SRodney W. Grimes 8575b81b6b3SRodney W. Grimes dp = &(fdc->head); 8585b81b6b3SRodney W. Grimes bp = dp->b_actf; 8595b81b6b3SRodney W. Grimes 8605b81b6b3SRodney W. Grimes switch(fdc->retry) 8615b81b6b3SRodney W. Grimes { 8625b81b6b3SRodney W. Grimes case 0: case 1: case 2: 8635b81b6b3SRodney W. Grimes fdc->state = SEEKCOMPLETE; 8645b81b6b3SRodney W. Grimes break; 8655b81b6b3SRodney W. Grimes case 3: case 4: case 5: 8665b81b6b3SRodney W. Grimes fdc->state = STARTRECAL; 8675b81b6b3SRodney W. Grimes break; 8685b81b6b3SRodney W. Grimes case 6: 8695b81b6b3SRodney W. Grimes fdc->state = RESETCTLR; 8705b81b6b3SRodney W. Grimes break; 8715b81b6b3SRodney W. Grimes case 7: 8725b81b6b3SRodney W. Grimes break; 8735b81b6b3SRodney W. Grimes default: 8745b81b6b3SRodney W. Grimes { 87592ed385aSRodney W. Grimes diskerr(bp, "fd", "hard error", LOG_PRINTF, 87692ed385aSRodney W. Grimes fdc->fd->skip, (struct disklabel *)NULL); 87792ed385aSRodney W. Grimes printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS); 8785b81b6b3SRodney W. Grimes printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS); 8795b81b6b3SRodney W. Grimes printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS); 8805b81b6b3SRodney W. Grimes printf("cyl %d hd %d sec %d)\n", 88192ed385aSRodney W. Grimes fdc->status[3], fdc->status[4], fdc->status[5]); 8825b81b6b3SRodney W. Grimes } 8835b81b6b3SRodney W. Grimes bp->b_flags |= B_ERROR; 8845b81b6b3SRodney W. Grimes bp->b_error = EIO; 8855b81b6b3SRodney W. Grimes bp->b_resid = bp->b_bcount - fdc->fd->skip; 8865b81b6b3SRodney W. Grimes dp->b_actf = bp->av_forw; 8875b81b6b3SRodney W. Grimes fdc->fd->skip = 0; 8885b81b6b3SRodney W. Grimes biodone(bp); 88992ed385aSRodney W. Grimes fdc->state = FINDWORK; 8905b81b6b3SRodney W. Grimes fdc->fd = (fd_p) 0; 8915b81b6b3SRodney W. Grimes fdc->fdu = -1; 892f5f7ba03SJordan K. Hubbard /* XXX abort current command, if any. */ 89392ed385aSRodney W. Grimes return(1); 8945b81b6b3SRodney W. Grimes } 8955b81b6b3SRodney W. Grimes fdc->retry++; 8965b81b6b3SRodney W. Grimes return(1); 8975b81b6b3SRodney W. Grimes } 8985b81b6b3SRodney W. Grimes 899f5f7ba03SJordan K. Hubbard /* 900f5f7ba03SJordan K. Hubbard * fdioctl() from jc@irbs.UUCP (John Capo) 901f5f7ba03SJordan K. Hubbard * i386/i386/conf.c needs to have fdioctl() declared and remove the line that 902f5f7ba03SJordan K. Hubbard * defines fdioctl to be enxio. 903f5f7ba03SJordan K. Hubbard * 904f5f7ba03SJordan K. Hubbard * TODO: Reformat. 905f5f7ba03SJordan K. Hubbard * Think about allocating buffer off stack. 906f5f7ba03SJordan K. Hubbard * Don't pass uncast 0's and NULL's to read/write/setdisklabel(). 907f5f7ba03SJordan K. Hubbard * Watch out for NetBSD's different *disklabel() interface. 908f5f7ba03SJordan K. Hubbard */ 9095b81b6b3SRodney W. Grimes 910f5f7ba03SJordan K. Hubbard int 911f5f7ba03SJordan K. Hubbard fdioctl (dev, cmd, addr, flag) 912f5f7ba03SJordan K. Hubbard dev_t dev; 913f5f7ba03SJordan K. Hubbard int cmd; 914f5f7ba03SJordan K. Hubbard caddr_t addr; 915f5f7ba03SJordan K. Hubbard int flag; 916f5f7ba03SJordan K. Hubbard { 917f5f7ba03SJordan K. Hubbard struct fd_type *fdt; 918f5f7ba03SJordan K. Hubbard struct disklabel *dl; 919f5f7ba03SJordan K. Hubbard char buffer[DEV_BSIZE]; 920f5f7ba03SJordan K. Hubbard int error; 921f5f7ba03SJordan K. Hubbard 922f5f7ba03SJordan K. Hubbard error = 0; 923f5f7ba03SJordan K. Hubbard 924f5f7ba03SJordan K. Hubbard switch (cmd) 925f5f7ba03SJordan K. Hubbard { 926f5f7ba03SJordan K. Hubbard case DIOCGDINFO: 927f5f7ba03SJordan K. Hubbard bzero(buffer, sizeof (buffer)); 928f5f7ba03SJordan K. Hubbard dl = (struct disklabel *)buffer; 929f5f7ba03SJordan K. Hubbard dl->d_secsize = FDBLK; 93092ed385aSRodney W. Grimes fdt = fd_data[FDUNIT(minor(dev))].ft; 931f5f7ba03SJordan K. Hubbard dl->d_secpercyl = fdt->size / fdt->tracks; 932f5f7ba03SJordan K. Hubbard dl->d_type = DTYPE_FLOPPY; 933f5f7ba03SJordan K. Hubbard 934f5f7ba03SJordan K. Hubbard if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL) 935f5f7ba03SJordan K. Hubbard error = 0; 936f5f7ba03SJordan K. Hubbard else 937f5f7ba03SJordan K. Hubbard error = EINVAL; 938f5f7ba03SJordan K. Hubbard 939f5f7ba03SJordan K. Hubbard *(struct disklabel *)addr = *dl; 940f5f7ba03SJordan K. Hubbard break; 941f5f7ba03SJordan K. Hubbard 942f5f7ba03SJordan K. Hubbard case DIOCSDINFO: 943f5f7ba03SJordan K. Hubbard 944f5f7ba03SJordan K. Hubbard if ((flag & FWRITE) == 0) 945f5f7ba03SJordan K. Hubbard error = EBADF; 946f5f7ba03SJordan K. Hubbard 947f5f7ba03SJordan K. Hubbard break; 948f5f7ba03SJordan K. Hubbard 949f5f7ba03SJordan K. Hubbard case DIOCWLABEL: 950f5f7ba03SJordan K. Hubbard if ((flag & FWRITE) == 0) 951f5f7ba03SJordan K. Hubbard error = EBADF; 952f5f7ba03SJordan K. Hubbard 953f5f7ba03SJordan K. Hubbard break; 954f5f7ba03SJordan K. Hubbard 955f5f7ba03SJordan K. Hubbard case DIOCWDINFO: 956f5f7ba03SJordan K. Hubbard if ((flag & FWRITE) == 0) 957f5f7ba03SJordan K. Hubbard { 958f5f7ba03SJordan K. Hubbard error = EBADF; 959f5f7ba03SJordan K. Hubbard break; 960f5f7ba03SJordan K. Hubbard } 961f5f7ba03SJordan K. Hubbard 962f5f7ba03SJordan K. Hubbard dl = (struct disklabel *)addr; 963f5f7ba03SJordan K. Hubbard 964f5f7ba03SJordan K. Hubbard if (error = setdisklabel ((struct disklabel *)buffer, dl, 0, NULL)) 965f5f7ba03SJordan K. Hubbard break; 966f5f7ba03SJordan K. Hubbard 967f5f7ba03SJordan K. Hubbard error = writedisklabel(dev, fdstrategy, (struct disklabel *)buffer, NULL); 968f5f7ba03SJordan K. Hubbard break; 969f5f7ba03SJordan K. Hubbard 970f5f7ba03SJordan K. Hubbard default: 971f5f7ba03SJordan K. Hubbard error = EINVAL; 972f5f7ba03SJordan K. Hubbard break; 973f5f7ba03SJordan K. Hubbard } 974f5f7ba03SJordan K. Hubbard return (error); 975f5f7ba03SJordan K. Hubbard } 976f5f7ba03SJordan K. Hubbard 977f5f7ba03SJordan K. Hubbard #endif 978