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/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  * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
    9  * aided by the Linux floppy driver modifications from David Bateman
   10  * (dbateman@eng.uts.edu.au).
   11  *
   12  * Copyright (c) 1993, 1994 by
   13  *  jc@irbs.UUCP (John Capo)
   14  *  vak@zebub.msk.su (Serge Vakulenko)
   15  *  ache@astral.msk.su (Andrew A. Chernov)
   16  *
   17  * Copyright (c) 1993, 1994, 1995 by
   18  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
   19  *  dufault@hda.com (Peter Dufault)
   20  *
   21  * Copyright (c) 2001 Joerg Wunsch,
   22  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
   23  *
   24  * Redistribution and use in source and binary forms, with or without
   25  * modification, are permitted provided that the following conditions
   26  * are met:
   27  * 1. Redistributions of source code must retain the above copyright
   28  *    notice, this list of conditions and the following disclaimer.
   29  * 2. Redistributions in binary form must reproduce the above copyright
   30  *    notice, this list of conditions and the following disclaimer in the
   31  *    documentation and/or other materials provided with the distribution.
   32  * 3. All advertising materials mentioning features or use of this software
   33  *    must display the following acknowledgement:
   34  *      This product includes software developed by the University of
   35  *      California, Berkeley and its contributors.
   36  * 4. Neither the name of the University nor the names of its contributors
   37  *    may be used to endorse or promote products derived from this software
   38  *    without specific prior written permission.
   39  *
   40  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   50  * SUCH DAMAGE.
   51  *
   52  *      from:   @(#)fd.c        7.4 (Berkeley) 5/25/91
   53  * $FreeBSD$
   54  *
   55  */
   56 
   57 #include "opt_fdc.h"
   58 #include "card.h"
   59 
   60 #include <sys/param.h>
   61 #include <sys/systm.h>
   62 #include <sys/kernel.h>
   63 #include <sys/buf.h>
   64 #include <sys/bus.h>
   65 #include <sys/conf.h>
   66 #include <sys/disklabel.h>
   67 #include <sys/devicestat.h>
   68 #include <sys/fcntl.h>
   69 #include <sys/malloc.h>
   70 #include <sys/module.h>
   71 #include <sys/proc.h>
   72 #include <sys/syslog.h>
   73 
   74 #include <sys/bus.h>
   75 #include <machine/bus.h>
   76 #include <sys/rman.h>
   77 
   78 #include <machine/clock.h>
   79 #include <machine/ioctl_fd.h>
   80 #include <machine/resource.h>
   81 #include <machine/stdarg.h>
   82 
   83 #include <isa/isavar.h>
   84 #include <isa/isareg.h>
   85 #include <isa/fdreg.h>
   86 #include <isa/fdc.h>
   87 #include <isa/rtc.h>
   88 
   89 /* misuse a flag to identify format operation */
   90 #define B_FORMAT B_XXX
   91 
   92 /* configuration flags */
   93 #define FDC_PRETEND_D0  (1 << 0)        /* pretend drive 0 to be there */
   94 #define FDC_NO_FIFO     (1 << 2)        /* do not enable FIFO  */
   95 
   96 /* internally used only, not really from CMOS: */
   97 #define RTCFDT_144M_PRETENDED   0x1000
   98 
   99 /* error returns for fd_cmd() */
  100 #define FD_FAILED -1
  101 #define FD_NOT_VALID -2
  102 #define FDC_ERRMAX      100     /* do not log more */
  103 /*
  104  * Stop retrying after this many DMA overruns.  Since each retry takes
  105  * one revolution, with 300 rpm., 25 retries take approximately 10
  106  * seconds which the read attempt will block in case the DMA overrun
  107  * is persistent.
  108  */
  109 #define FDC_DMAOV_MAX   25
  110 
  111 /*
  112  * Timeout value for the PIO loops to wait until the FDC main status
  113  * register matches our expectations (request for master, direction
  114  * bit).  This is supposed to be a number of microseconds, although
  115  * timing might actually not be very accurate.
  116  *
  117  * Timeouts of 100 msec are believed to be required for some broken
  118  * (old) hardware.
  119  */
  120 #define FDSTS_TIMEOUT   100000
  121 
  122 #define NUMTYPES 17
  123 #define NUMDENS  (NUMTYPES - 7)
  124 
  125 /* These defines (-1) must match index for fd_types */
  126 #define F_TAPE_TYPE     0x020   /* bit for fd_types to indicate tape */
  127 #define NO_TYPE         0       /* must match NO_TYPE in ft.c */
  128 #define FD_1720         1
  129 #define FD_1480         2
  130 #define FD_1440         3
  131 #define FD_1200         4
  132 #define FD_820          5
  133 #define FD_800          6
  134 #define FD_720          7
  135 #define FD_360          8
  136 #define FD_640          9
  137 #define FD_1232         10
  138 
  139 #define FD_1480in5_25   11
  140 #define FD_1440in5_25   12
  141 #define FD_820in5_25    13
  142 #define FD_800in5_25    14
  143 #define FD_720in5_25    15
  144 #define FD_360in5_25    16
  145 #define FD_640in5_25    17
  146 
  147 
  148 static struct fd_type fd_types[NUMTYPES] =
  149 {
  150 { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
  151 { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
  152 { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
  153 { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /*  1.2M in HD 5.25/3.5 */
  154 { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /*  820K in HD 3.5in */
  155 { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /*  800K in HD 3.5in */
  156 {  9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /*  720K in HD 3.5in */
  157 {  9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /*  360K in DD 5.25in */
  158 {  8,2,0xFF,0x2A,80,1280,1,FDC_250KBPS,2,0x50,1 }, /*  640K in DD 5.25in */
  159 {  8,3,0xFF,0x35,77,1232,1,FDC_500KBPS,2,0x74,1 }, /* 1.23M in HD 5.25in */
  160 
  161 { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
  162 { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
  163 { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /*  820K in HD 5.25in */
  164 { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /*  800K in HD 5.25in */
  165 {  9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /*  720K in HD 5.25in */
  166 {  9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /*  360K in HD 5.25in */
  167 {  8,2,0xFF,0x2A,80,1280,1,FDC_300KBPS,2,0x50,1 }, /*  640K in HD 5.25in */
  168 };
  169 
  170 #define DRVS_PER_CTLR 2         /* 2 floppies */
  171 
  172 /***********************************************************************\
  173 * Per controller structure.                                             *
  174 \***********************************************************************/
  175 static devclass_t fdc_devclass;
  176 
  177 /***********************************************************************\
  178 * Per drive structure.                                                  *
  179 * N per controller  (DRVS_PER_CTLR)                                     *
  180 \***********************************************************************/
  181 struct fd_data {
  182         struct  fdc_data *fdc;  /* pointer to controller structure */
  183         int     fdsu;           /* this units number on this controller */
  184         int     type;           /* Drive type (FD_1440...) */
  185         struct  fd_type *ft;    /* pointer to the type descriptor */
  186         int     flags;
  187 #define FD_OPEN         0x01    /* it's open            */
  188 #define FD_ACTIVE       0x02    /* it's active          */
  189 #define FD_MOTOR        0x04    /* motor should be on   */
  190 #define FD_MOTOR_WAIT   0x08    /* motor coming up      */
  191         int     skip;
  192         int     hddrv;
  193 #define FD_NO_TRACK -2
  194         int     track;          /* where we think the head is */
  195         int     options;        /* user configurable options, see ioctl_fd.h */
  196         struct  callout_handle toffhandle;
  197         struct  callout_handle tohandle;
  198         struct  devstat device_stats;
  199         device_t dev;
  200         fdu_t   fdu;
  201 };
  202 
  203 struct fdc_ivars {
  204         int     fdunit;
  205 };
  206 static devclass_t fd_devclass;
  207 
  208 /***********************************************************************\
  209 * Throughout this file the following conventions will be used:          *
  210 * fd is a pointer to the fd_data struct for the drive in question       *
  211 * fdc is a pointer to the fdc_data struct for the controller            *
  212 * fdu is the floppy drive unit number                                   *
  213 * fdcu is the floppy controller unit number                             *
  214 * fdsu is the floppy drive unit number on that controller. (sub-unit)   *
  215 \***********************************************************************/
  216 
  217 /* internal functions */
  218 static  void fdc_intr(void *);
  219 static void set_motor(struct fdc_data *, int, int);
  220 #  define TURNON 1
  221 #  define TURNOFF 0
  222 static timeout_t fd_turnoff;
  223 static timeout_t fd_motor_on;
  224 static void fd_turnon(struct fd_data *);
  225 static void fdc_reset(fdc_p);
  226 static int fd_in(struct fdc_data *, int *);
  227 static int out_fdc(struct fdc_data *, int);
  228 static void fdstart(struct fdc_data *);
  229 static timeout_t fd_iotimeout;
  230 static timeout_t fd_pseudointr;
  231 static int fdstate(struct fdc_data *);
  232 static int retrier(struct fdc_data *);
  233 static int fdformat(dev_t, struct fd_formb *, struct proc *);
  234 
  235 static int enable_fifo(fdc_p fdc);
  236 
  237 static int fifo_threshold = 8;  /* XXX: should be accessible via sysctl */
  238 
  239 
  240 #define DEVIDLE         0
  241 #define FINDWORK        1
  242 #define DOSEEK          2
  243 #define SEEKCOMPLETE    3
  244 #define IOCOMPLETE      4
  245 #define RECALCOMPLETE   5
  246 #define STARTRECAL      6
  247 #define RESETCTLR       7
  248 #define SEEKWAIT        8
  249 #define RECALWAIT       9
  250 #define MOTORWAIT       10
  251 #define IOTIMEDOUT      11
  252 #define RESETCOMPLETE   12
  253 #define PIOREAD         13
  254 
  255 #ifdef  FDC_DEBUG
  256 static char const * const fdstates[] =
  257 {
  258 "DEVIDLE",
  259 "FINDWORK",
  260 "DOSEEK",
  261 "SEEKCOMPLETE",
  262 "IOCOMPLETE",
  263 "RECALCOMPLETE",
  264 "STARTRECAL",
  265 "RESETCTLR",
  266 "SEEKWAIT",
  267 "RECALWAIT",
  268 "MOTORWAIT",
  269 "IOTIMEDOUT",
  270 "RESETCOMPLETE",
  271 "PIOREAD",
  272 };
  273 
  274 /* CAUTION: fd_debug causes huge amounts of logging output */
  275 static int volatile fd_debug = 0;
  276 #define TRACE0(arg) if(fd_debug) printf(arg)
  277 #define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
  278 #else /* FDC_DEBUG */
  279 #define TRACE0(arg)
  280 #define TRACE1(arg1, arg2)
  281 #endif /* FDC_DEBUG */
  282 
  283 static void
  284 fdout_wr(fdc_p fdc, u_int8_t v)
  285 {
  286         bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
  287 }
  288 
  289 static u_int8_t
  290 fdsts_rd(fdc_p fdc)
  291 {
  292         return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off);
  293 }
  294 
  295 static void
  296 fddata_wr(fdc_p fdc, u_int8_t v)
  297 {
  298         bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v);
  299 }
  300 
  301 static u_int8_t
  302 fddata_rd(fdc_p fdc)
  303 {
  304         return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off);
  305 }
  306 
  307 static void
  308 fdctl_wr_isa(fdc_p fdc, u_int8_t v)
  309 {
  310         bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
  311 }
  312 
  313 #if NCARD > 0
  314 static void
  315 fdctl_wr_pcmcia(fdc_p fdc, u_int8_t v)
  316 {
  317         bus_space_write_1(fdc->portt, fdc->porth, FDCTL+fdc->port_off, v);
  318 }
  319 #endif
  320 
  321 #if 0
  322 
  323 static u_int8_t
  324 fdin_rd(fdc_p fdc)
  325 {
  326         return bus_space_read_1(fdc->portt, fdc->porth, FDIN);
  327 }
  328 
  329 #endif
  330 
  331 static  d_open_t        Fdopen; /* NOTE, not fdopen */
  332 static  d_close_t       fdclose;
  333 static  d_ioctl_t       fdioctl;
  334 static  d_strategy_t    fdstrategy;
  335 
  336 #define CDEV_MAJOR 9
  337 #define BDEV_MAJOR 2
  338 
  339 static struct cdevsw fd_cdevsw = {
  340         /* open */      Fdopen,
  341         /* close */     fdclose,
  342         /* read */      physread,
  343         /* write */     physwrite,
  344         /* ioctl */     fdioctl,
  345         /* poll */      nopoll,
  346         /* mmap */      nommap,
  347         /* strategy */  fdstrategy,
  348         /* name */      "fd",
  349         /* maj */       CDEV_MAJOR,
  350         /* dump */      nodump,
  351         /* psize */     nopsize,
  352         /* flags */     D_DISK,
  353         /* bmaj */      BDEV_MAJOR
  354 };
  355 
  356 static int
  357 fdc_err(struct fdc_data *fdc, const char *s)
  358 {
  359         fdc->fdc_errs++;
  360         if (s) {
  361                 if (fdc->fdc_errs < FDC_ERRMAX)
  362                         device_printf(fdc->fdc_dev, "%s", s);
  363                 else if (fdc->fdc_errs == FDC_ERRMAX)
  364                         device_printf(fdc->fdc_dev, "too many errors, not "
  365                                                     "logging any more\n");
  366         }
  367 
  368         return FD_FAILED;
  369 }
  370 
  371 /*
  372  * fd_cmd: Send a command to the chip.  Takes a varargs with this structure:
  373  * Unit number,
  374  * # of output bytes, output bytes as ints ...,
  375  * # of input bytes, input bytes as ints ...
  376  */
  377 static int
  378 fd_cmd(struct fdc_data *fdc, int n_out, ...)
  379 {
  380         u_char cmd;
  381         int n_in;
  382         int n;
  383         va_list ap;
  384 
  385         va_start(ap, n_out);
  386         cmd = (u_char)(va_arg(ap, int));
  387         va_end(ap);
  388         va_start(ap, n_out);
  389         for (n = 0; n < n_out; n++)
  390         {
  391                 if (out_fdc(fdc, va_arg(ap, int)) < 0)
  392                 {
  393                         char msg[50];
  394                         snprintf(msg, sizeof(msg),
  395                                 "cmd %x failed at out byte %d of %d\n",
  396                                 cmd, n + 1, n_out);
  397                         return fdc_err(fdc, msg);
  398                 }
  399         }
  400         n_in = va_arg(ap, int);
  401         for (n = 0; n < n_in; n++)
  402         {
  403                 int *ptr = va_arg(ap, int *);
  404                 if (fd_in(fdc, ptr) < 0)
  405                 {
  406                         char msg[50];
  407                         snprintf(msg, sizeof(msg),
  408                                 "cmd %02x failed at in byte %d of %d\n",
  409                                 cmd, n + 1, n_in);
  410                         return fdc_err(fdc, msg);
  411                 }
  412         }
  413 
  414         return 0;
  415 }
  416 
  417 static int 
  418 enable_fifo(fdc_p fdc)
  419 {
  420         int i, j;
  421 
  422         if ((fdc->flags & FDC_HAS_FIFO) == 0) {
  423                 
  424                 /*
  425                  * XXX: 
  426                  * Cannot use fd_cmd the normal way here, since
  427                  * this might be an invalid command. Thus we send the
  428                  * first byte, and check for an early turn of data directon.
  429                  */
  430                 
  431                 if (out_fdc(fdc, I8207X_CONFIGURE) < 0)
  432                         return fdc_err(fdc, "Enable FIFO failed\n");
  433                 
  434                 /* If command is invalid, return */
  435                 j = FDSTS_TIMEOUT;
  436                 while ((i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM))
  437                        != NE7_RQM && j-- > 0) {
  438                         if (i == (NE7_DIO | NE7_RQM)) {
  439                                 fdc_reset(fdc);
  440                                 return FD_FAILED;
  441                         }
  442                         DELAY(1);
  443                 }
  444                 if (j<0 || 
  445                     fd_cmd(fdc, 3,
  446                            0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
  447                         fdc_reset(fdc);
  448                         return fdc_err(fdc, "Enable FIFO failed\n");
  449                 }
  450                 fdc->flags |= FDC_HAS_FIFO;
  451                 return 0;
  452         }
  453         if (fd_cmd(fdc, 4,
  454                    I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
  455                 return fdc_err(fdc, "Re-enable FIFO failed\n");
  456         return 0;
  457 }
  458 
  459 static int
  460 fd_sense_drive_status(fdc_p fdc, int *st3p)
  461 {
  462         int st3;
  463 
  464         if (fd_cmd(fdc, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
  465         {
  466                 return fdc_err(fdc, "Sense Drive Status failed\n");
  467         }
  468         if (st3p)
  469                 *st3p = st3;
  470 
  471         return 0;
  472 }
  473 
  474 static int
  475 fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
  476 {
  477         int cyl, st0, ret;
  478 
  479         ret = fd_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0);
  480         if (ret) {
  481                 (void)fdc_err(fdc,
  482                               "sense intr err reading stat reg 0\n");
  483                 return ret;
  484         }
  485 
  486         if (st0p)
  487                 *st0p = st0;
  488 
  489         if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) {
  490                 /*
  491                  * There doesn't seem to have been an interrupt.
  492                  */
  493                 return FD_NOT_VALID;
  494         }
  495 
  496         if (fd_in(fdc, &cyl) < 0) {
  497                 return fdc_err(fdc, "can't get cyl num\n");
  498         }
  499 
  500         if (cylp)
  501                 *cylp = cyl;
  502 
  503         return 0;
  504 }
  505 
  506 
  507 static int
  508 fd_read_status(fdc_p fdc, int fdsu)
  509 {
  510         int i, ret;
  511 
  512         for (i = 0; i < 7; i++) {
  513                 /*
  514                  * XXX types are poorly chosen.  Only bytes can by read
  515                  * from the hardware, but fdc->status[] wants u_ints and
  516                  * fd_in() gives ints.
  517                  */
  518                 int status;
  519 
  520                 ret = fd_in(fdc, &status);
  521                 fdc->status[i] = status;
  522                 if (ret != 0)
  523                         break;
  524         }
  525 
  526         if (ret == 0)
  527                 fdc->flags |= FDC_STAT_VALID;
  528         else
  529                 fdc->flags &= ~FDC_STAT_VALID;
  530 
  531         return ret;
  532 }
  533 
  534 /****************************************************************************/
  535 /*                      autoconfiguration stuff                             */
  536 /****************************************************************************/
  537 
  538 static int
  539 fdc_alloc_resources(struct fdc_data *fdc)
  540 {
  541         device_t dev;
  542         int ispnp, ispcmcia;
  543 
  544         dev = fdc->fdc_dev;
  545         ispnp = (fdc->flags & FDC_ISPNP) != 0;
  546         ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
  547         fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
  548         fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
  549 
  550         /*
  551          * On standard ISA, we don't just use an 8 port range
  552          * (e.g. 0x3f0-0x3f7) since that covers an IDE control
  553          * register at 0x3f6.
  554          *
  555          * Isn't PC hardware wonderful.
  556          *
  557          * The Y-E Data PCMCIA FDC doesn't have this problem, it
  558          * uses the register with offset 6 for pseudo-DMA, and the
  559          * one with offset 7 as control register.
  560          */
  561         fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
  562                                              &fdc->rid_ioport, 0ul, ~0ul, 
  563                                              ispcmcia ? 8 : (ispnp ? 1 : 6),
  564                                              RF_ACTIVE);
  565         if (fdc->res_ioport == 0) {
  566                 device_printf(dev, "cannot reserve I/O port range\n");
  567                 return ENXIO;
  568         }
  569         fdc->portt = rman_get_bustag(fdc->res_ioport);
  570         fdc->porth = rman_get_bushandle(fdc->res_ioport);
  571 
  572         if (!ispcmcia) {
  573                 /*
  574                  * Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
  575                  * and some at 0x3f0-0x3f5,0x3f7. We detect the former
  576                  * by checking the size and adjust the port address
  577                  * accordingly.
  578                  */
  579                 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
  580                         fdc->port_off = -2;
  581 
  582                 /*
  583                  * Register the control port range as rid 1 if it
  584                  * isn't there already. Most PnP BIOSen will have
  585                  * already done this but non-PnP configurations don't.
  586                  *
  587                  * And some (!!) report 0x3f2-0x3f5 and completely
  588                  * leave out the control register!  It seems that some
  589                  * non-antique controller chips have a different
  590                  * method of programming the transfer speed which
  591                  * doesn't require the control register, but it's
  592                  * mighty bogus as the chip still responds to the
  593                  * address for the control register.
  594                  */
  595                 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
  596                         u_long ctlstart;
  597 
  598                         /* Find the control port, usually 0x3f7 */
  599                         ctlstart = rman_get_start(fdc->res_ioport) +
  600                                 fdc->port_off + 7;
  601 
  602                         bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
  603                 }
  604 
  605                 /*
  606                  * Now (finally!) allocate the control port.
  607                  */
  608                 fdc->rid_ctl = 1;
  609                 fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT,
  610                                                   &fdc->rid_ctl,
  611                                                   0ul, ~0ul, 1, RF_ACTIVE);
  612                 if (fdc->res_ctl == 0) {
  613                         device_printf(dev,
  614                                       "cannot reserve control I/O port range\n");
  615                         return ENXIO;
  616                 }
  617                 fdc->ctlt = rman_get_bustag(fdc->res_ctl);
  618                 fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
  619         }
  620 
  621         fdc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
  622                                           &fdc->rid_irq, 0ul, ~0ul, 1, 
  623                                           RF_ACTIVE);
  624         if (fdc->res_irq == 0) {
  625                 device_printf(dev, "cannot reserve interrupt line\n");
  626                 return ENXIO;
  627         }
  628 
  629         if ((fdc->flags & FDC_NODMA) == 0) {
  630                 fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
  631                                                   &fdc->rid_drq, 0ul, ~0ul, 1, 
  632                                                   RF_ACTIVE);
  633                 if (fdc->res_drq == 0) {
  634                         device_printf(dev, "cannot reserve DMA request line\n");
  635                         return ENXIO;
  636                 }
  637                 fdc->dmachan = fdc->res_drq->r_start;
  638         }
  639 
  640         return 0;
  641 }
  642 
  643 static void
  644 fdc_release_resources(struct fdc_data *fdc)
  645 {
  646         device_t dev;
  647 
  648         dev = fdc->fdc_dev;
  649         if (fdc->res_irq != 0) {
  650                 bus_deactivate_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
  651                                         fdc->res_irq);
  652                 bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
  653                                      fdc->res_irq);
  654         }
  655         if (fdc->res_ctl != 0) {
  656                 bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
  657                                         fdc->res_ctl);
  658                 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
  659                                      fdc->res_ctl);
  660         }
  661         if (fdc->res_ioport != 0) {
  662                 bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
  663                                         fdc->res_ioport);
  664                 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
  665                                      fdc->res_ioport);
  666         }
  667         if (fdc->res_drq != 0) {
  668                 bus_deactivate_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
  669                                         fdc->res_drq);
  670                 bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
  671                                      fdc->res_drq);
  672         }
  673 }
  674 
  675 /****************************************************************************/
  676 /*                      autoconfiguration stuff                             */
  677 /****************************************************************************/
  678 
  679 static struct isa_pnp_id fdc_ids[] = {
  680         {0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
  681         {0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */
  682         {0}
  683 };
  684 
  685 static int
  686 fdc_read_ivar(device_t dev, device_t child, int which, u_long *result)
  687 {
  688         struct fdc_ivars *ivars = device_get_ivars(child);
  689 
  690         switch (which) {
  691         case FDC_IVAR_FDUNIT:
  692                 *result = ivars->fdunit;
  693                 break;
  694         default:
  695                 return ENOENT;
  696         }
  697         return 0;
  698 }
  699 
  700 /*
  701  * fdc controller section.
  702  */
  703 static int
  704 fdc_probe(device_t dev)
  705 {
  706         int     error, ic_type;
  707         struct  fdc_data *fdc;
  708 
  709         fdc = device_get_softc(dev);
  710         bzero(fdc, sizeof *fdc);
  711         fdc->fdc_dev = dev;
  712         fdc->fdctl_wr = fdctl_wr_isa;
  713 
  714         /* Check pnp ids */
  715         error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
  716         if (error == ENXIO)
  717                 return ENXIO;
  718         if (error == 0)
  719                 fdc->flags |= FDC_ISPNP;
  720 
  721         /* Attempt to allocate our resources for the duration of the probe */
  722         error = fdc_alloc_resources(fdc);
  723         if (error)
  724                 goto out;
  725 
  726         /* First - lets reset the floppy controller */
  727         fdout_wr(fdc, 0);
  728         DELAY(100);
  729         fdout_wr(fdc, FDO_FRST);
  730 
  731         /* see if it can handle a command */
  732         if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), 
  733                    NE7_SPEC_2(2, 0), 0)) {
  734                 error = ENXIO;
  735                 goto out;
  736         }
  737 
  738         if (fd_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
  739                 ic_type = (u_char)ic_type;
  740                 switch (ic_type) {
  741                 case 0x80:
  742                         device_set_desc(dev, "NEC 765 or clone");
  743                         fdc->fdct = FDC_NE765;
  744                         break;
  745                 case 0x81:
  746                         device_set_desc(dev, "Intel 82077 or clone");
  747                         fdc->fdct = FDC_I82077;
  748                         break;
  749                 case 0x90:
  750                         device_set_desc(dev, "NEC 72065B or clone");
  751                         fdc->fdct = FDC_NE72065;
  752                         break;
  753                 default:
  754                         device_set_desc(dev, "generic floppy controller");
  755                         fdc->fdct = FDC_UNKNOWN;
  756                         break;
  757                 }
  758         }
  759 
  760 out:
  761         fdc_release_resources(fdc);
  762         return (error);
  763 }
  764 
  765 #if NCARD > 0
  766 
  767 static int
  768 fdc_pccard_probe(device_t dev)
  769 {
  770         int     error;
  771         struct  fdc_data *fdc;
  772 
  773         fdc = device_get_softc(dev);
  774         bzero(fdc, sizeof *fdc);
  775         fdc->fdc_dev = dev;
  776         fdc->fdctl_wr = fdctl_wr_pcmcia;
  777 
  778         fdc->flags |= FDC_ISPCMCIA | FDC_NODMA;
  779 
  780         /* Attempt to allocate our resources for the duration of the probe */
  781         error = fdc_alloc_resources(fdc);
  782         if (error)
  783                 goto out;
  784 
  785         /* First - lets reset the floppy controller */
  786         fdout_wr(fdc, 0);
  787         DELAY(100);
  788         fdout_wr(fdc, FDO_FRST);
  789 
  790         /* see if it can handle a command */
  791         if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), 
  792                    NE7_SPEC_2(2, 0), 0)) {
  793                 error = ENXIO;
  794                 goto out;
  795         }
  796 
  797         device_set_desc(dev, "Y-E Data PCMCIA floppy");
  798         fdc->fdct = FDC_NE765;
  799 
  800 out:
  801         fdc_release_resources(fdc);
  802         return (error);
  803 }
  804 
  805 static int
  806 fdc_pccard_detach(device_t dev)
  807 {
  808         struct  fdc_data *fdc;
  809         int     error;
  810 
  811         fdc = device_get_softc(dev);
  812 
  813         /* have our children detached first */
  814         if ((error = bus_generic_detach(dev)))
  815                 return (error);
  816 
  817         if ((fdc->flags & FDC_ATTACHED) == 0) {
  818                 device_printf(dev, "already unloaded\n");
  819                 return (0);
  820         }
  821         fdc->flags &= ~FDC_ATTACHED;
  822 
  823         BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq,
  824                           fdc->fdc_intr);
  825         fdc_release_resources(fdc);
  826         device_printf(dev, "unload\n");
  827         return (0);
  828 }
  829 
  830 #endif /* NCARD > 0 */
  831 
  832 /*
  833  * Add a child device to the fdc controller.  It will then be probed etc.
  834  */
  835 static void
  836 fdc_add_child(device_t dev, const char *name, int unit)
  837 {
  838         int     disabled;
  839         struct fdc_ivars *ivar;
  840         device_t child;
  841 
  842         ivar = malloc(sizeof *ivar, M_DEVBUF /* XXX */, M_NOWAIT);
  843         if (ivar == NULL)
  844                 return;
  845         bzero(ivar, sizeof *ivar);
  846         if (resource_int_value(name, unit, "drive", &ivar->fdunit) != 0)
  847                 ivar->fdunit = 0;
  848         child = device_add_child(dev, name, unit);
  849         if (child == NULL)
  850                 return;
  851         device_set_ivars(child, ivar);
  852         if (resource_int_value(name, unit, "disabled", &disabled) == 0
  853             && disabled != 0)
  854                 device_disable(child);
  855 }
  856 
  857 static int
  858 fdc_attach(device_t dev)
  859 {
  860         struct  fdc_data *fdc;
  861         int     i, error;
  862 
  863         fdc = device_get_softc(dev);
  864         error = fdc_alloc_resources(fdc);
  865         if (error) {
  866                 device_printf(dev, "cannot re-aquire resources\n");
  867                 return error;
  868         }
  869         error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
  870                                INTR_TYPE_BIO, fdc_intr, fdc, &fdc->fdc_intr);
  871         if (error) {
  872                 device_printf(dev, "cannot setup interrupt\n");
  873                 return error;
  874         }
  875         fdc->fdcu = device_get_unit(dev);
  876         fdc->flags |= FDC_ATTACHED;
  877 
  878         if ((fdc->flags & FDC_NODMA) == 0) {
  879                 /* Acquire the DMA channel forever, The driver will do the rest */
  880                                 /* XXX should integrate with rman */
  881                 isa_dma_acquire(fdc->dmachan);
  882                 isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
  883         }
  884         fdc->state = DEVIDLE;
  885 
  886         /* reset controller, turn motor off, clear fdout mirror reg */
  887         fdout_wr(fdc, ((fdc->fdout = 0)));
  888         bufq_init(&fdc->head);
  889 
  890         /*
  891          * Probe and attach any children.  We should probably detect
  892          * devices from the BIOS unless overridden.
  893          */
  894         for (i = resource_query_string(-1, "at", device_get_nameunit(dev));
  895              i != -1;
  896              i = resource_query_string(i, "at", device_get_nameunit(dev)))
  897                 fdc_add_child(dev, resource_query_name(i),
  898                                resource_query_unit(i));
  899 
  900         return (bus_generic_attach(dev));
  901 }
  902 
  903 static int
  904 fdc_print_child(device_t me, device_t child)
  905 {
  906         int retval = 0;
  907 
  908         retval += bus_print_child_header(me, child);
  909         retval += printf(" on %s drive %d\n", device_get_nameunit(me),
  910                fdc_get_fdunit(child));
  911         
  912         return (retval);
  913 }
  914 
  915 static device_method_t fdc_methods[] = {
  916         /* Device interface */
  917         DEVMETHOD(device_probe,         fdc_probe),
  918         DEVMETHOD(device_attach,        fdc_attach),
  919         DEVMETHOD(device_detach,        bus_generic_detach),
  920         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  921         DEVMETHOD(device_suspend,       bus_generic_suspend),
  922         DEVMETHOD(device_resume,        bus_generic_resume),
  923 
  924         /* Bus interface */
  925         DEVMETHOD(bus_print_child,      fdc_print_child),
  926         DEVMETHOD(bus_read_ivar,        fdc_read_ivar),
  927         /* Our children never use any other bus interface methods. */
  928 
  929         { 0, 0 }
  930 };
  931 
  932 static driver_t fdc_driver = {
  933         "fdc",
  934         fdc_methods,
  935         sizeof(struct fdc_data)
  936 };
  937 
  938 DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);
  939 
  940 #if NCARD > 0
  941 
  942 static device_method_t fdc_pccard_methods[] = {
  943         /* Device interface */
  944         DEVMETHOD(device_probe,         fdc_pccard_probe),
  945         DEVMETHOD(device_attach,        fdc_attach),
  946         DEVMETHOD(device_detach,        fdc_pccard_detach),
  947         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  948         DEVMETHOD(device_suspend,       bus_generic_suspend),
  949         DEVMETHOD(device_resume,        bus_generic_resume),
  950 
  951         /* Bus interface */
  952         DEVMETHOD(bus_print_child,      fdc_print_child),
  953         DEVMETHOD(bus_read_ivar,        fdc_read_ivar),
  954         /* Our children never use any other bus interface methods. */
  955 
  956         { 0, 0 }
  957 };
  958 
  959 static driver_t fdc_pccard_driver = {
  960         "fdc",
  961         fdc_pccard_methods,
  962         sizeof(struct fdc_data)
  963 };
  964 
  965 DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
  966 
  967 #endif /* NCARD > 0 */
  968 
  969 /******************************************************************/
  970 /*
  971  * devices attached to the controller section.  
  972  */
  973 static int
  974 fd_probe(device_t dev)
  975 {
  976         int     i;
  977         u_int   fdt, st0, st3;
  978         struct  fd_data *fd;
  979         struct  fdc_data *fdc;
  980         fdsu_t  fdsu;
  981         static int fd_fifo = 0;
  982 
  983         fdsu = *(int *)device_get_ivars(dev); /* xxx cheat a bit... */
  984         fd = device_get_softc(dev);
  985         fdc = device_get_softc(device_get_parent(dev));
  986 
  987         bzero(fd, sizeof *fd);
  988         fd->dev = dev;
  989         fd->fdc = fdc;
  990         fd->fdsu = fdsu;
  991         fd->fdu = device_get_unit(dev);
  992 
  993 #ifdef __i386__
  994         /* look up what bios thinks we have */
  995         switch (fd->fdu) {
  996         case 0:
  997                 if ((fdc->flags & FDC_ISPCMCIA))
  998                         fdt = RTCFDT_144M;
  999                 else if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
 1000                         fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
 1001                 else
 1002                         fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
 1003                 break;
 1004         case 1:
 1005                 fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
 1006                 break;
 1007         default:
 1008                 fdt = RTCFDT_NONE;
 1009                 break;
 1010         }
 1011 #else
 1012         fdt = RTCFDT_144M;      /* XXX probably */
 1013 #endif
 1014 
 1015         /* is there a unit? */
 1016         if (fdt == RTCFDT_NONE)
 1017                 return (ENXIO);
 1018 
 1019         /* select it */
 1020         set_motor(fdc, fdsu, TURNON);
 1021         DELAY(1000000); /* 1 sec */
 1022 
 1023         /* XXX This doesn't work before the first set_motor() */
 1024         if (fd_fifo == 0 && fdc->fdct != FDC_NE765 && fdc->fdct != FDC_UNKNOWN
 1025             && (device_get_flags(fdc->fdc_dev) & FDC_NO_FIFO) == 0
 1026             && enable_fifo(fdc) == 0) {
 1027                 device_printf(device_get_parent(dev),
 1028                     "FIFO enabled, %d bytes threshold\n", fifo_threshold);
 1029         }
 1030         fd_fifo = 1;
 1031 
 1032         if ((fd_cmd(fdc, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0)
 1033             && (st3 & NE7_ST3_T0)) {
 1034                 /* if at track 0, first seek inwards */
 1035                 /* seek some steps: */
 1036                 fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0);
 1037                 DELAY(300000); /* ...wait a moment... */
 1038                 fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
 1039         }
 1040 
 1041         /* If we're at track 0 first seek inwards. */
 1042         if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
 1043                 /* Seek some steps... */
 1044                 if (fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
 1045                         /* ...wait a moment... */
 1046                         DELAY(300000);
 1047                         /* make ctrlr happy: */
 1048                         fd_sense_int(fdc, 0, 0);
 1049                 }
 1050         }
 1051 
 1052         for (i = 0; i < 2; i++) {
 1053                 /*
 1054                  * we must recalibrate twice, just in case the
 1055                  * heads have been beyond cylinder 76, since most
 1056                  * FDCs still barf when attempting to recalibrate
 1057                  * more than 77 steps
 1058                  */
 1059                 /* go back to 0: */
 1060                 if (fd_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
 1061                         /* a second being enough for full stroke seek*/
 1062                         DELAY(i == 0 ? 1000000 : 300000);
 1063 
 1064                         /* anything responding? */
 1065                         if (fd_sense_int(fdc, &st0, 0) == 0 &&
 1066                             (st0 & NE7_ST0_EC) == 0)
 1067                                 break; /* already probed succesfully */
 1068                 }
 1069         }
 1070 
 1071         set_motor(fdc, fdsu, TURNOFF);
 1072 
 1073         if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
 1074                 return (ENXIO);
 1075 
 1076         fd->track = FD_NO_TRACK;
 1077         fd->fdc = fdc;
 1078         fd->fdsu = fdsu;
 1079         fd->options = 0;
 1080         callout_handle_init(&fd->toffhandle);
 1081         callout_handle_init(&fd->tohandle);
 1082 
 1083         switch (fdt) {
 1084         case RTCFDT_12M:
 1085                 device_set_desc(dev, "1200-KB 5.25\" drive");
 1086                 fd->type = FD_1200;
 1087                 break;
 1088         case RTCFDT_144M | RTCFDT_144M_PRETENDED:
 1089                 device_set_desc(dev, "config-pretended 1440-MB 3.5\" drive");
 1090                 fdt = RTCFDT_144M;
 1091                 fd->type = FD_1440;
 1092         case RTCFDT_144M:
 1093                 device_set_desc(dev, "1440-KB 3.5\" drive");
 1094                 fd->type = FD_1440;
 1095                 break;
 1096         case RTCFDT_288M:
 1097         case RTCFDT_288M_1:
 1098                 device_set_desc(dev, "2880-KB 3.5\" drive (in 1440-KB mode)");
 1099                 fd->type = FD_1440;
 1100                 break;
 1101         case RTCFDT_360K:
 1102                 device_set_desc(dev, "360-KB 5.25\" drive");
 1103                 fd->type = FD_360;
 1104                 break;
 1105         case RTCFDT_720K:
 1106                 printf("720-KB 3.5\" drive");
 1107                 fd->type = FD_720;
 1108                 break;
 1109         default:
 1110                 return (ENXIO);
 1111         }
 1112         return (0);
 1113 }
 1114 
 1115 static int
 1116 fd_attach(device_t dev)
 1117 {
 1118         struct  fd_data *fd;
 1119 #if 0
 1120         int     i;
 1121         int     mynor;
 1122         int     typemynor;
 1123         int     typesize;
 1124 #endif
 1125         static int cdevsw_add_done = 0;
 1126 
 1127         fd = device_get_softc(dev);
 1128 
 1129         if (!cdevsw_add_done) {
 1130                 cdevsw_add(&fd_cdevsw); /* XXX */
 1131                 cdevsw_add_done++;
 1132         }
 1133         make_dev(&fd_cdevsw, (fd->fdu << 6),
 1134                 UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
 1135 
 1136 #if 0
 1137         /* Other make_dev() go here. */
 1138 #endif
 1139 
 1140         /*
 1141          * Export the drive to the devstat interface.
 1142          */
 1143         devstat_add_entry(&fd->device_stats, device_get_name(dev), 
 1144                           device_get_unit(dev), 512, DEVSTAT_NO_ORDERED_TAGS,
 1145                           DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
 1146                           DEVSTAT_PRIORITY_FD);
 1147         return (0);
 1148 }
 1149 
 1150 static int
 1151 fd_detach(device_t dev)
 1152 {
 1153         struct  fd_data *fd;
 1154 
 1155         fd = device_get_softc(dev);
 1156         untimeout(fd_turnoff, fd, fd->toffhandle);
 1157 
 1158         return (0);
 1159 }
 1160 
 1161 static device_method_t fd_methods[] = {
 1162         /* Device interface */
 1163         DEVMETHOD(device_probe,         fd_probe),
 1164         DEVMETHOD(device_attach,        fd_attach),
 1165         DEVMETHOD(device_detach,        fd_detach),
 1166         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1167         DEVMETHOD(device_suspend,       bus_generic_suspend), /* XXX */
 1168         DEVMETHOD(device_resume,        bus_generic_resume), /* XXX */
 1169 
 1170         { 0, 0 }
 1171 };
 1172 
 1173 static driver_t fd_driver = {
 1174         "fd",
 1175         fd_methods,
 1176         sizeof(struct fd_data)
 1177 };
 1178 
 1179 DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
 1180 
 1181 /****************************************************************************/
 1182 /*                            motor control stuff                           */
 1183 /*              remember to not deselect the drive we're working on         */
 1184 /****************************************************************************/
 1185 static void
 1186 set_motor(struct fdc_data *fdc, int fdsu, int turnon)
 1187 {
 1188         int fdout = fdc->fdout;
 1189         int needspecify = 0;
 1190 
 1191         if(turnon) {
 1192                 fdout &= ~FDO_FDSEL;
 1193                 fdout |= (FDO_MOEN0 << fdsu) + fdsu;
 1194         } else
 1195                 fdout &= ~(FDO_MOEN0 << fdsu);
 1196 
 1197         if(!turnon
 1198            && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
 1199                 /* gonna turn off the last drive, put FDC to bed */
 1200                 fdout &= ~ (FDO_FRST|FDO_FDMAEN);
 1201         else {
 1202                 /* make sure controller is selected and specified */
 1203                 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
 1204                         needspecify = 1;
 1205                 fdout |= (FDO_FRST|FDO_FDMAEN);
 1206         }
 1207 
 1208         fdout_wr(fdc, fdout);
 1209         fdc->fdout = fdout;
 1210         TRACE1("[0x%x->FDOUT]", fdout);
 1211 
 1212         if (needspecify) {
 1213                 /*
 1214                  * XXX
 1215                  * special case: since we have just woken up the FDC
 1216                  * from its sleep, we silently assume the command will
 1217                  * be accepted, and do not test for a timeout
 1218                  */
 1219                 (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
 1220                              NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
 1221                              0);
 1222                 if (fdc->flags & FDC_HAS_FIFO)
 1223                         (void) enable_fifo(fdc);
 1224         }
 1225 }
 1226 
 1227 static void
 1228 fd_turnoff(void *xfd)
 1229 {
 1230         int     s;
 1231         fd_p fd = xfd;
 1232 
 1233         TRACE1("[fd%d: turnoff]", fd->fdu);
 1234 
 1235         s = splbio();
 1236         /*
 1237          * Don't turn off the motor yet if the drive is active.
 1238          *
 1239          * If we got here, this could only mean we missed an interrupt.
 1240          * This can e. g. happen on the Y-E Date PCMCIA floppy controller
 1241          * after a controller reset.  Just schedule a pseudo-interrupt
 1242          * so the state machine gets re-entered.
 1243          */
 1244         if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
 1245                 fdc_intr(fd->fdc);
 1246                 splx(s);
 1247                 return;
 1248         }
 1249 
 1250         fd->flags &= ~FD_MOTOR;
 1251         set_motor(fd->fdc, fd->fdsu, TURNOFF);
 1252         splx(s);
 1253 }
 1254 
 1255 static void
 1256 fd_motor_on(void *xfd)
 1257 {
 1258         int     s;
 1259         fd_p fd = xfd;
 1260 
 1261         s = splbio();
 1262         fd->flags &= ~FD_MOTOR_WAIT;
 1263         if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
 1264         {
 1265                 fdc_intr(fd->fdc);
 1266         }
 1267         splx(s);
 1268 }
 1269 
 1270 static void
 1271 fd_turnon(fd_p fd)
 1272 {
 1273         if(!(fd->flags & FD_MOTOR))
 1274         {
 1275                 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
 1276                 set_motor(fd->fdc, fd->fdsu, TURNON);
 1277                 timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */
 1278         }
 1279 }
 1280 
 1281 static void
 1282 fdc_reset(fdc_p fdc)
 1283 {
 1284         /* Try a reset, keep motor on */
 1285         fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
 1286         TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
 1287         DELAY(100);
 1288         /* enable FDC, but defer interrupts a moment */
 1289         fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
 1290         TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
 1291         DELAY(100);
 1292         fdout_wr(fdc, fdc->fdout);
 1293         TRACE1("[0x%x->FDOUT]", fdc->fdout);
 1294 
 1295         /* XXX after a reset, silently believe the FDC will accept commands */
 1296         (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
 1297                      NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
 1298                      0);
 1299         if (fdc->flags & FDC_HAS_FIFO)
 1300                 (void) enable_fifo(fdc);
 1301 }
 1302 
 1303 /****************************************************************************/
 1304 /*                             fdc in/out                                   */
 1305 /****************************************************************************/
 1306 /*
 1307  * FDC IO functions, take care of the main status register, timeout
 1308  * in case the desired status bits are never set.
 1309  *
 1310  * These PIO loops initially start out with short delays between
 1311  * each iteration in the expectation that the required condition
 1312  * is usually met quickly, so it can be handled immediately.  After
 1313  * about 1 ms, stepping is increased to achieve a better timing
 1314  * accuracy in the calls to DELAY().
 1315  */
 1316 static int
 1317 fd_in(struct fdc_data *fdc, int *ptr)
 1318 {
 1319         int i, j, step;
 1320 
 1321         for (j = 0, step = 1;
 1322             (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM) &&
 1323             j < FDSTS_TIMEOUT;
 1324             j += step) {
 1325                 if (i == NE7_RQM)
 1326                         return (fdc_err(fdc, "ready for output in input\n"));
 1327                 if (j == 1000)
 1328                         step = 1000;
 1329                 DELAY(step);
 1330         }
 1331         if (j >= FDSTS_TIMEOUT)
 1332                 return (fdc_err(fdc, bootverbose? "input ready timeout\n": 0));
 1333 #ifdef  FDC_DEBUG
 1334         i = fddata_rd(fdc);
 1335         TRACE1("[FDDATA->0x%x]", (unsigned char)i);
 1336         *ptr = i;
 1337         return (0);
 1338 #else   /* !FDC_DEBUG */
 1339         i = fddata_rd(fdc);
 1340         if (ptr)
 1341                 *ptr = i;
 1342         return (0);
 1343 #endif  /* FDC_DEBUG */
 1344 }
 1345 
 1346 static int
 1347 out_fdc(struct fdc_data *fdc, int x)
 1348 {
 1349         int i, j, step;
 1350 
 1351         for (j = 0, step = 1;
 1352             (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != NE7_RQM &&
 1353             j < FDSTS_TIMEOUT;
 1354             j += step) {
 1355                 if (i == (NE7_DIO|NE7_RQM))
 1356                         return (fdc_err(fdc, "ready for input in output\n"));
 1357                 if (j == 1000)
 1358                         step = 1000;
 1359                 DELAY(step);
 1360         }
 1361         if (j >= FDSTS_TIMEOUT)
 1362                 return (fdc_err(fdc, bootverbose? "output ready timeout\n": 0));
 1363 
 1364         /* Send the command and return */
 1365         fddata_wr(fdc, x);
 1366         TRACE1("[0x%x->FDDATA]", x);
 1367         return (0);
 1368 }
 1369 
 1370 /****************************************************************************/
 1371 /*                           fdopen/fdclose                                 */
 1372 /****************************************************************************/
 1373 int
 1374 Fdopen(dev_t dev, int flags, int mode, struct proc *p)
 1375 {
 1376         fdu_t fdu = FDUNIT(minor(dev));
 1377         int type = FDTYPE(minor(dev));
 1378         fd_p    fd;
 1379         fdc_p   fdc;
 1380 
 1381         /* check bounds */
 1382         if ((fd = devclass_get_softc(fd_devclass, fdu)) == 0)
 1383                 return (ENXIO);
 1384         fdc = fd->fdc;
 1385         if ((fdc == NULL) || (fd->type == NO_TYPE))
 1386                 return (ENXIO);
 1387         if (type > NUMDENS)
 1388                 return (ENXIO);
 1389         if (type == 0)
 1390                 type = fd->type;
 1391         else {
 1392                 /*
 1393                  * For each type of basic drive, make sure we are trying
 1394                  * to open a type it can do,
 1395                  */
 1396                 if (type != fd->type) {
 1397                         switch (fd->type) {
 1398                         case FD_360:
 1399                                 return (ENXIO);
 1400                         case FD_720:
 1401                                 if (   type != FD_820
 1402                                     && type != FD_800
 1403                                     && type != FD_640
 1404                                    )
 1405                                         return (ENXIO);
 1406                                 break;
 1407                         case FD_1200:
 1408                                 switch (type) {
 1409                                 case FD_1480:
 1410                                         type = FD_1480in5_25;
 1411                                         break;
 1412                                 case FD_1440:
 1413                                         type = FD_1440in5_25;
 1414                                         break;
 1415                                 case FD_1232:
 1416                                         break;
 1417                                 case FD_820:
 1418                                         type = FD_820in5_25;
 1419                                         break;
 1420                                 case FD_800:
 1421                                         type = FD_800in5_25;
 1422                                         break;
 1423                                 case FD_720:
 1424                                         type = FD_720in5_25;
 1425                                         break;
 1426                                 case FD_640:
 1427                                         type = FD_640in5_25;
 1428                                         break;
 1429                                 case FD_360:
 1430                                         type = FD_360in5_25;
 1431                                         break;
 1432                                 default:
 1433                                         return(ENXIO);
 1434                                 }
 1435                                 break;
 1436                         case FD_1440:
 1437                                 if (   type != FD_1720
 1438                                     && type != FD_1480
 1439                                     && type != FD_1200
 1440                                     && type != FD_820
 1441                                     && type != FD_800
 1442                                     && type != FD_720
 1443                                     && type != FD_640
 1444                                     )
 1445                                         return(ENXIO);
 1446                                 break;
 1447                         }
 1448                 }
 1449         }
 1450         fd->ft = fd_types + type - 1;
 1451         fd->flags |= FD_OPEN;
 1452         /*
 1453          * Clearing the DMA overrun counter at open time is a bit messy.
 1454          * Since we're only managing one counter per controller, opening
 1455          * the second drive could mess it up.  Anyway, if the DMA overrun
 1456          * condition is really persistent, it will eventually time out
 1457          * still.  OTOH, clearing it here will ensure we'll at least start
 1458          * trying again after a previous (maybe even long ago) failure.
 1459          * Also, this is merely a stop-gap measure only that should not
 1460          * happen during normal operation, so we can tolerate it to be a
 1461          * bit sloppy about this.
 1462          */
 1463         fdc->dma_overruns = 0;
 1464 
 1465         return 0;
 1466 }
 1467 
 1468 int
 1469 fdclose(dev_t dev, int flags, int mode, struct proc *p)
 1470 {
 1471         fdu_t fdu = FDUNIT(minor(dev));
 1472         struct fd_data *fd;
 1473 
 1474         fd = devclass_get_softc(fd_devclass, fdu);
 1475         fd->flags &= ~FD_OPEN;
 1476         fd->options &= ~(FDOPT_NORETRY | FDOPT_NOERRLOG);
 1477 
 1478         return (0);
 1479 }
 1480 
 1481 /****************************************************************************/
 1482 /*                               fdstrategy                                 */
 1483 /****************************************************************************/
 1484 void
 1485 fdstrategy(struct buf *bp)
 1486 {
 1487         unsigned nblocks, blknum, cando;
 1488         int     s;
 1489         fdu_t   fdu;
 1490         fdc_p   fdc;
 1491         fd_p    fd;
 1492         size_t  fdblk;
 1493 
 1494         fdu = FDUNIT(minor(bp->b_dev));
 1495         fd = devclass_get_softc(fd_devclass, fdu);
 1496         if (fd == 0)
 1497                 panic("fdstrategy: buf for nonexistent device (%#lx, %#lx)",
 1498                       (u_long)major(bp->b_dev), (u_long)minor(bp->b_dev));
 1499         fdc = fd->fdc;
 1500         if (fd->type == NO_TYPE) {
 1501                 bp->b_error = ENXIO;
 1502                 bp->b_flags |= B_ERROR;
 1503                 goto bad;
 1504         };
 1505 
 1506         fdblk = 128 << (fd->ft->secsize);
 1507         if (!(bp->b_flags & B_FORMAT)) {
 1508                 if (bp->b_blkno < 0) {
 1509                         printf(
 1510                 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
 1511                                fdu, (u_long)bp->b_blkno, bp->b_bcount);
 1512                         bp->b_error = EINVAL;
 1513                         bp->b_flags |= B_ERROR;
 1514                         goto bad;
 1515                 }
 1516                 if ((bp->b_bcount % fdblk) != 0) {
 1517                         bp->b_error = EINVAL;
 1518                         bp->b_flags |= B_ERROR;
 1519                         goto bad;
 1520                 }
 1521         }
 1522 
 1523         /*
 1524          * Set up block calculations.
 1525          */
 1526         if (bp->b_blkno > 20000000) {
 1527                 /*
 1528                  * Reject unreasonably high block number, prevent the
 1529                  * multiplication below from overflowing.
 1530                  */
 1531                 bp->b_error = EINVAL;
 1532                 bp->b_flags |= B_ERROR;
 1533                 goto bad;
 1534         }
 1535         blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk;
 1536         nblocks = fd->ft->size;
 1537         bp->b_resid = 0;
 1538         if (blknum + (bp->b_bcount / fdblk) > nblocks) {
 1539                 if (blknum <= nblocks) {
 1540                         cando = (nblocks - blknum) * fdblk;
 1541                         bp->b_resid = bp->b_bcount - cando;
 1542                         if (cando == 0)
 1543                                 goto bad;       /* not actually bad but EOF */
 1544                 } else {
 1545                         bp->b_error = EINVAL;
 1546                         bp->b_flags |= B_ERROR;
 1547                         goto bad;
 1548                 }
 1549         }
 1550         bp->b_pblkno = bp->b_blkno;
 1551         s = splbio();
 1552         bufqdisksort(&fdc->head, bp);
 1553         untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
 1554 
 1555         /* Tell devstat we are starting on the transaction */
 1556         devstat_start_transaction(&fd->device_stats);
 1557         device_busy(fd->dev);
 1558 
 1559         fdstart(fdc);
 1560         splx(s);
 1561         return;
 1562 
 1563 bad:
 1564         biodone(bp);
 1565 }
 1566 
 1567 /***************************************************************\
 1568 *                               fdstart                         *
 1569 * We have just queued something.. if the controller is not busy *
 1570 * then simulate the case where it has just finished a command   *
 1571 * So that it (the interrupt routine) looks on the queue for more*
 1572 * work to do and picks up what we just added.                   *
 1573 * If the controller is already busy, we need do nothing, as it  *
 1574 * will pick up our work when the present work completes         *
 1575 \***************************************************************/
 1576 static void
 1577 fdstart(struct fdc_data *fdc)
 1578 {
 1579         int s;
 1580 
 1581         s = splbio();
 1582         if(fdc->state == DEVIDLE)
 1583         {
 1584                 fdc_intr(fdc);
 1585         }
 1586         splx(s);
 1587 }
 1588 
 1589 static void
 1590 fd_iotimeout(void *xfdc)
 1591 {
 1592         fdc_p fdc;
 1593         int s;
 1594 
 1595         fdc = xfdc;
 1596         TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
 1597 
 1598         /*
 1599          * Due to IBM's brain-dead design, the FDC has a faked ready
 1600          * signal, hardwired to ready == true. Thus, any command
 1601          * issued if there's no diskette in the drive will _never_
 1602          * complete, and must be aborted by resetting the FDC.
 1603          * Many thanks, Big Blue!
 1604          * The FDC must not be reset directly, since that would
 1605          * interfere with the state machine.  Instead, pretend that
 1606          * the command completed but was invalid.  The state machine
 1607          * will reset the FDC and retry once.
 1608          */
 1609         s = splbio();
 1610         fdc->status[0] = NE7_ST0_IC_IV;
 1611         fdc->flags &= ~FDC_STAT_VALID;
 1612         fdc->state = IOTIMEDOUT;
 1613         fdc_intr(fdc);
 1614         splx(s);
 1615 }
 1616 
 1617 /* just ensure it has the right spl */
 1618 static void
 1619 fd_pseudointr(void *xfdc)
 1620 {
 1621         int     s;
 1622 
 1623         s = splbio();
 1624         fdc_intr(xfdc);
 1625         splx(s);
 1626 }
 1627 
 1628 /***********************************************************************\
 1629 *                                 fdintr                                *
 1630 * keep calling the state machine until it returns a 0                   *
 1631 * ALWAYS called at SPLBIO                                               *
 1632 \***********************************************************************/
 1633 static void
 1634 fdc_intr(void *xfdc)
 1635 {
 1636         fdc_p fdc = xfdc;
 1637         while(fdstate(fdc))
 1638                 ;
 1639 }
 1640 
 1641 /*
 1642  * magic pseudo-DMA initialization for YE FDC. Sets count and
 1643  * direction
 1644  */
 1645 #define SET_BCDR(fdc,wr,cnt,port) \
 1646         bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port,  \
 1647             ((cnt)-1) & 0xff);                                           \
 1648         bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
 1649             ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
 1650 
 1651 /*
 1652  * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
 1653  */
 1654 static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
 1655 {
 1656         u_char *cptr = (u_char *)addr;
 1657 
 1658         if (flags & B_READ) {
 1659                 if (fdc->state != PIOREAD) {
 1660                         fdc->state = PIOREAD;
 1661                         return(0);
 1662                 };
 1663                 SET_BCDR(fdc, 0, count, 0);
 1664                 bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
 1665                     FDC_YE_DATAPORT, cptr, count);
 1666         } else {
 1667                 bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
 1668                     FDC_YE_DATAPORT, cptr, count);
 1669                 SET_BCDR(fdc, 0, count, 0);
 1670         };
 1671         return(1);
 1672 }
 1673 
 1674 /***********************************************************************\
 1675 * The controller state machine.                                         *
 1676 * if it returns a non zero value, it should be called again immediatly  *
 1677 \***********************************************************************/
 1678 static int
 1679 fdstate(fdc_p fdc)
 1680 {
 1681         int read, format, head, i, sec = 0, sectrac, st0, cyl, st3;
 1682         unsigned blknum = 0, b_cylinder = 0;
 1683         fdu_t fdu = fdc->fdu;
 1684         fd_p fd;
 1685         register struct buf *bp;
 1686         struct fd_formb *finfo = NULL;
 1687         size_t fdblk;
 1688 
 1689         bp = fdc->bp;
 1690         if (bp == NULL) {
 1691                 bp = bufq_first(&fdc->head);
 1692                 if (bp != NULL) {
 1693                         bufq_remove(&fdc->head, bp);
 1694                         fdc->bp = bp;
 1695                 }
 1696         }
 1697         if (bp == NULL) {
 1698                 /***********************************************\
 1699                 * nothing left for this controller to do        *
 1700                 * Force into the IDLE state,                    *
 1701                 \***********************************************/
 1702                 fdc->state = DEVIDLE;
 1703                 if (fdc->fd) {
 1704                         device_printf(fdc->fdc_dev,
 1705                             "unexpected valid fd pointer\n");
 1706                         fdc->fd = (fd_p) 0;
 1707                         fdc->fdu = -1;
 1708                 }
 1709                 TRACE1("[fdc%d IDLE]", fdc->fdcu);
 1710                 return (0);
 1711         }
 1712         fdu = FDUNIT(minor(bp->b_dev));
 1713         fd = devclass_get_softc(fd_devclass, fdu);
 1714         fdblk = 128 << fd->ft->secsize;
 1715         if (fdc->fd && (fd != fdc->fd))
 1716                 device_printf(fd->dev, "confused fd pointers\n");
 1717         read = bp->b_flags & B_READ;
 1718         format = bp->b_flags & B_FORMAT;
 1719         if (format) {
 1720                 finfo = (struct fd_formb *)bp->b_data;
 1721                 fd->skip = (char *)&(finfo->fd_formb_cylno(0))
 1722                         - (char *)finfo;
 1723         }
 1724         if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
 1725                 blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk +
 1726                         fd->skip/fdblk;
 1727                 b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
 1728         }
 1729         TRACE1("fd%d", fdu);
 1730         TRACE1("[%s]", fdstates[fdc->state]);
 1731         TRACE1("(0x%x)", fd->flags);
 1732         untimeout(fd_turnoff, fd, fd->toffhandle);
 1733         fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
 1734         switch (fdc->state)
 1735         {
 1736         case DEVIDLE:
 1737         case FINDWORK:  /* we have found new work */
 1738                 fdc->retry = 0;
 1739                 fd->skip = 0;
 1740                 fdc->fd = fd;
 1741                 fdc->fdu = fdu;
 1742                 fdc->fdctl_wr(fdc, fd->ft->trans);
 1743                 TRACE1("[0x%x->FDCTL]", fd->ft->trans);
 1744                 /*******************************************************\
 1745                 * If the next drive has a motor startup pending, then   *
 1746                 * it will start up in its own good time         *
 1747                 \*******************************************************/
 1748                 if(fd->flags & FD_MOTOR_WAIT) {
 1749                         fdc->state = MOTORWAIT;
 1750                         return (0); /* come back later */
 1751                 }
 1752                 /*******************************************************\
 1753                 * Maybe if it's not starting, it SHOULD be starting     *
 1754                 \*******************************************************/
 1755                 if (!(fd->flags & FD_MOTOR))
 1756                 {
 1757                         fdc->state = MOTORWAIT;
 1758                         fd_turnon(fd);
 1759                         return (0);
 1760                 }
 1761                 else    /* at least make sure we are selected */
 1762                 {
 1763                         set_motor(fdc, fd->fdsu, TURNON);
 1764                 }
 1765                 if (fdc->flags & FDC_NEEDS_RESET) {
 1766                         fdc->state = RESETCTLR;
 1767                         fdc->flags &= ~FDC_NEEDS_RESET;
 1768                 } else
 1769                         fdc->state = DOSEEK;
 1770                 break;
 1771         case DOSEEK:
 1772                 if (b_cylinder == (unsigned)fd->track)
 1773                 {
 1774                         fdc->state = SEEKCOMPLETE;
 1775                         break;
 1776                 }
 1777                 if (fd_cmd(fdc, 3, NE7CMD_SEEK,
 1778                            fd->fdsu, b_cylinder * fd->ft->steptrac,
 1779                            0))
 1780                 {
 1781                         /*
 1782                          * seek command not accepted, looks like
 1783                          * the FDC went off to the Saints...
 1784                          */
 1785                         fdc->retry = 6; /* try a reset */
 1786                         return(retrier(fdc));
 1787                 }
 1788                 fd->track = FD_NO_TRACK;
 1789                 fdc->state = SEEKWAIT;
 1790                 return(0);      /* will return later */
 1791         case SEEKWAIT:
 1792                 /* allow heads to settle */
 1793                 timeout(fd_pseudointr, fdc, hz / 16);
 1794                 fdc->state = SEEKCOMPLETE;
 1795                 return(0);      /* will return later */
 1796         case SEEKCOMPLETE : /* SEEK DONE, START DMA */
 1797                 /* Make sure seek really happened*/
 1798                 if(fd->track == FD_NO_TRACK) {
 1799                         int descyl = b_cylinder * fd->ft->steptrac;
 1800                         do {
 1801                                 /*
 1802                                  * This might be a "ready changed" interrupt,
 1803                                  * which cannot really happen since the
 1804                                  * RDY pin is hardwired to + 5 volts.  This
 1805                                  * generally indicates a "bouncing" intr
 1806                                  * line, so do one of the following:
 1807                                  *
 1808                                  * When running on an enhanced FDC that is
 1809                                  * known to not go stuck after responding
 1810                                  * with INVALID, fetch all interrupt states
 1811                                  * until seeing either an INVALID or a
 1812                                  * real interrupt condition.
 1813                                  *
 1814                                  * When running on a dumb old NE765, give
 1815                                  * up immediately.  The controller will
 1816                                  * provide up to four dummy RC interrupt
 1817                                  * conditions right after reset (for the
 1818                                  * corresponding four drives), so this is
 1819                                  * our only chance to get notice that it
 1820                                  * was not the FDC that caused the interrupt.
 1821                                  */
 1822                                 if (fd_sense_int(fdc, &st0, &cyl)
 1823                                     == FD_NOT_VALID)
 1824                                         return 0;
 1825                                 if(fdc->fdct == FDC_NE765
 1826                                    && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 1827                                         return 0; /* hope for a real intr */
 1828                         } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 1829 
 1830                         if (0 == descyl) {
 1831                                 int failed = 0;
 1832                                 /*
 1833                                  * seek to cyl 0 requested; make sure we are
 1834                                  * really there
 1835                                  */
 1836                                 if (fd_sense_drive_status(fdc, &st3))
 1837                                         failed = 1;
 1838                                 if ((st3 & NE7_ST3_T0) == 0) {
 1839                                         printf(
 1840                 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
 1841                                                fdu, st3, NE7_ST3BITS);
 1842                                         failed = 1;
 1843                                 }
 1844 
 1845                                 if (failed) {
 1846                                         if(fdc->retry < 3)
 1847                                                 fdc->retry = 3;
 1848                                         return (retrier(fdc));
 1849                                 }
 1850                         }
 1851 
 1852                         if (cyl != descyl) {
 1853                                 printf(
 1854                 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
 1855                                        fdu, descyl, cyl, st0);
 1856                                 if (fdc->retry < 3)
 1857                                         fdc->retry = 3;
 1858                                 return (retrier(fdc));
 1859                         }
 1860                 }
 1861 
 1862                 fd->track = b_cylinder;
 1863                 if (!(fdc->flags & FDC_NODMA))
 1864                         isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
 1865                                 format ? bp->b_bcount : fdblk, fdc->dmachan);
 1866                 sectrac = fd->ft->sectrac;
 1867                 sec = blknum %  (sectrac * fd->ft->heads);
 1868                 head = sec / sectrac;
 1869                 sec = sec % sectrac + 1;
 1870                 fd->hddrv = ((head&1)<<2)+fdu;
 1871 
 1872                 if(format || !read)
 1873                 {
 1874                         /* make sure the drive is writable */
 1875                         if(fd_sense_drive_status(fdc, &st3) != 0)
 1876                         {
 1877                                 /* stuck controller? */
 1878                                 if (!(fdc->flags & FDC_NODMA))
 1879                                         isa_dmadone(bp->b_flags,
 1880                                                     bp->b_data + fd->skip,
 1881                                                     format ? bp->b_bcount : fdblk,
 1882                                                     fdc->dmachan);
 1883                                 fdc->retry = 6; /* reset the beast */
 1884                                 return (retrier(fdc));
 1885                         }
 1886                         if(st3 & NE7_ST3_WP)
 1887                         {
 1888                                 /*
 1889                                  * XXX YES! this is ugly.
 1890                                  * in order to force the current operation
 1891                                  * to fail, we will have to fake an FDC
 1892                                  * error - all error handling is done
 1893                                  * by the retrier()
 1894                                  */
 1895                                 fdc->status[0] = NE7_ST0_IC_AT;
 1896                                 fdc->status[1] = NE7_ST1_NW;
 1897                                 fdc->status[2] = 0;
 1898                                 fdc->status[3] = fd->track;
 1899                                 fdc->status[4] = head;
 1900                                 fdc->status[5] = sec;
 1901                                 fdc->retry = 8; /* break out immediately */
 1902                                 fdc->state = IOTIMEDOUT; /* not really... */
 1903                                 return (1);
 1904                         }
 1905                 }
 1906 
 1907                 if (format) {
 1908                         if (fdc->flags & FDC_NODMA) {
 1909                                 /*
 1910                                  * This seems to be necessary for
 1911                                  * whatever obscure reason; if we omit
 1912                                  * it, we end up filling the sector ID
 1913                                  * fields of the newly formatted track
 1914                                  * entirely with garbage, causing
 1915                                  * `wrong cylinder' errors all over
 1916                                  * the place when trying to read them
 1917                                  * back.
 1918                                  *
 1919                                  * Umpf.
 1920                                  */
 1921                                 SET_BCDR(fdc, 1, bp->b_bcount, 0);
 1922 
 1923                                 (void)fdcpio(fdc,bp->b_flags,
 1924                                         bp->b_data+fd->skip,
 1925                                         bp->b_bcount);
 1926 
 1927                         }
 1928                         /* formatting */
 1929                         if(fd_cmd(fdc, 6,  NE7CMD_FORMAT, head << 2 | fdu,
 1930                                   finfo->fd_formb_secshift,
 1931                                   finfo->fd_formb_nsecs,
 1932                                   finfo->fd_formb_gaplen,
 1933                                   finfo->fd_formb_fillbyte, 0)) {
 1934                                 /* controller fell over */
 1935                                 if (!(fdc->flags & FDC_NODMA))
 1936                                         isa_dmadone(bp->b_flags,
 1937                                                     bp->b_data + fd->skip,
 1938                                                     format ? bp->b_bcount : fdblk,
 1939                                                     fdc->dmachan);
 1940                                 fdc->retry = 6;
 1941                                 return (retrier(fdc));
 1942                         }
 1943                 } else {
 1944                         if (fdc->flags & FDC_NODMA) {
 1945                                 /*
 1946                                  * this seems to be necessary even when
 1947                                  * reading data
 1948                                  */
 1949                                 SET_BCDR(fdc, 1, fdblk, 0);
 1950 
 1951                                 /*
 1952                                  * perform the write pseudo-DMA before
 1953                                  * the WRITE command is sent
 1954                                  */
 1955                                 if (!read)
 1956                                         (void)fdcpio(fdc,bp->b_flags,
 1957                                             bp->b_data+fd->skip,
 1958                                             fdblk);
 1959                         }
 1960                         if (fd_cmd(fdc, 9,
 1961                                    (read ? NE7CMD_READ : NE7CMD_WRITE),
 1962                                    head << 2 | fdu,  /* head & unit */
 1963                                    fd->track,        /* track */
 1964                                    head,
 1965                                    sec,              /* sector + 1 */
 1966                                    fd->ft->secsize,  /* sector size */
 1967                                    sectrac,          /* sectors/track */
 1968                                    fd->ft->gap,      /* gap size */
 1969                                    fd->ft->datalen,  /* data length */
 1970                                    0)) {
 1971                                 /* the beast is sleeping again */
 1972                                 if (!(fdc->flags & FDC_NODMA))
 1973                                         isa_dmadone(bp->b_flags,
 1974                                                     bp->b_data + fd->skip,
 1975                                                     format ? bp->b_bcount : fdblk,
 1976                                                     fdc->dmachan);
 1977                                 fdc->retry = 6;
 1978                                 return (retrier(fdc));
 1979                         }
 1980                 }
 1981                 if (fdc->flags & FDC_NODMA)
 1982                         /*
 1983                          * if this is a read, then simply await interrupt
 1984                          * before performing PIO
 1985                          */
 1986                         if (read && !fdcpio(fdc,bp->b_flags,
 1987                             bp->b_data+fd->skip,fdblk)) {
 1988                                 fd->tohandle = timeout(fd_iotimeout, fdc, hz);
 1989                                 return(0);      /* will return later */
 1990                         };
 1991 
 1992                 /*
 1993                  * write (or format) operation will fall through and
 1994                  * await completion interrupt
 1995                  */
 1996                 fdc->state = IOCOMPLETE;
 1997                 fd->tohandle = timeout(fd_iotimeout, fdc, hz);
 1998                 return (0);     /* will return later */
 1999         case PIOREAD:
 2000                 /* 
 2001                  * actually perform the PIO read.  The IOCOMPLETE case
 2002                  * removes the timeout for us.  
 2003                  */
 2004                 (void)fdcpio(fdc,bp->b_flags,bp->b_data+fd->skip,fdblk);
 2005                 fdc->state = IOCOMPLETE;
 2006                 /* FALLTHROUGH */
 2007         case IOCOMPLETE: /* IO DONE, post-analyze */
 2008                 untimeout(fd_iotimeout, fdc, fd->tohandle);
 2009 
 2010                 if (fd_read_status(fdc, fd->fdsu)) {
 2011                         if (!(fdc->flags & FDC_NODMA))
 2012                                 isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
 2013                                             format ? bp->b_bcount : fdblk,
 2014                                             fdc->dmachan);
 2015                         if (fdc->retry < 6)
 2016                                 fdc->retry = 6; /* force a reset */
 2017                         return (retrier(fdc));
 2018                 }
 2019 
 2020                 fdc->state = IOTIMEDOUT;
 2021 
 2022                 /* FALLTHROUGH */
 2023 
 2024         case IOTIMEDOUT:
 2025                 if (!(fdc->flags & FDC_NODMA))
 2026                         isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
 2027                                 format ? bp->b_bcount : fdblk, fdc->dmachan);
 2028                 if (fdc->status[0] & NE7_ST0_IC) {
 2029                         if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 2030                             && fdc->status[1] & NE7_ST1_OR) {
 2031                                 /*
 2032                                  * DMA overrun. Someone hogged the bus and
 2033                                  * didn't release it in time for the next
 2034                                  * FDC transfer.
 2035                                  *
 2036                                  * We normally restart this without bumping
 2037                                  * the retry counter.  However, in case
 2038                                  * something is seriously messed up (like
 2039                                  * broken hardware), we rather limit the
 2040                                  * number of retries so the IO operation
 2041                                  * doesn't block indefinately.
 2042                                  */
 2043                                 if (fdc->dma_overruns++ < FDC_DMAOV_MAX) {
 2044                                         fdc->state = SEEKCOMPLETE;
 2045                                         return (1);
 2046                                 } /* else fall through */
 2047                         }
 2048                         if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
 2049                                 && fdc->retry < 6)
 2050                                 fdc->retry = 6; /* force a reset */
 2051                         else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 2052                                 && fdc->status[2] & NE7_ST2_WC
 2053                                 && fdc->retry < 3)
 2054                                 fdc->retry = 3; /* force recalibrate */
 2055                         return (retrier(fdc));
 2056                 }
 2057                 /* All OK */
 2058                 /* Operation successful, retry DMA overruns again next time. */
 2059                 fdc->dma_overruns = 0;
 2060                 fd->skip += fdblk;
 2061                 if (!format && fd->skip < bp->b_bcount - bp->b_resid) {
 2062                         /* set up next transfer */
 2063                         fdc->state = DOSEEK;
 2064                 } else {
 2065                         /* ALL DONE */
 2066                         fd->skip = 0;
 2067                         fdc->bp = NULL;
 2068                         device_unbusy(fd->dev);
 2069                         devstat_end_transaction_buf(&fd->device_stats, bp);
 2070                         biodone(bp);
 2071                         fdc->fd = (fd_p) 0;
 2072                         fdc->fdu = -1;
 2073                         fdc->state = FINDWORK;
 2074                 }
 2075                 return (1);
 2076         case RESETCTLR:
 2077                 fdc_reset(fdc);
 2078                 fdc->retry++;
 2079                 fdc->state = RESETCOMPLETE;
 2080                 return (0);
 2081         case RESETCOMPLETE:
 2082                 /*
 2083                  * Discard all the results from the reset so that they
 2084                  * can't cause an unexpected interrupt later.
 2085                  */
 2086                 for (i = 0; i < 4; i++)
 2087                         (void)fd_sense_int(fdc, &st0, &cyl);
 2088                 fdc->state = STARTRECAL;
 2089                 /* Fall through. */
 2090         case STARTRECAL:
 2091                 if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) {
 2092                         /* arrgl */
 2093                         fdc->retry = 6;
 2094                         return (retrier(fdc));
 2095                 }
 2096                 fdc->state = RECALWAIT;
 2097                 return (0);     /* will return later */
 2098         case RECALWAIT:
 2099                 /* allow heads to settle */
 2100                 timeout(fd_pseudointr, fdc, hz / 8);
 2101                 fdc->state = RECALCOMPLETE;
 2102                 return (0);     /* will return later */
 2103         case RECALCOMPLETE:
 2104                 do {
 2105                         /*
 2106                          * See SEEKCOMPLETE for a comment on this:
 2107                          */
 2108                         if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
 2109                                 return 0;
 2110                         if(fdc->fdct == FDC_NE765
 2111                            && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 2112                                 return 0; /* hope for a real intr */
 2113                 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 2114                 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
 2115                 {
 2116                         if(fdc->retry > 3)
 2117                                 /*
 2118                                  * a recalibrate from beyond cylinder 77
 2119                                  * will "fail" due to the FDC limitations;
 2120                                  * since people used to complain much about
 2121                                  * the failure message, try not logging
 2122                                  * this one if it seems to be the first
 2123                                  * time in a line
 2124                                  */
 2125                                 printf("fd%d: recal failed ST0 %b cyl %d\n",
 2126                                        fdu, st0, NE7_ST0BITS, cyl);
 2127                         if(fdc->retry < 3) fdc->retry = 3;
 2128                         return (retrier(fdc));
 2129                 }
 2130                 fd->track = 0;
 2131                 /* Seek (probably) necessary */
 2132                 fdc->state = DOSEEK;
 2133                 return (1);     /* will return immediatly */
 2134         case MOTORWAIT:
 2135                 if(fd->flags & FD_MOTOR_WAIT)
 2136                 {
 2137                         return (0); /* time's not up yet */
 2138                 }
 2139                 if (fdc->flags & FDC_NEEDS_RESET) {
 2140                         fdc->state = RESETCTLR;
 2141                         fdc->flags &= ~FDC_NEEDS_RESET;
 2142                 } else {
 2143                         /*
 2144                          * If all motors were off, then the controller was
 2145                          * reset, so it has lost track of the current
 2146                          * cylinder.  Recalibrate to handle this case.
 2147                          * But first, discard the results of the reset.
 2148                          */
 2149                         fdc->state = RESETCOMPLETE;
 2150                 }
 2151                 return (1);     /* will return immediatly */
 2152         default:
 2153                 device_printf(fdc->fdc_dev, "unexpected FD int->");
 2154                 if (fd_read_status(fdc, fd->fdsu) == 0)
 2155                         printf("FDC status :%x %x %x %x %x %x %x   ",
 2156                                fdc->status[0],
 2157                                fdc->status[1],
 2158                                fdc->status[2],
 2159                                fdc->status[3],
 2160                                fdc->status[4],
 2161                                fdc->status[5],
 2162                                fdc->status[6] );
 2163                 else
 2164                         printf("No status available   ");
 2165                 if (fd_sense_int(fdc, &st0, &cyl) != 0)
 2166                 {
 2167                         printf("[controller is dead now]\n");
 2168                         return (0);
 2169                 }
 2170                 printf("ST0 = %x, PCN = %x\n", st0, cyl);
 2171                 return (0);
 2172         }
 2173         /*XXX confusing: some branches return immediately, others end up here*/
 2174         return (1); /* Come back immediatly to new state */
 2175 }
 2176 
 2177 static int
 2178 retrier(struct fdc_data *fdc)
 2179 {
 2180         register struct buf *bp;
 2181         struct fd_data *fd;
 2182         int fdu;
 2183 
 2184         bp = fdc->bp;
 2185 
 2186         /* XXX shouldn't this be cached somewhere?  */
 2187         fdu = FDUNIT(minor(bp->b_dev));
 2188         fd = devclass_get_softc(fd_devclass, fdu);
 2189         if (fd->options & FDOPT_NORETRY)
 2190                 goto fail;
 2191 
 2192         switch (fdc->retry) {
 2193         case 0: case 1: case 2:
 2194                 fdc->state = SEEKCOMPLETE;
 2195                 break;
 2196         case 3: case 4: case 5:
 2197                 fdc->state = STARTRECAL;
 2198                 break;
 2199         case 6:
 2200                 fdc->state = RESETCTLR;
 2201                 break;
 2202         case 7:
 2203                 break;
 2204         default:
 2205         fail:
 2206                 {
 2207                         int printerror = (fd->options & FDOPT_NOERRLOG) == 0;
 2208                         dev_t sav_b_dev = bp->b_dev;
 2209 
 2210                         /* Trick diskerr */
 2211                         bp->b_dev = makedev(major(bp->b_dev),
 2212                                     (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
 2213                         if (printerror)
 2214                                 diskerr(bp, "hard error", LOG_PRINTF,
 2215                                         fdc->fd->skip / DEV_BSIZE,
 2216                                         (struct disklabel *)NULL);
 2217                         bp->b_dev = sav_b_dev;
 2218                         if (printerror) {
 2219                                 if (fdc->flags & FDC_STAT_VALID)
 2220                                         printf(
 2221                         " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n",
 2222                                                fdc->status[0], NE7_ST0BITS,
 2223                                                fdc->status[1], NE7_ST1BITS,
 2224                                                fdc->status[2], NE7_ST2BITS,
 2225                                                fdc->status[3], fdc->status[4],
 2226                                                fdc->status[5]);
 2227                                 else
 2228                                         printf(" (No status)\n");
 2229                         }
 2230                 }
 2231                 bp->b_flags |= B_ERROR;
 2232                 bp->b_error = EIO;
 2233                 bp->b_resid += bp->b_bcount - fdc->fd->skip;
 2234                 fdc->bp = NULL;
 2235                 fdc->fd->skip = 0;
 2236                 device_unbusy(fd->dev);
 2237                 devstat_end_transaction_buf(&fdc->fd->device_stats, bp);
 2238                 biodone(bp);
 2239                 fdc->state = FINDWORK;
 2240                 fdc->flags |= FDC_NEEDS_RESET;
 2241                 fdc->fd = (fd_p) 0;
 2242                 fdc->fdu = -1;
 2243                 return (1);
 2244         }
 2245         fdc->retry++;
 2246         return (1);
 2247 }
 2248 
 2249 static int
 2250 fdformat(dev, finfo, p)
 2251         dev_t dev;
 2252         struct fd_formb *finfo;
 2253         struct proc *p;
 2254 {
 2255         fdu_t   fdu;
 2256         fd_p    fd;
 2257 
 2258         struct buf *bp;
 2259         int rv = 0, s;
 2260         size_t fdblk;
 2261 
 2262         fdu     = FDUNIT(minor(dev));
 2263         fd      = devclass_get_softc(fd_devclass, fdu);
 2264         fdblk = 128 << fd->ft->secsize;
 2265 
 2266         /* set up a buffer header for fdstrategy() */
 2267         bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
 2268         if(bp == 0)
 2269                 return ENOBUFS;
 2270         /*
 2271          * keep the process from being swapped
 2272          */
 2273         PHOLD(p);
 2274         bzero((void *)bp, sizeof(struct buf));
 2275         BUF_LOCKINIT(bp);
 2276         BUF_LOCK(bp, LK_EXCLUSIVE);
 2277         bp->b_flags = B_PHYS | B_FORMAT;
 2278 
 2279         /*
 2280          * calculate a fake blkno, so fdstrategy() would initiate a
 2281          * seek to the requested cylinder
 2282          */
 2283         bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
 2284                 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
 2285 
 2286         bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
 2287         bp->b_data = (caddr_t)finfo;
 2288 
 2289         /* now do the format */
 2290         bp->b_dev = dev;
 2291         BUF_STRATEGY(bp, 0);
 2292 
 2293         /* ...and wait for it to complete */
 2294         s = splbio();
 2295         while(!(bp->b_flags & B_DONE)) {
 2296                 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
 2297                 if (rv == EWOULDBLOCK)
 2298                         break;
 2299         }
 2300         splx(s);
 2301 
 2302         if (rv == EWOULDBLOCK) {
 2303                 /* timed out */
 2304                 rv = EIO;
 2305                 device_unbusy(fd->dev);
 2306                 biodone(bp);
 2307         }
 2308         if (bp->b_flags & B_ERROR)
 2309                 rv = bp->b_error;
 2310         /*
 2311          * allow the process to be swapped
 2312          */
 2313         PRELE(p);
 2314         BUF_UNLOCK(bp);
 2315         BUF_LOCKFREE(bp);
 2316         free(bp, M_TEMP);
 2317         return rv;
 2318 }
 2319 
 2320 /*
 2321  * TODO: don't allocate buffer on stack.
 2322  */
 2323 
 2324 static int
 2325 fdioctl(dev, cmd, addr, flag, p)
 2326         dev_t dev;
 2327         u_long cmd;
 2328         caddr_t addr;
 2329         int flag;
 2330         struct proc *p;
 2331 {
 2332         fdu_t   fdu = FDUNIT(minor(dev));
 2333         fd_p    fd = devclass_get_softc(fd_devclass, fdu);
 2334         size_t fdblk;
 2335 
 2336         struct fd_type *fdt;
 2337         struct disklabel *dl;
 2338         struct fdc_status *fsp;
 2339         char buffer[DEV_BSIZE];
 2340         int error = 0;
 2341 
 2342         fdblk = 128 << fd->ft->secsize;
 2343 
 2344         switch (cmd) {
 2345         case DIOCGDINFO:
 2346                 bzero(buffer, sizeof (buffer));
 2347                 dl = (struct disklabel *)buffer;
 2348                 dl->d_secsize = fdblk;
 2349                 fdt = fd->ft;
 2350                 dl->d_secpercyl = fdt->size / fdt->tracks;
 2351                 dl->d_type = DTYPE_FLOPPY;
 2352 
 2353                 if (readdisklabel(dev, dl)
 2354                     == NULL)
 2355                         error = 0;
 2356                 else
 2357                         error = EINVAL;
 2358 
 2359                 *(struct disklabel *)addr = *dl;
 2360                 break;
 2361 
 2362         case DIOCSDINFO:
 2363                 if ((flag & FWRITE) == 0)
 2364                         error = EBADF;
 2365                 break;
 2366 
 2367         case DIOCWLABEL:
 2368                 if ((flag & FWRITE) == 0)
 2369                         error = EBADF;
 2370                 break;
 2371 
 2372         case DIOCWDINFO:
 2373                 if ((flag & FWRITE) == 0) {
 2374                         error = EBADF;
 2375                         break;
 2376                 }
 2377 
 2378                 dl = (struct disklabel *)addr;
 2379 
 2380                 if ((error = setdisklabel((struct disklabel *)buffer, dl,
 2381                                           (u_long)0)) != 0)
 2382                         break;
 2383 
 2384                 error = writedisklabel(dev, (struct disklabel *)buffer);
 2385                 break;
 2386         case FD_FORM:
 2387                 if ((flag & FWRITE) == 0)
 2388                         error = EBADF;  /* must be opened for writing */
 2389                 else if (((struct fd_formb *)addr)->format_version !=
 2390                         FD_FORMAT_VERSION)
 2391                         error = EINVAL; /* wrong version of formatting prog */
 2392                 else
 2393                         error = fdformat(dev, (struct fd_formb *)addr, p);
 2394                 break;
 2395 
 2396         case FD_GTYPE:                  /* get drive type */
 2397                 *(struct fd_type *)addr = *fd->ft;
 2398                 break;
 2399 
 2400         case FD_STYPE:                  /* set drive type */
 2401                 /* this is considered harmful; only allow for superuser */
 2402                 if (suser(p) != 0)
 2403                         return EPERM;
 2404                 *fd->ft = *(struct fd_type *)addr;
 2405                 break;
 2406 
 2407         case FD_GOPTS:                  /* get drive options */
 2408                 *(int *)addr = fd->options;
 2409                 break;
 2410 
 2411         case FD_SOPTS:                  /* set drive options */
 2412                 fd->options = *(int *)addr;
 2413                 break;
 2414 
 2415         case FD_GSTAT:
 2416                 fsp = (struct fdc_status *)addr;
 2417                 if ((fd->fdc->flags & FDC_STAT_VALID) == 0)
 2418                         return EINVAL;
 2419                 memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int));
 2420                 break;
 2421 
 2422         default:
 2423                 error = ENOTTY;
 2424                 break;
 2425         }
 2426         return (error);
 2427 }
 2428 
 2429 /*
 2430  * Hello emacs, these are the
 2431  * Local Variables:
 2432  *  c-indent-level:               8
 2433  *  c-continued-statement-offset: 8
 2434  *  c-continued-brace-offset:     0
 2435  *  c-brace-offset:              -8
 2436  *  c-brace-imaginary-offset:     0
 2437  *  c-argdecl-indent:             8
 2438  *  c-label-offset:              -8
 2439  *  c++-hanging-braces:           1
 2440  *  c++-access-specifier-offset: -8
 2441  *  c++-empty-arglist-indent:     8
 2442  *  c++-friend-offset:            0
 2443  * End:
 2444  */

Cache object: 97b9348328f972361efb471a00955c98


[ 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.