The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/fd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1990 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Don Ahn.
    7  *
    8  * Copyright (c) 1993, 1994 by
    9  *  jc@irbs.UUCP (John Capo)
   10  *  vak@zebub.msk.su (Serge Vakulenko)
   11  *  ache@astral.msk.su (Andrew A. Chernov)
   12  *
   13  * Copyright (c) 1993, 1994, 1995 by
   14  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
   15  *  dufault@hda.com (Peter Dufault)
   16  *
   17  * Redistribution and use in source and binary forms, with or without
   18  * modification, are permitted provided that the following conditions
   19  * are met:
   20  * 1. Redistributions of source code must retain the above copyright
   21  *    notice, this list of conditions and the following disclaimer.
   22  * 2. Redistributions in binary form must reproduce the above copyright
   23  *    notice, this list of conditions and the following disclaimer in the
   24  *    documentation and/or other materials provided with the distribution.
   25  * 3. All advertising materials mentioning features or use of this software
   26  *    must display the following acknowledgement:
   27  *      This product includes software developed by the University of
   28  *      California, Berkeley and its contributors.
   29  * 4. Neither the name of the University nor the names of its contributors
   30  *    may be used to endorse or promote products derived from this software
   31  *    without specific prior written permission.
   32  *
   33  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   36  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   43  * SUCH DAMAGE.
   44  *
   45  *      from:   @(#)fd.c        7.4 (Berkeley) 5/25/91
   46  * $FreeBSD: src/sys/i386/isa/fd.c,v 1.92.2.7 1999/09/05 08:12:35 peter Exp $
   47  *
   48  */
   49 
   50 #include "ft.h"
   51 #if NFT < 1
   52 #undef NFDC
   53 #endif
   54 #include "fd.h"
   55 #include "opt_fdc.h"
   56 
   57 #if NFDC > 0
   58 
   59 #include <sys/param.h>
   60 #include <sys/systm.h>
   61 #include <sys/kernel.h>
   62 #include <sys/conf.h>
   63 #include <sys/file.h>
   64 #include <sys/ioctl.h>
   65 #include <machine/clock.h>
   66 #include <machine/ioctl_fd.h>
   67 #include <sys/disklabel.h>
   68 #include <sys/buf.h>
   69 #include <sys/uio.h>
   70 #include <sys/malloc.h>
   71 #include <sys/proc.h>
   72 #include <sys/syslog.h>
   73 #ifdef notyet
   74 #include <sys/dkstat.h>
   75 #endif
   76 #include <i386/isa/isa.h>
   77 #include <i386/isa/isa_device.h>
   78 #include <i386/isa/fdreg.h>
   79 #include <i386/isa/fdc.h>
   80 #include <i386/isa/rtc.h>
   81 #include <machine/stdarg.h>
   82 #if NFT > 0
   83 #include <sys/ftape.h>
   84 #include <i386/isa/ftreg.h>
   85 #endif
   86 #ifdef DEVFS
   87 #include <sys/devfsext.h>
   88 #endif
   89 
   90 /* misuse a flag to identify format operation */
   91 #define B_FORMAT B_XXX
   92 
   93 /* configuration flags */
   94 #define FDC_PRETEND_D0  (1 << 0)        /* pretend drive 0 to be there */
   95 
   96 /* internally used only, not really from CMOS: */
   97 #define RTCFDT_144M_PRETENDED   0x1000
   98 
   99 /*
  100  * this biotab field doubles as a field for the physical unit number
  101  * on the controller
  102  */
  103 #define id_physid id_scsiid
  104 
  105 /* error returns for fd_cmd() */
  106 #define FD_FAILED -1
  107 #define FD_NOT_VALID -2
  108 #define FDC_ERRMAX      100     /* do not log more */
  109 
  110 #define NUMTYPES 14
  111 #define NUMDENS  (NUMTYPES - 6)
  112 
  113 /* These defines (-1) must match index for fd_types */
  114 #define F_TAPE_TYPE     0x020   /* bit for fd_types to indicate tape */
  115 #define NO_TYPE         0       /* must match NO_TYPE in ft.c */
  116 #define FD_1720         1
  117 #define FD_1480         2
  118 #define FD_1440         3
  119 #define FD_1200         4
  120 #define FD_820          5
  121 #define FD_800          6
  122 #define FD_720          7
  123 #define FD_360          8
  124 
  125 #define FD_1480in5_25   9
  126 #define FD_1440in5_25   10
  127 #define FD_820in5_25    11
  128 #define FD_800in5_25    12
  129 #define FD_720in5_25    13
  130 #define FD_360in5_25    14
  131 
  132 
  133 static struct fd_type fd_types[NUMTYPES] =
  134 {
  135 { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
  136 { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
  137 { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
  138 { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /*  1.2M in HD 5.25/3.5 */
  139 { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /*  820K in HD 3.5in */
  140 { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /*  800K in HD 3.5in */
  141 {  9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /*  720K in HD 3.5in */
  142 {  9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /*  360K in DD 5.25in */
  143 
  144 { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
  145 { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
  146 { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /*  820K in HD 5.25in */
  147 { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /*  800K in HD 5.25in */
  148 {  9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /*  720K in HD 5.25in */
  149 {  9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /*  360K in HD 5.25in */
  150 };
  151 
  152 #define DRVS_PER_CTLR 2         /* 2 floppies */
  153 
  154 /***********************************************************************\
  155 * Per controller structure.                                             *
  156 \***********************************************************************/
  157 struct fdc_data fdc_data[NFDC];
  158 
  159 /***********************************************************************\
  160 * Per drive structure.                                                  *
  161 * N per controller  (DRVS_PER_CTLR)                                     *
  162 \***********************************************************************/
  163 static struct fd_data {
  164         struct  fdc_data *fdc;  /* pointer to controller structure */
  165         int     fdsu;           /* this units number on this controller */
  166         int     type;           /* Drive type (FD_1440...) */
  167         struct  fd_type *ft;    /* pointer to the type descriptor */
  168         int     flags;
  169 #define FD_OPEN         0x01    /* it's open            */
  170 #define FD_ACTIVE       0x02    /* it's active          */
  171 #define FD_MOTOR        0x04    /* motor should be on   */
  172 #define FD_MOTOR_WAIT   0x08    /* motor coming up      */
  173         int     skip;
  174         int     hddrv;
  175 #define FD_NO_TRACK -2
  176         int     track;          /* where we think the head is */
  177         int     options;        /* user configurable options, see ioctl_fd.h */
  178 #ifdef notyet
  179         int     dkunit;         /* disk stats unit number */
  180 #endif
  181 #ifdef DEVFS
  182         void    *bdevs[1 + NUMDENS + MAXPARTITIONS];
  183         void    *cdevs[1 + NUMDENS + MAXPARTITIONS];
  184 #endif
  185 } fd_data[NFD];
  186 
  187 /***********************************************************************\
  188 * Throughout this file the following conventions will be used:          *
  189 * fd is a pointer to the fd_data struct for the drive in question       *
  190 * fdc is a pointer to the fdc_data struct for the controller            *
  191 * fdu is the floppy drive unit number                                   *
  192 * fdcu is the floppy controller unit number                             *
  193 * fdsu is the floppy drive unit number on that controller. (sub-unit)   *
  194 \***********************************************************************/
  195 
  196 #if NFT > 0
  197 int ftopen(dev_t, int);
  198 int ftintr(ftu_t ftu);
  199 int ftclose(dev_t, int);
  200 void ftstrategy(struct buf *);
  201 int ftioctl(dev_t, int, caddr_t, int, struct proc *);
  202 int ftdump(dev_t);
  203 int ftsize(dev_t);
  204 int ftattach(struct isa_device *, struct isa_device *, int);
  205 #endif
  206 
  207 /* autoconfig functions */
  208 static int fdprobe(struct isa_device *);
  209 static int fdattach(struct isa_device *);
  210 
  211 /* needed for ft driver, thus exported */
  212 int in_fdc(fdcu_t);
  213 int out_fdc(fdcu_t, int);
  214 
  215 /* internal functions */
  216 static void set_motor(fdcu_t, int, int);
  217 #  define TURNON 1
  218 #  define TURNOFF 0
  219 static timeout_t fd_turnoff;
  220 static timeout_t fd_motor_on;
  221 static void fd_turnon(fdu_t);
  222 static void fdc_reset(fdc_p);
  223 static int fd_in(fdcu_t, int *);
  224 static void fdstart(fdcu_t);
  225 static timeout_t fd_timeout;
  226 static timeout_t fd_pseudointr;
  227 static int fdstate(fdcu_t, fdc_p);
  228 static int retrier(fdcu_t);
  229 static int fdformat(dev_t, struct fd_formb *, struct proc *);
  230 
  231 static int enable_fifo(fdc_p fdc);
  232 
  233 static int fifo_threshold = 8;  /* XXX: should be accessible via sysctl */
  234 
  235 
  236 #define DEVIDLE         0
  237 #define FINDWORK        1
  238 #define DOSEEK          2
  239 #define SEEKCOMPLETE    3
  240 #define IOCOMPLETE      4
  241 #define RECALCOMPLETE   5
  242 #define STARTRECAL      6
  243 #define RESETCTLR       7
  244 #define SEEKWAIT        8
  245 #define RECALWAIT       9
  246 #define MOTORWAIT       10
  247 #define IOTIMEDOUT      11
  248 
  249 #ifdef  FDC_DEBUG
  250 static char const * const fdstates[] =
  251 {
  252 "DEVIDLE",
  253 "FINDWORK",
  254 "DOSEEK",
  255 "SEEKCOMPLETE",
  256 "IOCOMPLETE",
  257 "RECALCOMPLETE",
  258 "STARTRECAL",
  259 "RESETCTLR",
  260 "SEEKWAIT",
  261 "RECALWAIT",
  262 "MOTORWAIT",
  263 "IOTIMEDOUT"
  264 };
  265 
  266 /* CAUTION: fd_debug causes huge amounts of logging output */
  267 static int volatile fd_debug = 0;
  268 #define TRACE0(arg) if(fd_debug) printf(arg)
  269 #define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
  270 #else /* FDC_DEBUG */
  271 #define TRACE0(arg)
  272 #define TRACE1(arg1, arg2)
  273 #endif /* FDC_DEBUG */
  274 
  275 /* autoconfig structure */
  276 
  277 struct  isa_driver fdcdriver = {
  278         fdprobe, fdattach, "fdc",
  279 };
  280 
  281 static  d_open_t        Fdopen; /* NOTE, not fdopen */
  282 static  d_close_t       fdclose;
  283 static  d_ioctl_t       fdioctl;
  284 static  d_strategy_t    fdstrategy;
  285 
  286 #define CDEV_MAJOR 9
  287 #define BDEV_MAJOR 2
  288 static struct cdevsw fd_cdevsw;
  289 static struct bdevsw fd_bdevsw = 
  290         { Fdopen,       fdclose,        fdstrategy,     fdioctl,        /*2*/
  291           nodump,       nopsize,        0,      "fd",   &fd_cdevsw,     -1 };
  292 
  293 
  294 static struct isa_device *fdcdevs[NFDC];
  295 
  296 static int
  297 fdc_err(fdcu_t fdcu, const char *s)
  298 {
  299         fdc_data[fdcu].fdc_errs++;
  300         if(s) {
  301                 if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX)
  302                         printf("fdc%d: %s", fdcu, s);
  303                 else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
  304                         printf("fdc%d: too many errors, not logging any more\n",
  305                                fdcu);
  306         }
  307 
  308         return FD_FAILED;
  309 }
  310 
  311 /*
  312  * fd_cmd: Send a command to the chip.  Takes a varargs with this structure:
  313  * Unit number,
  314  * # of output bytes, output bytes as ints ...,
  315  * # of input bytes, input bytes as ints ...
  316  */
  317 
  318 static int
  319 fd_cmd(fdcu_t fdcu, int n_out, ...)
  320 {
  321         u_char cmd;
  322         int n_in;
  323         int n;
  324         va_list ap;
  325 
  326         va_start(ap, n_out);
  327         cmd = (u_char)(va_arg(ap, int));
  328         va_end(ap);
  329         va_start(ap, n_out);
  330         for (n = 0; n < n_out; n++)
  331         {
  332                 if (out_fdc(fdcu, va_arg(ap, int)) < 0)
  333                 {
  334                         char msg[50];
  335                         sprintf(msg,
  336                                 "cmd %x failed at out byte %d of %d\n",
  337                                 cmd, n + 1, n_out);
  338                         return fdc_err(fdcu, msg);
  339                 }
  340         }
  341         n_in = va_arg(ap, int);
  342         for (n = 0; n < n_in; n++)
  343         {
  344                 int *ptr = va_arg(ap, int *);
  345                 if (fd_in(fdcu, ptr) < 0)
  346                 {
  347                         char msg[50];
  348                         sprintf(msg,
  349                                 "cmd %02x failed at in byte %d of %d\n",
  350                                 cmd, n + 1, n_in);
  351                         return fdc_err(fdcu, msg);
  352                 }
  353         }
  354 
  355         return 0;
  356 }
  357 
  358 static int 
  359 enable_fifo(fdc_p fdc)
  360 {
  361         int i, j;
  362 
  363         if ((fdc->flags & FDC_HAS_FIFO) == 0) {
  364                 
  365                 /*
  366                  * XXX: 
  367                  * Cannot use fd_cmd the normal way here, since
  368                  * this might be an invalid command. Thus we send the
  369                  * first byte, and check for an early turn of data directon.
  370                  */
  371                 
  372                 if (out_fdc(fdc->fdcu, I8207X_CONFIGURE) < 0)
  373                         return fdc_err(fdc->fdcu, "Enable FIFO failed\n");
  374                 
  375                 /* If command is invalid, return */
  376                 j = 100000;
  377                 while ((i = inb(fdc->baseport + FDSTS) & (NE7_DIO | NE7_RQM))
  378                        != NE7_RQM && j-- > 0)
  379                         if (i == (NE7_DIO | NE7_RQM)) {
  380                                 fdc_reset(fdc);
  381                                 return FD_FAILED;
  382                         }
  383                 if (j<0 || 
  384                     fd_cmd(fdc->fdcu, 3,
  385                            0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
  386                         fdc_reset(fdc);
  387                         return fdc_err(fdc->fdcu, "Enable FIFO failed\n");
  388                 }
  389                 fdc->flags |= FDC_HAS_FIFO;
  390                 return 0;
  391         }
  392         if (fd_cmd(fdc->fdcu, 4,
  393                    I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
  394                 return fdc_err(fdc->fdcu, "Re-enable FIFO failed\n");
  395         return 0;
  396 }
  397 
  398 static int
  399 fd_sense_drive_status(fdc_p fdc, int *st3p)
  400 {
  401         int st3;
  402 
  403         if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
  404         {
  405                 return fdc_err(fdc->fdcu, "Sense Drive Status failed\n");
  406         }
  407         if (st3p)
  408                 *st3p = st3;
  409 
  410         return 0;
  411 }
  412 
  413 static int
  414 fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
  415 {
  416         int st0, cyl;
  417 
  418         int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0);
  419 
  420         if (ret)
  421         {
  422                 (void)fdc_err(fdc->fdcu,
  423                               "sense intr err reading stat reg 0\n");
  424                 return ret;
  425         }
  426 
  427         if (st0p)
  428                 *st0p = st0;
  429 
  430         if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV)
  431         {
  432                 /*
  433                  * There doesn't seem to have been an interrupt.
  434                  */
  435                 return FD_NOT_VALID;
  436         }
  437 
  438         if (fd_in(fdc->fdcu, &cyl) < 0)
  439         {
  440                 return fdc_err(fdc->fdcu, "can't get cyl num\n");
  441         }
  442 
  443         if (cylp)
  444                 *cylp = cyl;
  445 
  446         return 0;
  447 }
  448 
  449 
  450 static int
  451 fd_read_status(fdc_p fdc, int fdsu)
  452 {
  453         int i, ret;
  454 
  455         for (i = 0; i < 7; i++)
  456         {
  457                 /*
  458                  * XXX types are poorly chosen.  Only bytes can by read
  459                  * from the hardware, but fdc_status wants u_longs and
  460                  * fd_in() gives ints.
  461                  */
  462                 int status;
  463 
  464                 ret = fd_in(fdc->fdcu, &status);
  465                 fdc->status[i] = status;
  466                 if (ret != 0)
  467                         break;
  468         }
  469 
  470         if (ret == 0)
  471                 fdc->flags |= FDC_STAT_VALID;
  472         else
  473                 fdc->flags &= ~FDC_STAT_VALID;
  474 
  475         return ret;
  476 }
  477 
  478 /****************************************************************************/
  479 /*                      autoconfiguration stuff                             */
  480 /****************************************************************************/
  481 
  482 /*
  483  * probe for existance of controller
  484  */
  485 static int
  486 fdprobe(struct isa_device *dev)
  487 {
  488         fdcu_t  fdcu = dev->id_unit;
  489         if(fdc_data[fdcu].flags & FDC_ATTACHED)
  490         {
  491                 printf("fdc%d: unit used multiple times\n", fdcu);
  492                 return 0;
  493         }
  494 
  495         fdcdevs[fdcu] = dev;
  496         fdc_data[fdcu].baseport = dev->id_iobase;
  497 
  498         /* First - lets reset the floppy controller */
  499         outb(dev->id_iobase+FDOUT, 0);
  500         DELAY(100);
  501         outb(dev->id_iobase+FDOUT, FDO_FRST);
  502 
  503         /* see if it can handle a command */
  504         if (fd_cmd(fdcu,
  505                    3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
  506                    0))
  507         {
  508                 return(0);
  509         }
  510         return (IO_FDCSIZE);
  511 }
  512 
  513 /*
  514  * wire controller into system, look for floppy units
  515  */
  516 static int
  517 fdattach(struct isa_device *dev)
  518 {
  519         unsigned fdt;
  520         fdu_t   fdu;
  521         fdcu_t  fdcu = dev->id_unit;
  522         fdc_p   fdc = fdc_data + fdcu;
  523         fd_p    fd;
  524         int     fdsu, st0, st3, i;
  525 #if NFT > 0
  526         int     unithasfd;
  527 #endif
  528         struct isa_device *fdup;
  529         int ic_type = 0;
  530 #ifdef DEVFS
  531         int     mynor;
  532         int     typemynor;
  533         int     typesize;
  534 #endif
  535 
  536         fdc->fdcu = fdcu;
  537         fdc->flags |= FDC_ATTACHED;
  538         fdc->dmachan = dev->id_drq;
  539         /* Acquire the DMA channel forever, The driver will do the rest */
  540         isa_dma_acquire(fdc->dmachan);
  541         isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
  542         fdc->state = DEVIDLE;
  543         /* reset controller, turn motor off, clear fdout mirror reg */
  544         outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
  545         bufq_init(&fdc->head);
  546 
  547         /* check for each floppy drive */
  548         for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
  549                 if (fdup->id_iobase != dev->id_iobase)
  550                         continue;
  551                 fdu = fdup->id_unit;
  552                 fd = &fd_data[fdu];
  553                 if (fdu >= (NFD+NFT))
  554                         continue;
  555                 fdsu = fdup->id_physid;
  556                 /* look up what bios thinks we have */
  557                 switch (fdu) {
  558                         case 0: if (dev->id_flags & FDC_PRETEND_D0)
  559                                         fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
  560                                 else
  561                                         fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
  562                                 break;
  563                         case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
  564                                 break;
  565                         default: fdt = RTCFDT_NONE;
  566                                 break;
  567                 }
  568                 /* is there a unit? */
  569                 if ((fdt == RTCFDT_NONE)
  570 #if NFT > 0
  571                     || (fdsu >= DRVS_PER_CTLR)) {
  572 #else
  573                 ) {
  574                         fd->type = NO_TYPE;
  575 #endif
  576 #if NFT > 0
  577                         /* If BIOS says no floppy, or > 2nd device */
  578                         /* Probe for and attach a floppy tape.     */
  579                         /* Tell FT if there was already a disk     */
  580                         /* with this unit number found.            */
  581 
  582                         unithasfd = 0;
  583                         if (fdu < NFD && fd->type != NO_TYPE)
  584                                 unithasfd = 1;
  585                         if (ftattach(dev, fdup, unithasfd))
  586                                 continue;
  587                         if (fdsu < DRVS_PER_CTLR)
  588                                 fd->type = NO_TYPE;
  589 #endif
  590                         continue;
  591                 }
  592 
  593                 /* select it */
  594                 set_motor(fdcu, fdsu, TURNON);
  595                 DELAY(1000000); /* 1 sec */
  596 
  597                 if (ic_type == 0 &&
  598                     fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0)
  599                 {
  600 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
  601                         printf("fdc%d: ", fdcu);
  602 #endif
  603                         ic_type = (u_char)ic_type;
  604                         switch( ic_type ) {
  605                         case 0x80:
  606 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
  607                                 printf("NEC 765\n");
  608 #endif
  609                                 fdc->fdct = FDC_NE765;
  610                                 break;
  611                         case 0x81:
  612 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
  613                                 printf("Intel 82077\n");
  614 #endif
  615                                 fdc->fdct = FDC_I82077;
  616                                 break;
  617                         case 0x90:
  618 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
  619                                 printf("NEC 72065B\n");
  620 #endif
  621                                 fdc->fdct = FDC_NE72065;
  622                                 break;
  623                         default:
  624 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
  625                                 printf("unknown IC type %02x\n", ic_type);
  626 #endif
  627                                 fdc->fdct = FDC_UNKNOWN;
  628                                 break;
  629                         }
  630                         if (fdc->fdct != FDC_NE765 &&
  631                             fdc->fdct != FDC_UNKNOWN && 
  632                             enable_fifo(fdc) == 0) {
  633                                 printf("fdc%d: FIFO enabled", fdcu);
  634                                 printf(", %d bytes threshold\n", 
  635                                        fifo_threshold);
  636                         }
  637                 }
  638                 if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
  639                     (st3 & NE7_ST3_T0)) {
  640                         /* if at track 0, first seek inwards */
  641                         /* seek some steps: */
  642                         (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
  643                         DELAY(300000); /* ...wait a moment... */
  644                         (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
  645                 }
  646 
  647                 /* If we're at track 0 first seek inwards. */
  648                 if ((fd_sense_drive_status(fdc, &st3) == 0) &&
  649                     (st3 & NE7_ST3_T0)) {
  650                         /* Seek some steps... */
  651                         if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
  652                                 /* ...wait a moment... */
  653                                 DELAY(300000);
  654                                 /* make ctrlr happy: */
  655                                 (void)fd_sense_int(fdc, 0, 0);
  656                         }
  657                 }
  658 
  659                 for(i = 0; i < 2; i++) {
  660                         /*
  661                          * we must recalibrate twice, just in case the
  662                          * heads have been beyond cylinder 76, since most
  663                          * FDCs still barf when attempting to recalibrate
  664                          * more than 77 steps
  665                          */
  666                         /* go back to 0: */
  667                         if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
  668                                 /* a second being enough for full stroke seek*/
  669                                 DELAY(i == 0? 1000000: 300000);
  670 
  671                                 /* anything responding? */
  672                                 if (fd_sense_int(fdc, &st0, 0) == 0 &&
  673                                 (st0 & NE7_ST0_EC) == 0)
  674                                         break; /* already probed succesfully */
  675                         }
  676                 }
  677 
  678                 set_motor(fdcu, fdsu, TURNOFF);
  679 
  680                 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
  681                         continue;
  682 
  683                 fd->track = FD_NO_TRACK;
  684                 fd->fdc = fdc;
  685                 fd->fdsu = fdsu;
  686                 fd->options = 0;
  687                 printf("fd%d: ", fdu);
  688 
  689                 switch (fdt) {
  690                 case RTCFDT_12M:
  691                         printf("1.2MB 5.25in\n");
  692                         fd->type = FD_1200;
  693                         break;
  694                 case RTCFDT_144M | RTCFDT_144M_PRETENDED:
  695                         printf("config-pretended ");
  696                         fdt = RTCFDT_144M;
  697                         /* fallthrough */
  698                 case RTCFDT_144M:
  699                         printf("1.44MB 3.5in\n");
  700                         fd->type = FD_1440;
  701                         break;
  702                 case RTCFDT_288M:
  703                 case RTCFDT_288M_1:
  704                         printf("2.88MB 3.5in - 1.44MB mode\n");
  705                         fd->type = FD_1440;
  706                         break;
  707                 case RTCFDT_360K:
  708                         printf("360KB 5.25in\n");
  709                         fd->type = FD_360;
  710                         break;
  711                 case RTCFDT_720K:
  712                         printf("720KB 3.5in\n");
  713                         fd->type = FD_720;
  714                         break;
  715                 default:
  716                         printf("unknown\n");
  717                         fd->type = NO_TYPE;
  718                         continue;
  719                 }
  720 #ifdef DEVFS
  721                 mynor = fdu << 6;
  722                 fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK,
  723                                                 UID_ROOT, GID_OPERATOR, 0640,
  724                                                 "fd%d", fdu);
  725                 fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR,
  726                                                 UID_ROOT, GID_OPERATOR, 0640,
  727                                                 "rfd%d", fdu);
  728                 for (i = 1; i < 1 + NUMDENS; i++) {
  729                         /*
  730                          * XXX this and the lookup in Fdopen() should be
  731                          * data driven.
  732                          */
  733                         switch (fd->type) {
  734                         case FD_360:
  735                                 if (i != FD_360)
  736                                         continue;
  737                                 break;
  738                         case FD_720:
  739                                 if (i != FD_720 && i != FD_800 && i != FD_820)
  740                                         continue;
  741                                 break;
  742                         case FD_1200:
  743                                 if (i != FD_360 && i != FD_720 && i != FD_800
  744                                     && i != FD_820 && i != FD_1200
  745                                     && i != FD_1440 && i != FD_1480)
  746                                         continue;
  747                                 break;
  748                         case FD_1440:
  749                                 if (i != FD_720 && i != FD_800 && i != FD_820
  750                                     && i != FD_1200 && i != FD_1440
  751                                     && i != FD_1480 && i != FD_1720)
  752                                         continue;
  753                                 break;
  754                         }
  755                         typemynor = mynor | i;
  756                         typesize = fd_types[i - 1].size / 2;
  757                         /*
  758                          * XXX all these conversions give bloated code and
  759                          * confusing names.
  760                          */
  761                         if (typesize == 1476)
  762                                 typesize = 1480;
  763                         if (typesize == 1722)
  764                                 typesize = 1720;
  765                         fd->bdevs[i] =
  766                                 devfs_add_devswf(&fd_bdevsw, typemynor, DV_BLK,
  767                                                  UID_ROOT, GID_OPERATOR, 0640,
  768                                                  "fd%d.%d", fdu, typesize);
  769                         fd->cdevs[i] =
  770                                 devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR,
  771                                                  UID_ROOT, GID_OPERATOR, 0640,
  772                                                  "rfd%d.%d", fdu, typesize);
  773                 }
  774                 for (i = 0; i < MAXPARTITIONS; i++) {
  775                         fd->bdevs[1 + NUMDENS + i] =
  776                                 devfs_link(fd->bdevs[0],
  777                                            "fd%d%c", fdu, 'a' + i);
  778                         fd->cdevs[1 + NUMDENS + i] =
  779                                 devfs_link(fd->cdevs[0],
  780                                            "rfd%d%c", fdu, 'a' + i);
  781                 }
  782 #endif /* DEVFS */
  783 #ifdef notyet
  784                 if (dk_ndrive < DK_NDRIVE) {
  785                         sprintf(dk_names[dk_ndrive], "fd%d", fdu);
  786                         fd->dkunit = dk_ndrive++;
  787                         /*
  788                          * XXX assume rate is FDC_500KBPS.
  789                          */
  790                         dk_wpms[dk_ndrive] = 500000 / 8 / 2;
  791                 } else {
  792                         fd->dkunit = -1;
  793                 }
  794 #endif
  795         }
  796 
  797         return (1);
  798 }
  799 
  800 /****************************************************************************/
  801 /*                            motor control stuff                           */
  802 /*              remember to not deselect the drive we're working on         */
  803 /****************************************************************************/
  804 static void
  805 set_motor(fdcu_t fdcu, int fdsu, int turnon)
  806 {
  807         int fdout = fdc_data[fdcu].fdout;
  808         int needspecify = 0;
  809 
  810         if(turnon) {
  811                 fdout &= ~FDO_FDSEL;
  812                 fdout |= (FDO_MOEN0 << fdsu) + fdsu;
  813         } else
  814                 fdout &= ~(FDO_MOEN0 << fdsu);
  815 
  816         if(!turnon
  817            && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
  818                 /* gonna turn off the last drive, put FDC to bed */
  819                 fdout &= ~ (FDO_FRST|FDO_FDMAEN);
  820         else {
  821                 /* make sure controller is selected and specified */
  822                 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
  823                         needspecify = 1;
  824                 fdout |= (FDO_FRST|FDO_FDMAEN);
  825         }
  826 
  827         outb(fdc_data[fdcu].baseport+FDOUT, fdout);
  828         fdc_data[fdcu].fdout = fdout;
  829         TRACE1("[0x%x->FDOUT]", fdout);
  830 
  831         if(needspecify) {
  832                 /*
  833                  * XXX
  834                  * special case: since we have just woken up the FDC
  835                  * from its sleep, we silently assume the command will
  836                  * be accepted, and do not test for a timeout
  837                  */
  838                 (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
  839                              NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
  840                              0);
  841                 if (fdc_data[fdcu].flags & FDC_HAS_FIFO)
  842                         (void) enable_fifo(&fdc_data[fdcu]);
  843         }
  844 }
  845 
  846 static void
  847 fd_turnoff(void *arg1)
  848 {
  849         fdu_t fdu = (fdu_t)arg1;
  850         int     s;
  851         fd_p fd = fd_data + fdu;
  852 
  853         TRACE1("[fd%d: turnoff]", fdu);
  854 
  855         /*
  856          * Don't turn off the motor yet if the drive is active.
  857          * XXX shouldn't even schedule turnoff until drive is inactive
  858          * and nothing is queued on it.
  859          */
  860         if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) {
  861                 timeout(fd_turnoff, arg1, 4 * hz);
  862                 return;
  863         }
  864 
  865         s = splbio();
  866         fd->flags &= ~FD_MOTOR;
  867         set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF);
  868         splx(s);
  869 }
  870 
  871 static void
  872 fd_motor_on(void *arg1)
  873 {
  874         fdu_t fdu = (fdu_t)arg1;
  875         int     s;
  876 
  877         fd_p fd = fd_data + fdu;
  878         s = splbio();
  879         fd->flags &= ~FD_MOTOR_WAIT;
  880         if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
  881         {
  882                 fdintr(fd->fdc->fdcu);
  883         }
  884         splx(s);
  885 }
  886 
  887 static void
  888 fd_turnon(fdu_t fdu)
  889 {
  890         fd_p fd = fd_data + fdu;
  891         if(!(fd->flags & FD_MOTOR))
  892         {
  893                 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
  894                 set_motor(fd->fdc->fdcu, fd->fdsu, TURNON);
  895                 timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
  896         }
  897 }
  898 
  899 static void
  900 fdc_reset(fdc_p fdc)
  901 {
  902         fdcu_t fdcu = fdc->fdcu;
  903 
  904         /* Try a reset, keep motor on */
  905         outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
  906         TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
  907         DELAY(100);
  908         /* enable FDC, but defer interrupts a moment */
  909         outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN);
  910         TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
  911         DELAY(100);
  912         outb(fdc->baseport + FDOUT, fdc->fdout);
  913         TRACE1("[0x%x->FDOUT]", fdc->fdout);
  914 
  915         /* XXX after a reset, silently believe the FDC will accept commands */
  916         (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
  917                      NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
  918                      0);
  919         if (fdc->flags & FDC_HAS_FIFO)
  920                 (void) enable_fifo(fdc);
  921 }
  922 
  923 /****************************************************************************/
  924 /*                             fdc in/out                                   */
  925 /****************************************************************************/
  926 int
  927 in_fdc(fdcu_t fdcu)
  928 {
  929         int baseport = fdc_data[fdcu].baseport;
  930         int i, j = 100000;
  931         while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
  932                 != (NE7_DIO|NE7_RQM) && j-- > 0)
  933                 if (i == NE7_RQM)
  934                         return fdc_err(fdcu, "ready for output in input\n");
  935         if (j <= 0)
  936                 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0);
  937 #ifdef  FDC_DEBUG
  938         i = inb(baseport+FDDATA);
  939         TRACE1("[FDDATA->0x%x]", (unsigned char)i);
  940         return(i);
  941 #else   /* !FDC_DEBUG */
  942         return inb(baseport+FDDATA);
  943 #endif  /* FDC_DEBUG */
  944 }
  945 
  946 /*
  947  * fd_in: Like in_fdc, but allows you to see if it worked.
  948  */
  949 static int
  950 fd_in(fdcu_t fdcu, int *ptr)
  951 {
  952         int baseport = fdc_data[fdcu].baseport;
  953         int i, j = 100000;
  954         while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
  955                 != (NE7_DIO|NE7_RQM) && j-- > 0)
  956                 if (i == NE7_RQM)
  957                         return fdc_err(fdcu, "ready for output in input\n");
  958         if (j <= 0)
  959                 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0);
  960 #ifdef  FDC_DEBUG
  961         i = inb(baseport+FDDATA);
  962         TRACE1("[FDDATA->0x%x]", (unsigned char)i);
  963         *ptr = i;
  964         return 0;
  965 #else   /* !FDC_DEBUG */
  966         i = inb(baseport+FDDATA);
  967         if (ptr)
  968                 *ptr = i;
  969         return 0;
  970 #endif  /* FDC_DEBUG */
  971 }
  972 
  973 int
  974 out_fdc(fdcu_t fdcu, int x)
  975 {
  976         int baseport = fdc_data[fdcu].baseport;
  977         int i;
  978 
  979         /* Check that the direction bit is set */
  980         i = 100000;
  981         while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
  982         if (i <= 0) return fdc_err(fdcu, "direction bit not set\n");
  983 
  984         /* Check that the floppy controller is ready for a command */
  985         i = 100000;
  986         while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
  987         if (i <= 0)
  988                 return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0);
  989 
  990         /* Send the command and return */
  991         outb(baseport+FDDATA, x);
  992         TRACE1("[0x%x->FDDATA]", x);
  993         return (0);
  994 }
  995 
  996 /****************************************************************************/
  997 /*                           fdopen/fdclose                                 */
  998 /****************************************************************************/
  999 int
 1000 Fdopen(dev_t dev, int flags, int mode, struct proc *p)
 1001 {
 1002         fdu_t fdu = FDUNIT(minor(dev));
 1003         int type = FDTYPE(minor(dev));
 1004         fdc_p   fdc;
 1005 
 1006 #if NFT > 0
 1007         /* check for a tape open */
 1008         if (type & F_TAPE_TYPE)
 1009                 return(ftopen(dev, flags));
 1010 #endif
 1011         /* check bounds */
 1012         if (fdu >= NFD)
 1013                 return(ENXIO);
 1014         fdc = fd_data[fdu].fdc;
 1015         if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
 1016                 return(ENXIO);
 1017         if (type > NUMDENS)
 1018                 return(ENXIO);
 1019         if (type == 0)
 1020                 type = fd_data[fdu].type;
 1021         else {
 1022                 if (type != fd_data[fdu].type) {
 1023                         switch (fd_data[fdu].type) {
 1024                         case FD_360:
 1025                                 return(ENXIO);
 1026                         case FD_720:
 1027                                 if (   type != FD_820
 1028                                     && type != FD_800
 1029                                    )
 1030                                         return(ENXIO);
 1031                                 break;
 1032                         case FD_1200:
 1033                                 switch (type) {
 1034                                 case FD_1480:
 1035                                         type = FD_1480in5_25;
 1036                                         break;
 1037                                 case FD_1440:
 1038                                         type = FD_1440in5_25;
 1039                                         break;
 1040                                 case FD_820:
 1041                                         type = FD_820in5_25;
 1042                                         break;
 1043                                 case FD_800:
 1044                                         type = FD_800in5_25;
 1045                                         break;
 1046                                 case FD_720:
 1047                                         type = FD_720in5_25;
 1048                                         break;
 1049                                 case FD_360:
 1050                                         type = FD_360in5_25;
 1051                                         break;
 1052                                 default:
 1053                                         return(ENXIO);
 1054                                 }
 1055                                 break;
 1056                         case FD_1440:
 1057                                 if (   type != FD_1720
 1058                                     && type != FD_1480
 1059                                     && type != FD_1200
 1060                                     && type != FD_820
 1061                                     && type != FD_800
 1062                                     && type != FD_720
 1063                                     )
 1064                                         return(ENXIO);
 1065                                 break;
 1066                         }
 1067                 }
 1068         }
 1069         fd_data[fdu].ft = fd_types + type - 1;
 1070         fd_data[fdu].flags |= FD_OPEN;
 1071 
 1072         return 0;
 1073 }
 1074 
 1075 int
 1076 fdclose(dev_t dev, int flags, int mode, struct proc *p)
 1077 {
 1078         fdu_t fdu = FDUNIT(minor(dev));
 1079 
 1080 #if NFT > 0
 1081         int type = FDTYPE(minor(dev));
 1082 
 1083         if (type & F_TAPE_TYPE)
 1084                 return ftclose(dev, flags);
 1085 #endif
 1086         fd_data[fdu].flags &= ~FD_OPEN;
 1087         fd_data[fdu].options &= ~FDOPT_NORETRY;
 1088 
 1089         return(0);
 1090 }
 1091 
 1092 
 1093 /****************************************************************************/
 1094 /*                               fdstrategy                                 */
 1095 /****************************************************************************/
 1096 void
 1097 fdstrategy(struct buf *bp)
 1098 {
 1099         unsigned nblocks, blknum, cando;
 1100         int     s;
 1101         fdcu_t  fdcu;
 1102         fdu_t   fdu;
 1103         fdc_p   fdc;
 1104         fd_p    fd;
 1105         size_t  fdblk;
 1106 
 1107         fdu = FDUNIT(minor(bp->b_dev));
 1108         fd = &fd_data[fdu];
 1109         fdc = fd->fdc;
 1110         fdcu = fdc->fdcu;
 1111 
 1112 #if NFT > 0
 1113         if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
 1114                 /* ft tapes do not (yet) support strategy i/o */
 1115                 bp->b_error = ENODEV;
 1116                 bp->b_flags |= B_ERROR;
 1117                 goto bad;
 1118         }
 1119         /* check for controller already busy with tape */
 1120         if (fdc->flags & FDC_TAPE_BUSY) {
 1121                 bp->b_error = EBUSY;
 1122                 bp->b_flags |= B_ERROR;
 1123                 goto bad;
 1124         }
 1125 #endif
 1126         fdblk = 128 << (fd->ft->secsize);
 1127         if (!(bp->b_flags & B_FORMAT)) {
 1128                 if ((fdu >= NFD) || (bp->b_blkno < 0)) {
 1129                         printf(
 1130                 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
 1131                                fdu, (u_long)bp->b_blkno, bp->b_bcount);
 1132                         bp->b_error = EINVAL;
 1133                         bp->b_flags |= B_ERROR;
 1134                         goto bad;
 1135                 }
 1136                 if ((bp->b_bcount % fdblk) != 0) {
 1137                         bp->b_error = EINVAL;
 1138                         bp->b_flags |= B_ERROR;
 1139                         goto bad;
 1140                 }
 1141         }
 1142 
 1143         /*
 1144          * Set up block calculations.
 1145          */
 1146         if (bp->b_blkno > 20000000) {
 1147                 /*
 1148                  * Reject unreasonably high block number, prevent the
 1149                  * multiplication below from overflowing.
 1150                  */
 1151                 bp->b_error = EINVAL;
 1152                 bp->b_flags |= B_ERROR;
 1153                 goto bad;
 1154         }
 1155         blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk;
 1156         nblocks = fd->ft->size;
 1157         bp->b_resid = 0;
 1158         if (blknum + (bp->b_bcount / fdblk) > nblocks) {
 1159                 if (blknum <= nblocks) {
 1160                         cando = (nblocks - blknum) * fdblk;
 1161                         bp->b_resid = bp->b_bcount - cando;
 1162                         if (cando == 0)
 1163                                 goto bad;       /* not actually bad but EOF */
 1164                 } else {
 1165                         bp->b_error = EINVAL;
 1166                         bp->b_flags |= B_ERROR;
 1167                         goto bad;
 1168                 }
 1169         }
 1170         bp->b_pblkno = bp->b_blkno;
 1171         s = splbio();
 1172         bufqdisksort(&fdc->head, bp);
 1173         untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
 1174         fdstart(fdcu);
 1175         splx(s);
 1176         return;
 1177 
 1178 bad:
 1179         biodone(bp);
 1180 }
 1181 
 1182 /***************************************************************\
 1183 *                               fdstart                         *
 1184 * We have just queued something.. if the controller is not busy *
 1185 * then simulate the case where it has just finished a command   *
 1186 * So that it (the interrupt routine) looks on the queue for more*
 1187 * work to do and picks up what we just added.                   *
 1188 * If the controller is already busy, we need do nothing, as it  *
 1189 * will pick up our work when the present work completes         *
 1190 \***************************************************************/
 1191 static void
 1192 fdstart(fdcu_t fdcu)
 1193 {
 1194         int s;
 1195 
 1196         s = splbio();
 1197         if(fdc_data[fdcu].state == DEVIDLE)
 1198         {
 1199                 fdintr(fdcu);
 1200         }
 1201         splx(s);
 1202 }
 1203 
 1204 static void
 1205 fd_timeout(void *arg1)
 1206 {
 1207         fdcu_t fdcu = (fdcu_t)arg1;
 1208         fdu_t fdu = fdc_data[fdcu].fdu;
 1209         int baseport = fdc_data[fdcu].baseport;
 1210         struct buf *bp;
 1211         int s;
 1212 
 1213         bp = bufq_first(&fdc_data[fdcu].head);
 1214 
 1215         /*
 1216          * Due to IBM's brain-dead design, the FDC has a faked ready
 1217          * signal, hardwired to ready == true. Thus, any command
 1218          * issued if there's no diskette in the drive will _never_
 1219          * complete, and must be aborted by resetting the FDC.
 1220          * Many thanks, Big Blue!
 1221          */
 1222 
 1223         s = splbio();
 1224 
 1225         TRACE1("fd%d[fd_timeout()]", fdu);
 1226         /* See if the controller is still busy (patiently awaiting data) */
 1227         if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB)
 1228         {
 1229                 TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS));
 1230                 /* yup, it is; kill it now */
 1231                 fdc_reset(&fdc_data[fdcu]);
 1232                 printf("fd%d: Operation timeout\n", fdu);
 1233         }
 1234 
 1235         if (bp)
 1236         {
 1237                 retrier(fdcu);
 1238                 fdc_data[fdcu].status[0] = NE7_ST0_IC_RC;
 1239                 fdc_data[fdcu].state = IOTIMEDOUT;
 1240                 if( fdc_data[fdcu].retry < 6)
 1241                         fdc_data[fdcu].retry = 6;
 1242         }
 1243         else
 1244         {
 1245                 fdc_data[fdcu].fd = (fd_p) 0;
 1246                 fdc_data[fdcu].fdu = -1;
 1247                 fdc_data[fdcu].state = DEVIDLE;
 1248         }
 1249         fdintr(fdcu);
 1250         splx(s);
 1251 }
 1252 
 1253 /* just ensure it has the right spl */
 1254 static void
 1255 fd_pseudointr(void *arg1)
 1256 {
 1257         fdcu_t fdcu = (fdcu_t)arg1;
 1258         int     s;
 1259 
 1260         s = splbio();
 1261         fdintr(fdcu);
 1262         splx(s);
 1263 }
 1264 
 1265 /***********************************************************************\
 1266 *                                 fdintr                                *
 1267 * keep calling the state machine until it returns a 0                   *
 1268 * ALWAYS called at SPLBIO                                               *
 1269 \***********************************************************************/
 1270 void
 1271 fdintr(fdcu_t fdcu)
 1272 {
 1273         fdc_p fdc = fdc_data + fdcu;
 1274 #if NFT > 0
 1275         fdu_t fdu = fdc->fdu;
 1276 
 1277         if (fdc->flags & FDC_TAPE_BUSY)
 1278                 (ftintr(fdu));
 1279         else
 1280 #endif
 1281                 while(fdstate(fdcu, fdc))
 1282                         ;
 1283 }
 1284 
 1285 /***********************************************************************\
 1286 * The controller state machine.                                         *
 1287 * if it returns a non zero value, it should be called again immediatly  *
 1288 \***********************************************************************/
 1289 static int
 1290 fdstate(fdcu_t fdcu, fdc_p fdc)
 1291 {
 1292         int read, format, head, sec = 0, sectrac, st0, cyl, st3;
 1293         unsigned blknum = 0, b_cylinder = 0;
 1294         fdu_t fdu = fdc->fdu;
 1295         fd_p fd;
 1296         register struct buf *bp;
 1297         struct fd_formb *finfo = NULL;
 1298         size_t fdblk;
 1299 
 1300         bp = bufq_first(&fdc->head);
 1301         if(!bp) {
 1302                 /***********************************************\
 1303                 * nothing left for this controller to do        *
 1304                 * Force into the IDLE state,                    *
 1305                 \***********************************************/
 1306                 fdc->state = DEVIDLE;
 1307                 if(fdc->fd)
 1308                 {
 1309                         printf("fd%d: unexpected valid fd pointer\n",
 1310                                fdc->fdu);
 1311                         fdc->fd = (fd_p) 0;
 1312                         fdc->fdu = -1;
 1313                 }
 1314                 TRACE1("[fdc%d IDLE]", fdcu);
 1315                 return(0);
 1316         }
 1317         fdu = FDUNIT(minor(bp->b_dev));
 1318         fd = fd_data + fdu;
 1319         fdblk = 128 << fd->ft->secsize;
 1320         if (fdc->fd && (fd != fdc->fd))
 1321         {
 1322                 printf("fd%d: confused fd pointers\n", fdu);
 1323         }
 1324         read = bp->b_flags & B_READ;
 1325         format = bp->b_flags & B_FORMAT;
 1326         if(format) {
 1327                 finfo = (struct fd_formb *)bp->b_un.b_addr;
 1328                 fd->skip = (char *)&(finfo->fd_formb_cylno(0))
 1329                         - (char *)finfo;
 1330         }
 1331         if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
 1332                 blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk +
 1333                         fd->skip/fdblk;
 1334                 b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
 1335         }
 1336         TRACE1("fd%d", fdu);
 1337         TRACE1("[%s]", fdstates[fdc->state]);
 1338         TRACE1("(0x%x)", fd->flags);
 1339         untimeout(fd_turnoff, (caddr_t)fdu);
 1340         timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
 1341         switch (fdc->state)
 1342         {
 1343         case DEVIDLE:
 1344         case FINDWORK:  /* we have found new work */
 1345                 fdc->retry = 0;
 1346                 fd->skip = 0;
 1347                 fdc->fd = fd;
 1348                 fdc->fdu = fdu;
 1349                 outb(fdc->baseport+FDCTL, fd->ft->trans);
 1350                 TRACE1("[0x%x->FDCTL]", fd->ft->trans);
 1351                 /*******************************************************\
 1352                 * If the next drive has a motor startup pending, then   *
 1353                 * it will start up in it's own good time                *
 1354                 \*******************************************************/
 1355                 if(fd->flags & FD_MOTOR_WAIT)
 1356                 {
 1357                         fdc->state = MOTORWAIT;
 1358                         return(0); /* come back later */
 1359                 }
 1360                 /*******************************************************\
 1361                 * Maybe if it's not starting, it SHOULD be starting     *
 1362                 \*******************************************************/
 1363                 if (!(fd->flags & FD_MOTOR))
 1364                 {
 1365                         fdc->state = MOTORWAIT;
 1366                         fd_turnon(fdu);
 1367                         return(0);
 1368                 }
 1369                 else    /* at least make sure we are selected */
 1370                 {
 1371                         set_motor(fdcu, fd->fdsu, TURNON);
 1372                 }
 1373                 fdc->state = DOSEEK;
 1374                 break;
 1375         case DOSEEK:
 1376                 if (b_cylinder == (unsigned)fd->track)
 1377                 {
 1378                         fdc->state = SEEKCOMPLETE;
 1379                         break;
 1380                 }
 1381                 if (fd_cmd(fdcu, 3, NE7CMD_SEEK,
 1382                            fd->fdsu, b_cylinder * fd->ft->steptrac,
 1383                            0))
 1384                 {
 1385                         /*
 1386                          * seek command not accepted, looks like
 1387                          * the FDC went off to the Saints...
 1388                          */
 1389                         fdc->retry = 6; /* try a reset */
 1390                         return(retrier(fdcu));
 1391                 }
 1392                 fd->track = FD_NO_TRACK;
 1393                 fdc->state = SEEKWAIT;
 1394                 return(0);      /* will return later */
 1395         case SEEKWAIT:
 1396                 /* allow heads to settle */
 1397                 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16);
 1398                 fdc->state = SEEKCOMPLETE;
 1399                 return(0);      /* will return later */
 1400         case SEEKCOMPLETE : /* SEEK DONE, START DMA */
 1401                 /* Make sure seek really happened*/
 1402                 if(fd->track == FD_NO_TRACK)
 1403                 {
 1404                         int descyl = b_cylinder * fd->ft->steptrac;
 1405                         do {
 1406                                 /*
 1407                                  * This might be a "ready changed" interrupt,
 1408                                  * which cannot really happen since the
 1409                                  * RDY pin is hardwired to + 5 volts.  This
 1410                                  * generally indicates a "bouncing" intr
 1411                                  * line, so do one of the following:
 1412                                  *
 1413                                  * When running on an enhanced FDC that is
 1414                                  * known to not go stuck after responding
 1415                                  * with INVALID, fetch all interrupt states
 1416                                  * until seeing either an INVALID or a
 1417                                  * real interrupt condition.
 1418                                  *
 1419                                  * When running on a dumb old NE765, give
 1420                                  * up immediately.  The controller will
 1421                                  * provide up to four dummy RC interrupt
 1422                                  * conditions right after reset (for the
 1423                                  * corresponding four drives), so this is
 1424                                  * our only chance to get notice that it
 1425                                  * was not the FDC that caused the interrupt.
 1426                                  */
 1427                                 if (fd_sense_int(fdc, &st0, &cyl)
 1428                                     == FD_NOT_VALID)
 1429                                         return 0;
 1430                                 if(fdc->fdct == FDC_NE765
 1431                                    && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 1432                                         return 0; /* hope for a real intr */
 1433                         } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 1434 
 1435                         if (0 == descyl)
 1436                         {
 1437                                 int failed = 0;
 1438                                 /*
 1439                                  * seek to cyl 0 requested; make sure we are
 1440                                  * really there
 1441                                  */
 1442                                 if (fd_sense_drive_status(fdc, &st3))
 1443                                         failed = 1;
 1444                                 if ((st3 & NE7_ST3_T0) == 0) {
 1445                                         printf(
 1446                 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
 1447                                                fdu, st3, NE7_ST3BITS);
 1448                                         failed = 1;
 1449                                 }
 1450 
 1451                                 if (failed)
 1452                                 {
 1453                                         if(fdc->retry < 3)
 1454                                                 fdc->retry = 3;
 1455                                         return(retrier(fdcu));
 1456                                 }
 1457                         }
 1458 
 1459                         if (cyl != descyl)
 1460                         {
 1461                                 printf(
 1462                 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
 1463                                        fdu, descyl, cyl, st0);
 1464                                 return(retrier(fdcu));
 1465                         }
 1466                 }
 1467 
 1468                 fd->track = b_cylinder;
 1469                 isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
 1470                         format ? bp->b_bcount : fdblk, fdc->dmachan);
 1471                 sectrac = fd->ft->sectrac;
 1472                 sec = blknum %  (sectrac * fd->ft->heads);
 1473                 head = sec / sectrac;
 1474                 sec = sec % sectrac + 1;
 1475                 fd->hddrv = ((head&1)<<2)+fdu;
 1476 
 1477                 if(format || !read)
 1478                 {
 1479                         /* make sure the drive is writable */
 1480                         if(fd_sense_drive_status(fdc, &st3) != 0)
 1481                         {
 1482                                 /* stuck controller? */
 1483                                 fdc->retry = 6; /* reset the beast */
 1484                                 return(retrier(fdcu));
 1485                         }
 1486                         if(st3 & NE7_ST3_WP)
 1487                         {
 1488                                 /*
 1489                                  * XXX YES! this is ugly.
 1490                                  * in order to force the current operation
 1491                                  * to fail, we will have to fake an FDC
 1492                                  * error - all error handling is done
 1493                                  * by the retrier()
 1494                                  */
 1495                                 fdc->status[0] = NE7_ST0_IC_AT;
 1496                                 fdc->status[1] = NE7_ST1_NW;
 1497                                 fdc->status[2] = 0;
 1498                                 fdc->status[3] = fd->track;
 1499                                 fdc->status[4] = head;
 1500                                 fdc->status[5] = sec;
 1501                                 fdc->retry = 8; /* break out immediately */
 1502                                 fdc->state = IOTIMEDOUT; /* not really... */
 1503                                 return (1);
 1504                         }
 1505                 }
 1506 
 1507                 if(format)
 1508                 {
 1509                         /* formatting */
 1510                         if(fd_cmd(fdcu, 6,
 1511                                   NE7CMD_FORMAT,
 1512                                   head << 2 | fdu,
 1513                                   finfo->fd_formb_secshift,
 1514                                   finfo->fd_formb_nsecs,
 1515                                   finfo->fd_formb_gaplen,
 1516                                   finfo->fd_formb_fillbyte,
 1517                                   0))
 1518                         {
 1519                                 /* controller fell over */
 1520                                 fdc->retry = 6;
 1521                                 return(retrier(fdcu));
 1522                         }
 1523                 }
 1524                 else
 1525                 {
 1526                         if (fd_cmd(fdcu, 9,
 1527                                    (read ? NE7CMD_READ : NE7CMD_WRITE),
 1528                                    head << 2 | fdu,  /* head & unit */
 1529                                    fd->track,        /* track */
 1530                                    head,
 1531                                    sec,              /* sector + 1 */
 1532                                    fd->ft->secsize,  /* sector size */
 1533                                    sectrac,          /* sectors/track */
 1534                                    fd->ft->gap,      /* gap size */
 1535                                    fd->ft->datalen,  /* data length */
 1536                                    0))
 1537                         {
 1538                                 /* the beast is sleeping again */
 1539                                 fdc->retry = 6;
 1540                                 return(retrier(fdcu));
 1541                         }
 1542                 }
 1543                 fdc->state = IOCOMPLETE;
 1544                 timeout(fd_timeout, (caddr_t)fdcu, hz);
 1545                 return(0);      /* will return later */
 1546         case IOCOMPLETE: /* IO DONE, post-analyze */
 1547                 untimeout(fd_timeout, (caddr_t)fdcu);
 1548 
 1549                 if (fd_read_status(fdc, fd->fdsu))
 1550                 {
 1551                         if (fdc->retry < 6)
 1552                                 fdc->retry = 6; /* force a reset */
 1553                         return retrier(fdcu);
 1554                 }
 1555 
 1556                 fdc->state = IOTIMEDOUT;
 1557 
 1558                 /* FALLTHROUGH */
 1559 
 1560         case IOTIMEDOUT:
 1561                 isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
 1562                             format ? bp->b_bcount : fdblk, fdc->dmachan);
 1563                 if (fdc->status[0] & NE7_ST0_IC)
 1564                 {
 1565                         if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 1566                             && fdc->status[1] & NE7_ST1_OR) {
 1567                                 /*
 1568                                  * DMA overrun. Someone hogged the bus
 1569                                  * and didn't release it in time for the
 1570                                  * next FDC transfer.
 1571                                  * Just restart it, don't increment retry
 1572                                  * count. (vak)
 1573                                  */
 1574                                 fdc->state = SEEKCOMPLETE;
 1575                                 return (1);
 1576                         }
 1577                         else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
 1578                                 && fdc->retry < 6)
 1579                                 fdc->retry = 6; /* force a reset */
 1580                         else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 1581                                 && fdc->status[2] & NE7_ST2_WC
 1582                                 && fdc->retry < 3)
 1583                                 fdc->retry = 3; /* force recalibrate */
 1584                         return(retrier(fdcu));
 1585                 }
 1586                 /* All OK */
 1587                 fd->skip += fdblk;
 1588                 if (!format && fd->skip < bp->b_bcount - bp->b_resid)
 1589                 {
 1590                         /* set up next transfer */
 1591                         fdc->state = DOSEEK;
 1592                 }
 1593                 else
 1594                 {
 1595                         /* ALL DONE */
 1596                         fd->skip = 0;
 1597                         bufq_remove(&fdc->head, bp);
 1598                         biodone(bp);
 1599                         fdc->fd = (fd_p) 0;
 1600                         fdc->fdu = -1;
 1601                         fdc->state = FINDWORK;
 1602                 }
 1603                 return(1);
 1604         case RESETCTLR:
 1605                 fdc_reset(fdc);
 1606                 fdc->retry++;
 1607                 fdc->state = STARTRECAL;
 1608                 break;
 1609         case STARTRECAL:
 1610                 /* XXX clear the fdc results from the last reset, if any. */
 1611                 {
 1612                         int i;
 1613                         for (i = 0; i < 4; i++)
 1614                                 (void)fd_sense_int(fdc, &st0, &cyl);
 1615                 }
 1616 
 1617                 if(fd_cmd(fdcu,
 1618                           2, NE7CMD_RECAL, fdu,
 1619                           0)) /* Recalibrate Function */
 1620                 {
 1621                         /* arrgl */
 1622                         fdc->retry = 6;
 1623                         return(retrier(fdcu));
 1624                 }
 1625                 fdc->state = RECALWAIT;
 1626                 return(0);      /* will return later */
 1627         case RECALWAIT:
 1628                 /* allow heads to settle */
 1629                 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8);
 1630                 fdc->state = RECALCOMPLETE;
 1631                 return(0);      /* will return later */
 1632         case RECALCOMPLETE:
 1633                 do {
 1634                         /*
 1635                          * See SEEKCOMPLETE for a comment on this:
 1636                          */
 1637                         if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
 1638                                 return 0;
 1639                         if(fdc->fdct == FDC_NE765
 1640                            && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 1641                                 return 0; /* hope for a real intr */
 1642                 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 1643                 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
 1644                 {
 1645                         if(fdc->retry > 3)
 1646                                 /*
 1647                                  * a recalibrate from beyond cylinder 77
 1648                                  * will "fail" due to the FDC limitations;
 1649                                  * since people used to complain much about
 1650                                  * the failure message, try not logging
 1651                                  * this one if it seems to be the first
 1652                                  * time in a line
 1653                                  */
 1654                                 printf("fd%d: recal failed ST0 %b cyl %d\n",
 1655                                        fdu, st0, NE7_ST0BITS, cyl);
 1656                         if(fdc->retry < 3) fdc->retry = 3;
 1657                         return(retrier(fdcu));
 1658                 }
 1659                 fd->track = 0;
 1660                 /* Seek (probably) necessary */
 1661                 fdc->state = DOSEEK;
 1662                 return(1);      /* will return immediatly */
 1663         case MOTORWAIT:
 1664                 if(fd->flags & FD_MOTOR_WAIT)
 1665                 {
 1666                         return(0); /* time's not up yet */
 1667                 }
 1668                 /*
 1669                  * since the controller was off, it has lost its
 1670                  * idea about the current track it were; thus,
 1671                  * recalibrate the bastard
 1672                  */
 1673                 fdc->state = STARTRECAL;
 1674                 return(1);      /* will return immediatly */
 1675         default:
 1676                 printf("fdc%d: Unexpected FD int->", fdcu);
 1677                 if (fd_read_status(fdc, fd->fdsu) == 0)
 1678                         printf("FDC status :%lx %lx %lx %lx %lx %lx %lx   ",
 1679                                fdc->status[0],
 1680                                fdc->status[1],
 1681                                fdc->status[2],
 1682                                fdc->status[3],
 1683                                fdc->status[4],
 1684                                fdc->status[5],
 1685                                fdc->status[6] );
 1686                 else
 1687                         printf("No status available   ");
 1688                 if (fd_sense_int(fdc, &st0, &cyl) != 0)
 1689                 {
 1690                         printf("[controller is dead now]\n");
 1691                         return(0);
 1692                 }
 1693                 printf("ST0 = %x, PCN = %x\n", st0, cyl);
 1694                 return(0);
 1695         }
 1696         /*XXX confusing: some branches return immediately, others end up here*/
 1697         return(1); /* Come back immediatly to new state */
 1698 }
 1699 
 1700 static int
 1701 retrier(fdcu)
 1702         fdcu_t fdcu;
 1703 {
 1704         fdc_p fdc = fdc_data + fdcu;
 1705         register struct buf *bp;
 1706 
 1707         bp = bufq_first(&fdc->head);
 1708 
 1709         if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY)
 1710                 goto fail;
 1711         switch(fdc->retry)
 1712         {
 1713         case 0: case 1: case 2:
 1714                 fdc->state = SEEKCOMPLETE;
 1715                 break;
 1716         case 3: case 4: case 5:
 1717                 fdc->state = STARTRECAL;
 1718                 break;
 1719         case 6:
 1720                 fdc->state = RESETCTLR;
 1721                 break;
 1722         case 7:
 1723                 break;
 1724         default:
 1725         fail:
 1726                 {
 1727                         dev_t sav_b_dev = bp->b_dev;
 1728                         /* Trick diskerr */
 1729                         bp->b_dev = makedev(major(bp->b_dev),
 1730                                             (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
 1731                         diskerr(bp, "fd", "hard error", LOG_PRINTF,
 1732                                 fdc->fd->skip / DEV_BSIZE,
 1733                                 (struct disklabel *)NULL);
 1734                         bp->b_dev = sav_b_dev;
 1735                         if (fdc->flags & FDC_STAT_VALID)
 1736                         {
 1737                                 printf(
 1738                         " (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n",
 1739                                        fdc->status[0], NE7_ST0BITS,
 1740                                        fdc->status[1], NE7_ST1BITS,
 1741                                        fdc->status[2], NE7_ST2BITS,
 1742                                        fdc->status[3], fdc->status[4],
 1743                                        fdc->status[5]);
 1744                         }
 1745                         else
 1746                                 printf(" (No status)\n");
 1747                 }
 1748                 bp->b_flags |= B_ERROR;
 1749                 bp->b_error = EIO;
 1750                 bp->b_resid += bp->b_bcount - fdc->fd->skip;
 1751                 bufq_remove(&fdc->head, bp);
 1752                 fdc->fd->skip = 0;
 1753                 biodone(bp);
 1754                 fdc->state = FINDWORK;
 1755                 fdc->fd = (fd_p) 0;
 1756                 fdc->fdu = -1;
 1757                 /* XXX abort current command, if any.  */
 1758                 return(1);
 1759         }
 1760         fdc->retry++;
 1761         return(1);
 1762 }
 1763 
 1764 static int
 1765 fdformat(dev, finfo, p)
 1766         dev_t dev;
 1767         struct fd_formb *finfo;
 1768         struct proc *p;
 1769 {
 1770         fdu_t   fdu;
 1771         fd_p    fd;
 1772 
 1773         struct buf *bp;
 1774         int rv = 0, s;
 1775         size_t fdblk;
 1776 
 1777         fdu = FDUNIT(minor(dev));
 1778         fd = &fd_data[fdu];
 1779         fdblk = 128 << fd->ft->secsize;
 1780 
 1781         /* set up a buffer header for fdstrategy() */
 1782         bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
 1783         if(bp == 0)
 1784                 return ENOBUFS;
 1785         /*
 1786          * keep the process from being swapped
 1787          */
 1788         p->p_flag |= P_PHYSIO;
 1789         bzero((void *)bp, sizeof(struct buf));
 1790         bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
 1791         bp->b_proc = p;
 1792         bp->b_dev = dev;
 1793 
 1794         /*
 1795          * calculate a fake blkno, so fdstrategy() would initiate a
 1796          * seek to the requested cylinder
 1797          */
 1798         bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
 1799                 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
 1800 
 1801         bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
 1802         bp->b_un.b_addr = (caddr_t)finfo;
 1803 
 1804         /* now do the format */
 1805         fdstrategy(bp);
 1806 
 1807         /* ...and wait for it to complete */
 1808         s = splbio();
 1809         while(!(bp->b_flags & B_DONE))
 1810         {
 1811                 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
 1812                 if(rv == EWOULDBLOCK)
 1813                         break;
 1814         }
 1815         splx(s);
 1816 
 1817         if(rv == EWOULDBLOCK) {
 1818                 /* timed out */
 1819                 rv = EIO;
 1820                 biodone(bp);
 1821         }
 1822         if(bp->b_flags & B_ERROR)
 1823                 rv = bp->b_error;
 1824         /*
 1825          * allow the process to be swapped
 1826          */
 1827         p->p_flag &= ~P_PHYSIO;
 1828         free(bp, M_TEMP);
 1829         return rv;
 1830 }
 1831 
 1832 /*
 1833  * TODO: don't allocate buffer on stack.
 1834  */
 1835 
 1836 int
 1837 fdioctl(dev, cmd, addr, flag, p)
 1838         dev_t dev;
 1839         int cmd;
 1840         caddr_t addr;
 1841         int flag;
 1842         struct proc *p;
 1843 {
 1844         fdu_t   fdu = FDUNIT(minor(dev));
 1845         fd_p    fd = &fd_data[fdu];
 1846         size_t fdblk;
 1847 
 1848         struct fd_type *fdt;
 1849         struct disklabel *dl;
 1850         char buffer[DEV_BSIZE];
 1851         int error = 0;
 1852 
 1853 #if NFT > 0
 1854         int type = FDTYPE(minor(dev));
 1855 
 1856         /* check for a tape ioctl */
 1857         if (type & F_TAPE_TYPE)
 1858                 return ftioctl(dev, cmd, addr, flag, p);
 1859 #endif
 1860 
 1861         fdblk = 128 << fd->ft->secsize;
 1862 
 1863         switch (cmd)
 1864         {
 1865         case DIOCGDINFO:
 1866                 bzero(buffer, sizeof (buffer));
 1867                 dl = (struct disklabel *)buffer;
 1868                 dl->d_secsize = fdblk;
 1869                 fdt = fd_data[FDUNIT(minor(dev))].ft;
 1870                 dl->d_secpercyl = fdt->size / fdt->tracks;
 1871                 dl->d_type = DTYPE_FLOPPY;
 1872 
 1873                 if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl)
 1874                     == NULL)
 1875                         error = 0;
 1876                 else
 1877                         error = EINVAL;
 1878 
 1879                 *(struct disklabel *)addr = *dl;
 1880                 break;
 1881 
 1882         case DIOCSDINFO:
 1883                 if ((flag & FWRITE) == 0)
 1884                         error = EBADF;
 1885                 break;
 1886 
 1887         case DIOCWLABEL:
 1888                 if ((flag & FWRITE) == 0)
 1889                         error = EBADF;
 1890                 break;
 1891 
 1892         case DIOCWDINFO:
 1893                 if ((flag & FWRITE) == 0)
 1894                 {
 1895                         error = EBADF;
 1896                         break;
 1897                 }
 1898 
 1899                 dl = (struct disklabel *)addr;
 1900 
 1901                 if ((error = setdisklabel((struct disklabel *)buffer, dl,
 1902                                           (u_long)0)) != 0)
 1903                         break;
 1904 
 1905                 error = writedisklabel(dev, fdstrategy,
 1906                                        (struct disklabel *)buffer);
 1907                 break;
 1908 
 1909         case FD_FORM:
 1910                 if((flag & FWRITE) == 0)
 1911                         error = EBADF;  /* must be opened for writing */
 1912                 else if(((struct fd_formb *)addr)->format_version !=
 1913                         FD_FORMAT_VERSION)
 1914                         error = EINVAL; /* wrong version of formatting prog */
 1915                 else
 1916                         error = fdformat(dev, (struct fd_formb *)addr, p);
 1917                 break;
 1918 
 1919         case FD_GTYPE:                  /* get drive type */
 1920                 *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
 1921                 break;
 1922 
 1923         case FD_STYPE:                  /* set drive type */
 1924                 /* this is considered harmful; only allow for superuser */
 1925                 if(suser(p->p_ucred, &p->p_acflag) != 0)
 1926                         return EPERM;
 1927                 *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr;
 1928                 break;
 1929 
 1930         case FD_GOPTS:                  /* get drive options */
 1931                 *(int *)addr = fd_data[FDUNIT(minor(dev))].options;
 1932                 break;
 1933 
 1934         case FD_SOPTS:                  /* set drive options */
 1935                 fd_data[FDUNIT(minor(dev))].options = *(int *)addr;
 1936                 break;
 1937 
 1938         default:
 1939                 error = ENOTTY;
 1940                 break;
 1941         }
 1942         return (error);
 1943 }
 1944 
 1945 
 1946 static fd_devsw_installed = 0;
 1947 
 1948 static void     fd_drvinit(void *notused )
 1949 {
 1950 
 1951         if( ! fd_devsw_installed ) {
 1952                 bdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &fd_bdevsw);
 1953                 fd_devsw_installed = 1;
 1954         }
 1955 }
 1956 
 1957 SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL)
 1958 
 1959 #endif
 1960 /*
 1961  * Hello emacs, these are the
 1962  * Local Variables:
 1963  *  c-indent-level:               8
 1964  *  c-continued-statement-offset: 8
 1965  *  c-continued-brace-offset:     0
 1966  *  c-brace-offset:              -8
 1967  *  c-brace-imaginary-offset:     0
 1968  *  c-argdecl-indent:             8
 1969  *  c-label-offset:              -8
 1970  *  c++-hanging-braces:           1
 1971  *  c++-access-specifier-offset: -8
 1972  *  c++-empty-arglist-indent:     8
 1973  *  c++-friend-offset:            0
 1974  * End:
 1975  */

Cache object: 87a95ebe13fc3f5d6cc013be826f15bc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.