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/i386at/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  * Mach Operating System
    3  * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /* 
   27  * HISTORY
   28  * $Log:        fd.c,v $
   29  * Revision 2.16  93/11/17  16:44:25  dbg
   30  *      Changed HZ to hz.  Added include of kern/time_out.h.
   31  *      Removed non-MACH_KERNEL code.
   32  *      [93/05/21            dbg]
   33  * 
   34  * Revision 2.15  93/08/02  21:43:43  mrt
   35  *      Put the free copyright on this file, again.
   36  *      [93/07/22            mrt]
   37  * 
   38  * Revision 2.14  93/05/15  19:32:35  mrt
   39  *      machparam.h -> machspl.h
   40  * 
   41  * Revision 2.13  93/05/10  21:19:02  rvb
   42  *      Lint.
   43  *      [93/05/08  11:19:03  af]
   44  * 
   45  * Revision 2.12  93/01/24  13:15:28  danner
   46  *      [93/01/19  11:03:43  rvb]
   47  * 
   48  *      Test lower bound of media type; convert fd_addr to vm_offset_t.
   49  * 
   50  * Revision 2.11  93/01/14  17:30:11  danner
   51  *      Proper spl typing.
   52  *      [92/11/30            af]
   53  * 
   54  * Revision 2.10  92/07/09  22:53:34  rvb
   55  *      There is a problem with ADAPTEC boards, where scsi disk dma will
   56  *      lock out the floppy dma.  An expedient fix seems to be to drop
   57  *      the DMA size for the floppy, in the retry code when/if this happens.
   58  *      [92/07/08            rvb]
   59  * 
   60  * Revision 2.9  92/04/08  08:58:30  rpd
   61  *      Fixed fdprobe to loop longer.  From rvb.
   62  *      [92/04/08            rpd]
   63  * 
   64  * Revision 2.8  92/02/23  22:42:57  elf
   65  *      Added (mandatory) DEV_GET_SIZE flavor of get_status.
   66  *      [92/02/22            af]
   67  * 
   68  * Revision 2.7  92/01/27  16:42:54  rpd
   69  *      Fixed fdgetstat and fdsetstat to return D_INVALID_OPERATION
   70  *      for unsupported flavors.
   71  *      [92/01/26            rpd]
   72  * 
   73  * Revision 2.6  91/11/12  11:09:18  rvb
   74  *      Amazing how hard getting the probe to work for all machines is.
   75  *      [91/10/16            rvb]
   76  * 
   77  * Revision 2.5  91/10/07  17:25:22  af
   78  *      Still better
   79  *      [91/10/07  16:29:57  rvb]
   80  * 
   81  *      From mg32: Better probe for multiple controllers now possible.
   82  *      [91/09/23            rvb]
   83  *      New chips/busses.[ch] nomenclature.
   84  *      [91/09/09  17:12:23  rvb]
   85  * 
   86  *      Added a reset in open to prevent "no such device" errors
   87  *      Added dlb's fddevinfo.
   88  *      Reworked to make 2.5/3.0 compatible
   89  *      [91/09/04  15:46:49  rvb]
   90  * 
   91  *      Major rewrite by mg32.
   92  *      [91/08/07            mg32]
   93  * 
   94  * Revision 2.4  91/08/24  11:57:32  af
   95  *      New MI autoconf.
   96  *      [91/08/02  02:53:26  af]
   97  * 
   98  * Revision 2.3  91/05/14  16:22:47  mrt
   99  *      Correcting copyright
  100  * 
  101  * Revision 2.2  91/02/14  14:42:23  mrt
  102  *      This file is the logical concatenation of the previous c765.c,
  103  *      m765knl.c and m765drv.c, in that order.  
  104  *      [91/01/15            rvb]
  105  * 
  106  * Revision 2.5  91/01/08  17:33:32  rpd
  107  *      Add some 3.0 get/set stat stuff.
  108  *      [91/01/04  12:21:06  rvb]
  109  * 
  110  * Revision 2.4  90/11/26  14:50:54  rvb
  111  *      jsb beat me to XMK34, sigh ...
  112  *      [90/11/26            rvb]
  113  *      Synched 2.5 & 3.0 at I386q (r1.6.1.6) & XMK35 (r2.4)
  114  *      [90/11/15            rvb]
  115  * 
  116  * Revision 1.6.1.6  90/11/27  13:44:55  rvb
  117  *      Synched 2.5 & 3.0 at I386q (r1.6.1.6) & XMK35 (r2.4)
  118  *      [90/11/15            rvb]
  119  * 
  120  * Revision 2.3  90/08/27  22:01:22  dbg
  121  *      Remove include of device/param.h (unnecessary).  Flush ushort.
  122  *      [90/07/17            dbg]
  123  * 
  124  * Revision 1.6.1.5  90/08/25  15:44:31  rvb
  125  *      Use take_<>_irq() vs direct manipulations of ivect and friends.
  126  *      [90/08/20            rvb]
  127  * 
  128  * Revision 1.6.1.4  90/07/27  11:26:53  rvb
  129  *      Fix Intel Copyright as per B. Davies authorization.
  130  *      [90/07/27            rvb]
  131  * 
  132  * Revision 1.6.1.3  90/07/10  11:45:11  rvb
  133  *      New style probe/attach.
  134  *      NOTE: the whole probe/slave/attach is a crock.  Someone
  135  *      who spends the time to understand the driver should do
  136  *      it right.
  137  *      [90/06/15            rvb]
  138  * 
  139  * Revision 2.2  90/05/03  15:45:37  dbg
  140  *      Convert for pure kernel.
  141  *      Optimized fd_disksort iff dp empty.
  142  *      [90/04/19            dbg]
  143  * 
  144  * Revision 1.6.1.2  90/01/08  13:30:14  rvb
  145  *      Add Intel copyright.
  146  *      [90/01/08            rvb]
  147  * 
  148  * Revision 1.6.1.1  89/10/22  11:34:51  rvb
  149  *      Received from Intel October 5, 1989.
  150  *      [89/10/13            rvb]
  151  * 
  152  * Revision 1.6  89/09/25  12:27:05  rvb
  153  *      vtoc.h -> disk.h
  154  *      [89/09/23            rvb]
  155  * 
  156  * Revision 1.5  89/09/09  15:23:15  rvb
  157  *      Have fd{read,write} use stragegy now that physio maps correctly.
  158  *      [89/09/06            rvb]
  159  * 
  160  * Revision 1.4  89/03/09  20:07:26  rpd
  161  *      More cleanup.
  162  * 
  163  * Revision 1.3  89/02/26  12:40:28  gm0w
  164  *      Changes for cleanup.
  165  *
  166  */
  167  
  168 /*
  169   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
  170 
  171                 All Rights Reserved
  172 
  173 Permission to use, copy, modify, and distribute this software and
  174 its documentation for any purpose and without fee is hereby
  175 granted, provided that the above copyright notice appears in all
  176 copies and that both the copyright notice and this permission notice
  177 appear in supporting documentation, and that the name of Intel
  178 not be used in advertising or publicity pertaining to distribution
  179 of the software without specific, written prior permission.
  180 
  181 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  182 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  183 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  184 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  185 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  186 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  187 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  188 */
  189 
  190 /*      Copyright (c) 1987, 1988 TOSHIBA Corp.          */
  191 /*              All Rights Reserved                     */
  192 
  193 #include <fd.h>
  194 
  195 #include <kern/time_out.h>
  196 #include <sys/types.h>
  197 #include <device/buf.h>
  198 #include <device/errno.h>
  199 #include <sys/ioctl.h>
  200 #include <i386/pio.h>
  201 #include <i386/machspl.h>
  202 #include <chips/busses.h>
  203 #include <i386at/fdreg.h>
  204 #include <i386at/disk.h>
  205 
  206 #ifdef  DEBUG
  207 #define D(x) x
  208 #else   /* DEBUG */
  209 #define D(x)
  210 #endif  /* DEBUG */
  211 
  212 /*
  213  * Floppy Device-Table Definitions (drtabs)
  214  *
  215  *      Cyls,Sec,spc,part,Mtype,RWFpl,FGpl
  216  */
  217 struct  fddrtab m765f[] = {                     /* format table */
  218         80, 18, 1440,  9, 0x88, 0x2a, 0x50,     /* [0] 3.50" 720  Kb  */
  219         80, 36, 2880, 18, 0x08, 0x1b, 0x6c,     /* [1] 3.50" 1.44 Meg */
  220         40, 18,  720,  9, 0xa8, 0x2a, 0x50,     /* [2] 5.25" 360  Kb  */
  221         80, 30, 2400, 15, 0x08, 0x1b, 0x54      /* [3] 5.25" 1.20 Meg */
  222 };
  223 
  224 /*
  225  * The following are static initialization variables
  226  * which are based on the configuration.
  227  */
  228 struct ctrl_info ctrl_info[MAXUNIT>>1] = {              /* device data table */
  229         {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
  230         {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  231 };
  232 
  233 struct unit_info unit_info[MAXUNIT];            /* unit buffer headers  */
  234 
  235 char *fderr = "FD Error on unit";
  236 char *fdmsg[] = {
  237         "?",
  238         "Missing data address mark",
  239         "Write protected",
  240         "Sector not found",
  241         "Data Overrun",                         /* Over run error */
  242         "Uncorrectable data read error",        /* CRC Error */
  243         "FDC Error",
  244         "Illegal format type",
  245         "Drive not ready",
  246         "diskette not present - please insert",
  247         "Illegal interrupt type"
  248 };
  249 
  250 struct buf      fdrbuf[MAXUNIT];        /* data transfer buffer structures */
  251 
  252 boolean_t fdprobe(vm_offset_t, struct bus_ctlr *);
  253 int     fdslave(struct bus_device *, vm_offset_t);
  254 void    fdattach(struct bus_device *);
  255 void    fdintr(int);
  256 
  257 vm_offset_t     fd_std[NFD] = { 0 };
  258 struct  bus_device *fd_dinfo[NFD*2];
  259 struct  bus_ctlr *fd_minfo[NFD];
  260 struct  bus_driver      fddriver = 
  261         {fdprobe, fdslave, fdattach, 0, fd_std,
  262          "fd", fd_dinfo, "fdc", fd_minfo, 0};
  263 
  264 int     m765verify[MAXUNIT] = {1,1,1,1};        /* write after read flag */
  265                                                 /* 0 != verify mode     */ 
  266                                                 /* 0 == not verify mode */
  267 extern struct buf *geteblk();
  268 extern void     wakeup();
  269 
  270 void m765iosub(
  271         struct unit_info *uip);         /* forward */
  272 void m765intrsub(
  273         struct unit_info *uip);         /* forward */
  274 void mtr_off(
  275         struct unit_info *uip);         /* forward */
  276 
  277 #define trfrate(uip, type)   outb(VFOREG(uip->addr),(((type)&RATEMASK)>>6))
  278 #define rbskrate(uip, type)  trfrate(uip,(type)&RAPID?RPSEEK:NMSEEK)
  279 #define getparm(type)   ((type<0||type>3)?(struct fddrtab *)ERROR:&m765f[type])
  280 #define relative(s1,s2) ((s1)>(s2)?(s1)-(s2):(s2)-(s1))
  281 
  282 boolean_t fdprobe(
  283         vm_offset_t     port,
  284         struct bus_ctlr *ctlr)
  285 {
  286         int                     spot = STSREG((int) ctlr->address);
  287         struct ctrl_info        *cip = &ctrl_info[ctlr->unit];
  288         int                     i, in;
  289 
  290         outb(spot, DATAOK);
  291         for (i = 1000; i--;) {
  292                 in = inb(spot);
  293                 if ((in&DATAOK) == DATAOK && !(in&0x0f)) {
  294                         take_ctlr_irq(ctlr);
  295                         cip->b_cmd.c_rbmtr = 0;         /* recalibrate/motor flag */
  296                         cip->b_cmd.c_intr = CMDRST;     /* interrupt flag */
  297                         cip->b_unitf = 0;
  298                         cip->b_uip = 0;
  299                         cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
  300                         printf("%s%d: port = %x, spl = %d, pic = %d.\n", ctlr->name,
  301                                 ctlr->unit, ctlr->address, ctlr->sysdep, ctlr->sysdep1);
  302                         return(1);
  303                 }
  304         }
  305         return(0);
  306 }
  307 
  308 int fdslave(
  309         struct bus_device *dev,
  310         vm_offset_t     port)
  311 {
  312         return(1);      /* gross hack */
  313 }
  314 
  315 void fdattach(
  316         struct bus_device *dev)
  317 {
  318         struct unit_info        *uip = &unit_info[dev->unit];
  319         struct ctrl_info        *cip = &ctrl_info[dev->ctlr];
  320 
  321         uip->dev = dev;
  322         dev->address = dev->mi->address;
  323         uip->addr = dev->address;
  324         uip->b_cmd = &cip->b_cmd;
  325         uip->b_seekaddr = 0;
  326         uip->av_forw = 0;
  327         uip->wakeme = 0;
  328         if (cip->b_unitf) {
  329                 uip->b_unitf=cip->b_unitf->b_unitf;
  330                 cip->b_unitf->b_unitf=uip;
  331         } else {
  332                 uip->b_unitf=uip;
  333                 cip->b_unitf=uip;
  334         }
  335         uip->d_drtab.dr_type &= ~OKTYPE; 
  336 
  337         printf(", port = %x, spl = %d, pic = %d.",
  338                 dev->address, dev->sysdep, dev->sysdep1);
  339 
  340         rstout(uip);
  341         specify(uip);
  342 }
  343 /*****************************************************************************
  344  *
  345  * TITLE:       fdopen
  346  *
  347  * ABSTRACT:    Open a unit. 
  348  *
  349  ****************************************************************************/
  350 fdopen(dev, flag, otyp)
  351 dev_t   dev;
  352 int     flag;                   /* not used */
  353 int     otyp;                   /* not used */
  354 {
  355         struct fddrtab          *driv;
  356         struct buf              *wbp;
  357         spl_t                   x = SPL();
  358         int                     error = 0;
  359         int                     unit = UNIT(dev);
  360         struct unit_info        *uip = &unit_info[unit];
  361         int                     slave = uip->dev->slave;
  362         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
  363         struct  fdcmd           *cmdp = uip->b_cmd;
  364         if (unit < MAXUNIT){
  365           /* Since all functions that use this are called from open, we only
  366              set this once, right here. */
  367                 rstout(uip);
  368                 cip->b_wup = uip;
  369                 openchk(cmdp);
  370                 cmdp->c_devflag |= FDMCHK;
  371                 chkbusy(cmdp);
  372                 cmdp->c_stsflag |= MTRFLAG;
  373                 mtr_on(uip);
  374                 if(inb(VFOREG(uip->addr))&OPENBIT || 
  375                    !(uip->d_drtab.dr_type&OKTYPE)){
  376                         uip->d_drtab.dr_type &= ~OKTYPE;
  377                         if(!rbrate(RAPID, uip))
  378                                 fdseek(RAPID, uip, 2);
  379                         if(inb(VFOREG(uip->addr))&OPENBIT)
  380                                 error = ENXIO;
  381                 }
  382                 cmdp->c_stsflag &= ~MTRFLAG;
  383                 mtr_on(uip);
  384                 openfre(cmdp);
  385                 if(!error && !(uip->d_drtab.dr_type & OKTYPE)) {
  386                         if (MEDIATYPE(dev)>3)
  387                                 goto endopen;
  388                         driv = &m765f[MEDIATYPE(dev)];
  389                         wbp = geteblk(BLKSIZE);
  390                         m765sweep(uip, driv);
  391                         cmdp->c_rbmtr &= ~(1<<(RBSHIFT+(slave)));
  392                         ++cip->b_rwerr;
  393                         wbp->b_dev = dev; wbp->b_error = 0; wbp->b_resid = 0;
  394                         wbp->b_flags = (B_READ|B_VERIFY); wbp->b_bcount = 512;
  395                         wbp->b_pfcent = 2*driv->dr_spc + driv->dr_nsec - 1;
  396                         setqueue(wbp, uip);
  397                         biowait(wbp);
  398                         brelse(wbp);
  399                         error = 0;
  400                         uip->d_drtab.dr_type |= OKTYPE;
  401                 }
  402         } else
  403                 error = ENXIO;
  404       endopen:
  405         splx(x);
  406         return(error);
  407 }
  408 /*****************************************************************************
  409  *
  410  * TITLE:       fdclose
  411  *
  412  * ABSTRACT:    Close a unit.
  413  *
  414  *      Called on last close. mark the unit closed and not-ready.
  415  *
  416  *      Unix doesn't actually "open" an inode for rootdev, swapdev or pipedev.
  417  *      If UNIT(swapdev) != UNIT(rootdev), then must add code in init() to 
  418  *      "open" swapdev.  These  devices should never be closed.
  419  *
  420  *****************************************************************************/
  421 fdclose(dev, flag, otyp, offset)
  422 dev_t   dev;            /* major, minor numbers */
  423 int     flag;           /* not used */
  424 int     otyp;           /* not used */
  425 off_t   offset;         /* not used */
  426 {
  427         extern                  dev_t   rootdev, swapdev;
  428         struct unit_info        *uip = &unit_info[UNIT(dev)];
  429         spl_t s;
  430 
  431         /* Clear the bit.
  432          * If last close of drive insure drtab queue is empty before returning.
  433          */
  434         s = SPL();
  435         while(uip->av_forw != 0) {
  436                 uip->wakeme = 1;
  437                 sleep(uip, PRIBIO);
  438         }
  439         splx(s);
  440         return 0;
  441 }
  442 /*****************************************************************************
  443  *
  444  * TITLE:       fdstrategy
  445  *
  446  * ABSTRACT:    Queue an I/O Request, and start it if not busy already.
  447  *
  448  *      Reject request if unit is not-ready.
  449  *
  450  *      Note:   check for not-ready done here ==> could get requests
  451  *              queued prior to unit going not-ready.
  452  *              not-ready status to those requests that are attempted
  453  *              before a new volume is inserted.  Once a new volume is
  454  *              inserted, would get good I/O's to wrong volume.
  455  *
  456  * CALLS:       iodone(),setqueue()
  457  *
  458  * CALLING ROUTINES:    fdread (indirectly, thru physio)
  459  *                      fdwrite (indirectly, thru physio)
  460  *
  461  ****************************************************************************/
  462 fdstrategy(bp)
  463 struct buf *bp; /* buffer header */
  464 {
  465         unsigned                bytes_left;
  466         daddr_t                 secno;
  467         struct unit_info        *uip = &unit_info[UNIT(bp->b_dev)];
  468         struct fddrtab          *dr = &uip->d_drtab;
  469         struct fddrtab          *sdr;
  470 
  471         bp->b_error = 0;
  472         /* set b_resid to b_bcount because we haven't done anything yet */
  473         bp->b_resid = bp->b_bcount;
  474         if (!(dr->dr_type & OKTYPE) || 
  475             ((sdr = getparm(MEDIATYPE(bp->b_dev)))==(struct fddrtab *)ERROR) ||
  476             /* wrong parameters */
  477             (sdr->dr_ncyl != dr->dr_ncyl) || (sdr->dr_nsec != dr->dr_nsec) ||
  478             ((sdr->dr_type|OKTYPE) != dr->dr_type) ||
  479             (sdr->dr_rwgpl != dr->dr_rwgpl) ||
  480             (sdr->dr_fgpl != dr->dr_fgpl)) {
  481                 bp->b_flags |= B_ERROR;
  482                 bp->b_error = EIO;
  483                 biodone(bp);
  484                 return(0);
  485         }
  486         /*
  487          * Figure "secno" from b_blkno. Adjust sector # for partition.
  488          *
  489          * If reading just past the end of the device, it's
  490          * End of File.  If not reading, or if read starts further in
  491          * than the first sector after the partition, it's an error.
  492          *
  493          * secno is logical blockno / # of logical blocks per sector */
  494         secno = (bp->b_blkno * NBPSCTR) >> 9;
  495         if (secno >= dr->p_nsec) {
  496                 if (!((bp->b_flags & B_READ) && (secno == dr->p_nsec))){
  497                         /* off the deep end */
  498                         bp->b_flags |= B_ERROR;
  499                         bp->b_error = ENXIO;
  500                 }
  501                 biodone(bp);
  502                 return(0);
  503         }
  504 /* At this point, it is no longer possible to directly return from strategy.
  505    We now set b_resid to the number of bytes we cannot transfer because
  506    they lie beyond the end of the request's partition.  This value is 0
  507    if the entire request is within the partition. */
  508         bytes_left = (dr->p_nsec - secno) << 9;
  509         bp->b_resid = ((bp->b_bcount<=bytes_left)?0:(bp->b_bcount-bytes_left));
  510         bp->b_pfcent = secno;
  511         setqueue(bp, uip);
  512         return(0);
  513 }
  514 
  515 /***************************************************************************
  516  *
  517  *      set queue to buffer
  518  *
  519  ***************************************************************************/
  520 setqueue(bp, uip)
  521 struct buf *bp;
  522 struct unit_info *uip;
  523 {
  524         spl_t                   x = SPL();
  525         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
  526         struct  fdcmd           *cmdp = uip->b_cmd;
  527 
  528         openchk(cmdp);          /* openning check */
  529         cmdp->c_devflag |= STRCHK;
  530         fd_disksort(uip, bp);   /* queue the request */
  531         /*
  532          * If no requests are in progress, start this one up.  Else
  533          * leave it on the queue, and fdintr will call m765io later.
  534          */
  535         if(!cip->b_uip)
  536                 m765io(uip);
  537         splx(x);
  538 }
  539 /***************************************************************************
  540  *
  541  *      check io_busy routine
  542  *
  543  ***************************************************************************/
  544 chkbusy(cmdp)
  545 struct  fdcmd   *cmdp;
  546 {
  547         while(cmdp->c_devflag & STRCHK){
  548                 cmdp->c_devflag |= STRWAIT;
  549                 sleep(&cmdp->c_devflag,PZERO);
  550         } 
  551 }
  552 /***************************************************************************
  553  *
  554  *      check fdopen() routine
  555  *
  556  ***************************************************************************/
  557 openchk(cmdp)
  558 struct  fdcmd   *cmdp;
  559 {
  560         while(cmdp->c_devflag & FDMCHK ){
  561                 cmdp->c_devflag |= FDWAIT;
  562                 sleep(&cmdp->c_devflag,PZERO);
  563         } 
  564 }
  565 /***************************************************************************
  566  *
  567  *      free fdopen() routine
  568  *
  569  ***************************************************************************/
  570 openfre(cmdp)
  571 struct  fdcmd   *cmdp;
  572 {
  573         cmdp->c_devflag &= ~FDMCHK;
  574         if(cmdp->c_devflag & FDWAIT){
  575                 cmdp->c_devflag &= ~FDWAIT;
  576                 wakeup(&cmdp->c_devflag);
  577         }
  578 }
  579 /*****************************************************************************
  580  *
  581  * TITLE:       m765io
  582  *
  583  * ABSTRACT:    Start handling an I/O request.
  584  *
  585  ****************************************************************************/
  586 m765io(uip)
  587 struct unit_info *uip;
  588 {
  589         register struct buf *bp;
  590         struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
  591 
  592         bp = uip->av_forw; /*move bp to ctrl_info[ctrl].b_buf*/
  593         cip->b_buf = bp;
  594         cip->b_uip = uip;
  595         cip->b_xferaddr  = bp->b_un.b_addr;
  596         cip->b_xfercount = bp->b_bcount - bp->b_resid;
  597         cip->b_sector    = bp->b_pfcent;
  598         uip->b_cmd->c_stsflag |= MTRFLAG;
  599         if(!mtr_start(uip))
  600                 timeout(m765iosub, uip, hz);
  601         else
  602                 m765iosub(uip);
  603 }
  604 /****************************************************************************
  605  *
  606  *      m765io subroutine
  607  *
  608  ****************************************************************************/
  609 void m765iosub(
  610         struct unit_info *uip)
  611 {
  612         struct fddrtab          *dr = &uip->d_drtab;
  613         int                     startsec;
  614         int                     slave = uip->dev->slave;
  615         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
  616         struct  fdcmd           *cmdp = uip->b_cmd;
  617 
  618         rwcmdset(uip);
  619         if(cip->b_buf->b_flags&B_FORMAT)
  620                 goto skipchk;
  621         startsec = (cmdp->c_rwdata[3] * dr->dr_nsec) + cmdp->c_rwdata[4];
  622         if(startsec+(cip->b_xfercount>>9)-1 > dr->dr_spc)
  623                 cip->b_xferdma = (dr->dr_spc-startsec+1) << 9;
  624         else
  625 skipchk:        cip->b_xferdma = cip->b_xfercount;
  626         if(!(cmdp->c_rbmtr & (1<<(RBSHIFT+slave))))
  627                 cip->b_status = rbirate(uip);
  628         else if(uip->b_seekaddr != cmdp->c_saddr)
  629                 cip->b_status = fdiseek(uip,cmdp->c_saddr);
  630         else
  631                 cip->b_status = outicmd(uip);
  632         if(cip->b_status)
  633                 intrerr0(uip);
  634         return;
  635 }
  636 /***************************************************************************
  637  *
  638  *      read / write / format / verify command set to command table
  639  *
  640  ***************************************************************************/
  641 rwcmdset(uip)
  642 struct unit_info *uip;
  643 {
  644         short                   resid;
  645         int                     slave = uip->dev->slave;
  646         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
  647         struct fdcmd            *cmdp = uip->b_cmd;
  648 
  649         switch(cip->b_buf->b_flags&(B_FORMAT|B_VERIFY|B_READ|B_WRITE)){
  650         case B_VERIFY|B_WRITE:  /* VERIFY after WRITE */
  651                 cmdp->c_rwdata[0] = RDMV;
  652                 break;
  653         case B_FORMAT:
  654                 cmdp->c_dcount = FMTCNT; 
  655                 cmdp->c_rwdata[0] = FMTM;
  656                 cmdp->c_saddr = cip->b_sector / uip->d_drtab.dr_spc;
  657                 resid = cip->b_sector % uip->d_drtab.dr_spc;
  658                 cmdp->c_rwdata[1] = slave|((resid/uip->d_drtab.dr_nsec)<<2);
  659                 cmdp->c_rwdata[2] = 
  660                         ((struct fmttbl *)cip->b_buf->b_un.b_addr)->s_type;
  661                 cmdp->c_rwdata[3] = uip->d_drtab.dr_nsec;
  662                 cmdp->c_rwdata[4] = uip->d_drtab.dr_fgpl;
  663                 cmdp->c_rwdata[5] = FMTDATA;
  664                 break;
  665         case B_WRITE:
  666         case B_READ:
  667         case B_READ|B_VERIFY:
  668                 cmdp->c_dcount = RWCNT;
  669                 if(cip->b_buf->b_flags&B_READ)
  670                         if(cip->b_buf->b_flags&B_VERIFY)
  671                                 cmdp->c_rwdata[0] = RDMV;
  672                         else
  673                                 cmdp->c_rwdata[0] = RDM;
  674                 else
  675                         cmdp->c_rwdata[0] = WTM;        /* format or write */
  676                 resid = cip->b_sector % uip->d_drtab.dr_spc;
  677                 cmdp->c_rwdata[3] = resid / uip->d_drtab.dr_nsec;
  678                 cmdp->c_rwdata[1] = slave|(cmdp->c_rwdata[3]<<2);
  679                 cmdp->c_rwdata[2] = cmdp->c_saddr = 
  680                         cip->b_sector / uip->d_drtab.dr_spc;
  681                 cmdp->c_rwdata[4] = (resid % uip->d_drtab.dr_nsec) + 1;
  682                 cmdp->c_rwdata[5] = 2;
  683                 cmdp->c_rwdata[6] = uip->d_drtab.dr_nsec;
  684                 cmdp->c_rwdata[7] = uip->d_drtab.dr_rwgpl;
  685                 cmdp->c_rwdata[8] = DTL;
  686                 D(printf("SET %x %x C%x H%x S%x %x %x %x %x ",
  687                         cmdp->c_rwdata[0], cmdp->c_rwdata[1],
  688                         cmdp->c_rwdata[2], cmdp->c_rwdata[3],
  689                         cmdp->c_rwdata[4], cmdp->c_rwdata[5],
  690                         cmdp->c_rwdata[6], cmdp->c_rwdata[7],
  691                         cmdp->c_rwdata[8]));
  692                 break;
  693         }
  694 }
  695 /*****************************************************************************
  696  *
  697  * TITLE:       fdread
  698  *
  699  * ABSTRACT:    "Raw" read.  Use physio().
  700  *
  701  * CALLS:       m765breakup (indirectly, thru physio)
  702  *
  703  ****************************************************************************/
  704 fdread(dev, uio)
  705 register dev_t  dev;
  706 struct uio *uio;
  707 { 
  708         /* no need for page-size restriction */
  709         return block_io(fdstrategy, minphys, uio);
  710 }
  711 /*****************************************************************************
  712  *
  713  * TITLE:       fdwrite
  714  *
  715  * ABSTRACT:    "Raw" write.  Use physio().
  716  *
  717  * CALLS:       m765breakup (indirectly, thru physio)
  718  *
  719  ****************************************************************************/
  720 fdwrite(dev, uio)
  721 register dev_t  dev;
  722 struct uio *uio;
  723 {
  724         /* no need for page-size restriction */
  725         return block_io(fdstrategy, minphys, uio);
  726 }
  727 
  728 /* IOC_OUT only and not IOC_INOUT */
  729 io_return_t fdgetstat(dev, flavor, data, count)
  730         dev_t           dev;
  731         int             flavor;
  732         int *           data;           /* pointer to OUT array */
  733         natural_t       *count;         /* OUT */
  734 {
  735         switch (flavor) {
  736 
  737         /* Mandatory flavors */
  738 
  739         case DEV_GET_SIZE: {
  740                 int ret;
  741                 struct disk_parms       p;
  742 
  743                 ret = fd_getparms(dev, &p);
  744                 if (ret) return ret;
  745                 data[DEV_GET_SIZE_DEVICE_SIZE] = p.dp_pnumsec * NBPSCTR;
  746                 data[DEV_GET_SIZE_RECORD_SIZE] = NBPSCTR;
  747                 *count = DEV_GET_SIZE_COUNT;
  748                 break;
  749         }
  750 
  751         /* Extra flavors */
  752 
  753         case V_GETPARMS:
  754                 if (*count < sizeof (struct disk_parms)/sizeof (int))
  755                         return (D_INVALID_OPERATION);
  756                 *count = sizeof (struct disk_parms)/sizeof(int);
  757                 return (fd_getparms(dev, data));
  758         default:
  759                 return (D_INVALID_OPERATION);
  760         }
  761 }
  762 /* IOC_VOID or IOC_IN or IOC_INOUT */
  763 /*ARGSUSED*/
  764 io_return_t fdsetstat(dev, flavor, data, count)
  765         dev_t           dev;
  766         int             flavor;
  767         int *           data;
  768         unsigned int    count;
  769 {
  770         int                     unit = UNIT(dev);
  771         switch (flavor) {
  772         case V_SETPARMS:    /* Caller wants reset_parameters */
  773                 return(fd_setparms(unit,*(int *)data));
  774         case V_FORMAT:
  775                 return(fd_format(dev,data));
  776         case V_VERIFY:  /* cmdarg : 0 == no verify, 0 != verify */
  777                 m765verify[unit] = *(int *)data;
  778                 return(D_SUCCESS);
  779         default:
  780                 return(D_INVALID_OPERATION);
  781         }
  782 }
  783 
  784 /*
  785  *      Get block size
  786  */
  787 int
  788 fddevinfo(dev, flavor, info)
  789 dev_t   dev;
  790 int     flavor;
  791 char    *info;
  792 {
  793         register struct fddrtab *dr;
  794         register struct fdpart *p;
  795         register int result = D_SUCCESS;
  796 
  797         switch (flavor) {
  798         case D_INFO_BLOCK_SIZE:
  799                 dr = &unit_info[UNIT(dev)].d_drtab;
  800 
  801                 if(dr->dr_type & OKTYPE)
  802                         *((int *) info) =  512;
  803                 else
  804                         result = D_INVALID_OPERATION;
  805 
  806                 break;
  807         default:
  808                 result = D_INVALID_OPERATION;
  809         }
  810 
  811         return(result);
  812 }
  813 /****************************************************************************
  814  *
  815  *      set fd parameters 
  816  *
  817  ****************************************************************************/
  818 int
  819 fd_setparms(unit, cmdarg)
  820 register unsigned int unit;
  821 long cmdarg;
  822 {
  823         struct fddrtab   *fdparm;
  824         spl_t            x;
  825         struct unit_info *uip = &unit_info[unit];
  826         struct  fdcmd    *cmdp = uip->b_cmd;
  827 
  828         cmdp->c_rbmtr &= ~(1<<(RBSHIFT+uip->dev->slave));
  829         if ((fdparm = getparm(MEDIATYPE(cmdarg))) == (struct fddrtab *)ERROR)
  830                 return(EINVAL);
  831         x = SPL();
  832         openchk(cmdp);
  833         cmdp->c_devflag |= FDMCHK;
  834         chkbusy(cmdp);
  835         m765sweep(uip, fdparm);
  836         uip->d_drtab.dr_type |= OKTYPE;
  837         openfre(cmdp);
  838         splx(x);
  839         return(0);
  840 }
  841 /****************************************************************************
  842  *
  843  *      get fd parameters 
  844  *
  845  ****************************************************************************/
  846 int
  847 fd_getparms(dev,cmdarg)
  848 dev_t   dev;            /* major, minor numbers */
  849 int     *cmdarg;
  850 {
  851         struct disk_parms       *diskp = (struct disk_parms *)cmdarg;
  852         register struct fddrtab *dr = &unit_info[UNIT(dev)].d_drtab;
  853 
  854         if(dr->dr_type & OKTYPE){
  855                 diskp->dp_type = DPT_FLOPPY;
  856                 diskp->dp_heads = 2;
  857                 diskp->dp_sectors = dr->dr_nsec;
  858                 diskp->dp_pstartsec = 0;
  859                 diskp->dp_cyls = dr->dr_ncyl;
  860                 diskp->dp_pnumsec = dr->p_nsec;
  861                 return(0);
  862         }
  863         return(ENXIO);
  864 }
  865 /****************************************************************************
  866  *
  867  *      format command
  868  *
  869  ****************************************************************************/
  870 fd_format(dev,cmdarg)
  871 dev_t   dev;            /* major, minor numbers */
  872 int     *cmdarg;
  873 
  874 {
  875         register struct buf     *bp;
  876         register daddr_t        track;
  877         union  io_arg           *varg;
  878         u_short                 num_trks;
  879         register struct fddrtab *dr = &unit_info[UNIT(dev)].d_drtab;
  880 
  881         if(!(dr->dr_type & OKTYPE))
  882                 return(EINVAL); 
  883         varg = (union io_arg *)cmdarg;
  884         num_trks = varg->ia_fmt.num_trks;
  885         track = (daddr_t)(varg->ia_fmt.start_trk*dr->dr_nsec);
  886         if((track + (num_trks*dr->dr_nsec))>dr->p_nsec)
  887                 return(EINVAL);
  888         bp = geteblk(BLKSIZE);          /* get struct buf area */
  889         while (num_trks>0) {
  890                 bp->b_flags &= ~B_DONE;
  891                 bp->b_dev = dev;
  892                 bp->b_error = 0; bp->b_resid = 0;
  893                 bp->b_flags = B_FORMAT; 
  894                 bp->b_bcount = dr->dr_nsec * FMTID;
  895                 bp->b_blkno = (daddr_t)((track << 9) / NBPSCTR);
  896                 if(makeidtbl(bp->b_un.b_addr,dr,
  897                              varg->ia_fmt.start_trk++,varg->ia_fmt.intlv))
  898                         return(EINVAL);
  899                 fdstrategy(bp);
  900                 biowait(bp);
  901                 if(bp->b_error)
  902                         if((bp->b_error == (char)EBBHARD) || 
  903                            (bp->b_error == (char)EBBSOFT))
  904                                 return(EIO);
  905                         else
  906                                 return(bp->b_error);
  907                 num_trks--;
  908                 track += dr->dr_nsec;
  909         }
  910         brelse(bp);
  911         return(0);
  912 }
  913 /****************************************************************************
  914  *
  915  *      make id table for format
  916  *
  917  ****************************************************************************/
  918 makeidtbl(tblpt,dr,track,intlv)
  919 struct fmttbl *tblpt;
  920 struct fddrtab *dr;
  921 unsigned short track;
  922 unsigned short intlv;
  923 {
  924         register int    i,j,secno;
  925 
  926         if(intlv >= dr->dr_nsec)
  927                 return(1);
  928         for(i=0; i<dr->dr_nsec; i++)
  929                 tblpt[i].sector = 0;
  930         for(i=0,j=0,secno=1; i<dr->dr_nsec; i++){
  931                 tblpt[j].cyl = track >> 1;
  932                 tblpt[j].head = track & 1;
  933                 tblpt[j].sector = secno++;
  934                 tblpt[j].s_type = 2;
  935                 if((j+=intlv) < dr->dr_nsec)
  936                         continue;
  937                 for(j-=dr->dr_nsec; j < dr->dr_nsec ; j++)
  938                         if(!tblpt[j].sector)
  939                                 break;
  940         }
  941         return(0);
  942 }
  943 /*****************************************************************************
  944  *
  945  * TITLE:       fdintr
  946  *
  947  * ABSTRACT:    Handle interrupt.
  948  *
  949  *      Interrupt procedure for m765 driver.  Gets status of last
  950  *      operation and performs service function according to the
  951  *      type of interrupt.  If it was an operation complete interrupt,
  952  *      switches on the current driver state and either declares the
  953  *      operation done, or starts the next operation
  954  *
  955  ****************************************************************************/
  956 void fdintr(
  957         int     ctrl)
  958 {
  959         struct unit_info        *uip = ctrl_info[ctrl].b_uip;
  960         struct unit_info        *wup = ctrl_info[ctrl].b_wup;
  961         struct fdcmd            *cmdp = &ctrl_info[ctrl].b_cmd;
  962         if(cmdp->c_stsflag & INTROUT)
  963                 untimeout(fdintr, (void *) ctrl);
  964         cmdp->c_stsflag &= ~INTROUT;    
  965         switch(cmdp->c_intr){
  966         case RWFLAG:
  967                 rwintr(uip);
  968                 break;  
  969         case SKFLAG:
  970         case SKEFLAG|SKFLAG:
  971         case RBFLAG:
  972                 timeout(m765intrsub, uip, SEEKWAIT);
  973                 break;
  974         case WUPFLAG:
  975                 cmdp->c_intr &= ~WUPFLAG;
  976                 wakeup(wup);
  977         }
  978 }
  979 /*****************************************************************************
  980  *
  981  *      interrup subroutine (seek recalibrate)
  982  *
  983  *****************************************************************************/
  984 void m765intrsub(
  985         struct unit_info *uip)
  986 {
  987         struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
  988 
  989         if((cip->b_status = sis(uip))!=  ST0OK)
  990                 switch(uip->b_cmd->c_intr){
  991                 case SKFLAG:
  992                         seekintr(uip);
  993                         break;
  994                 case SKEFLAG|SKFLAG:
  995                         seekintre(uip);
  996                         break;
  997                 case RBFLAG:
  998                         rbintr(uip);
  999                 }
 1000 }
 1001 /*****************************************************************************
 1002  *
 1003  *      read / write / format / verify interrupt routine
 1004  *
 1005  *****************************************************************************/
 1006 rwintr(uip)
 1007 struct unit_info *uip;
 1008 {
 1009         int                     rsult[7];
 1010         register int            rtn, count;
 1011         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1012         struct fdcmd            *cmdp = uip->b_cmd;
 1013 
 1014         cmdp->c_intr &= ~RWFLAG;
 1015         if((cip->b_buf->b_flags&(B_READ|B_VERIFY))!=(B_READ|B_VERIFY))
 1016                 if(inb(VFOREG(uip->addr))&OPENBIT){
 1017                         if(cip->b_buf->b_flags&B_FORMAT){
 1018                                 cip->b_status = TIMEOUT;
 1019                                 intrerr0(uip);
 1020                         } else {
 1021                                 if((inb(STSREG(uip->addr))&ST0OK)!=ST0OK)
 1022                                         printf("%s %d : %s\n",
 1023                                                 fderr,
 1024                                                 uip-unit_info,
 1025                                                 fdmsg[DOORERR]);
 1026                                 rstout(uip);
 1027                                 specify(uip);
 1028                                 cmdp->c_rbmtr &= RBRST;
 1029                                 cmdp->c_intr |= SKEFLAG;
 1030                                 if(cmdp->c_saddr > 2)
 1031                                         fdiseek(uip, cmdp->c_saddr-2);
 1032                                 else
 1033                                         fdiseek(uip, cmdp->c_saddr+2);
 1034                         }
 1035                         return;
 1036                 }
 1037         for( count = 0 ; count < 7 ; count++ ){
 1038                 if(rtn = fdc_sts(FD_ISTS, uip)) /* status check */
 1039                         goto rwend;
 1040                 rsult[count] = inb(DATAREG(uip->addr));
 1041         }
 1042         rtn = 0;
 1043         if(rsult[0]&0xc0){
 1044                 rtn = cmdp->c_rwdata[0]<<8;
 1045                 if(rsult[0]&0x80){ rtn |= FDCERR;   goto rwend; }
 1046                 if(rsult[1]&0x80){ rtn |= NOREC;    goto rwend; }
 1047                 if(rsult[1]&0x20){ rtn |= CRCERR;   goto rwend; }
 1048                 if(rsult[1]&0x10){ rtn |= OVERRUN;  goto rwend; }
 1049                 if(rsult[1]&0x04){ rtn |= NOREC;    goto rwend; }
 1050                 if(rsult[1]&0x02){ rtn |= WTPRT;    goto rwend; }
 1051                 if(rsult[1]&0x01){ rtn |= ADDRERR;  goto rwend; }
 1052                 rtn |= FDCERR;
 1053 rwend:          outb(0x0a, 0x06);
 1054         }
 1055         if(cip->b_status = rtn) {
 1056                 D(printf("\n->rwierr %x ", rtn));
 1057                 rwierr(uip);
 1058         } else { /* write command */
 1059                 if(((cip->b_buf->b_flags&(B_FORMAT|B_READ|B_WRITE))==B_WRITE) 
 1060                    && !(cip->b_buf->b_flags & B_VERIFY)) {
 1061                         D(printf("->w/v "));
 1062                         cip->b_buf->b_flags |= B_VERIFY;
 1063                         rwcmdset(uip);
 1064                         if(cip->b_status = outicmd(uip))
 1065                                 intrerr0(uip);
 1066                         return;
 1067                 }
 1068                 /* clear retry count */
 1069                 cip->b_buf->b_flags &= ~B_VERIFY;
 1070                 cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
 1071                 cip->b_xfercount -= cip->b_xferdma;
 1072                 cip->b_xferaddr += cip->b_xferdma;
 1073                 cip->b_sector = cip->b_sector+(cip->b_xferdma>>9);
 1074                 D(printf("->done%s\n", cip->b_xfercount?"":"." ));
 1075                 /* next address (cyl,head,sec) */
 1076                 if((int)cip->b_xfercount>0)
 1077                         m765iosub(uip);
 1078                 else
 1079                         quechk(uip);
 1080         }
 1081 }
 1082 /*****************************************************************************
 1083  *
 1084  *      read / write / format / verify error routine
 1085  *
 1086  *****************************************************************************/
 1087 rwierr(uip)
 1088 struct unit_info *uip;
 1089 {
 1090         short                   status;
 1091         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1092         struct  fdcmd           *cmdp = uip->b_cmd;
 1093 
 1094         D(printf("%x-%x-%x ", cip->b_rwerr&SRMASK, cip->b_rwerr&MRMASK, cip->b_rwerr&LRMASK));
 1095         if((cip->b_buf->b_flags&(B_READ|B_VERIFY))==(B_READ|B_VERIFY)){
 1096                 if((cip->b_rwerr&SRMASK)<MEDIARD)
 1097                         goto rwrtry;
 1098                 if((cip->b_rwerr&MRMASK)<MEDIASEEK)
 1099                         goto rwseek;
 1100                 goto rwexit;
 1101         } else
 1102                 if(cip->b_buf->b_flags&B_VERIFY){
 1103                         cip->b_buf->b_flags &= ~B_VERIFY;
 1104                         rwcmdset(uip);
 1105                 }
 1106 rwrtry: status = cip->b_status;
 1107         if((++cip->b_rwerr&SRMASK)<SRETRY)
 1108                 cip->b_status = outicmd(uip);
 1109         else {
 1110 rwseek:         cip->b_rwerr = (cip->b_rwerr&RMRMASK)+MINC;
 1111                 if((cip->b_rwerr&MRMASK)<MRETRY){
 1112                         cmdp->c_intr |= SKEFLAG;
 1113                         if(cmdp->c_saddr > 2)
 1114                                 cip->b_status=fdiseek(uip,cmdp->c_saddr-2);
 1115                         else
 1116                                 cip->b_status=fdiseek(uip,cmdp->c_saddr+2);
 1117                 } else {
 1118                         cip->b_rwerr = (cip->b_rwerr&LRMASK)+LINC;
 1119                         if((cip->b_rwerr&LRMASK)<LRETRY)
 1120                                 cip->b_status=rbirate(uip);
 1121                 }
 1122         }
 1123         if(cip->b_status){
 1124                 D(printf("ERR->intrerr0 "));
 1125                 cip->b_status = status;
 1126 rwexit:         intrerr0(uip);
 1127         }
 1128 }
 1129 /*****************************************************************************
 1130  *
 1131  *      recalibrate interrupt routine
 1132  *
 1133  *****************************************************************************/
 1134 rbintr(uip)
 1135 struct unit_info *uip;
 1136 {
 1137         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1138         struct fdcmd            *cmdp = uip->b_cmd;
 1139 
 1140         cmdp->c_intr &= ~RBFLAG;
 1141         if(cip->b_status) {
 1142                 if(++cip->b_rberr<SRETRY)
 1143                         cip->b_status = rbirate(uip);
 1144         } else {
 1145                 cmdp->c_rbmtr |= 1<<(RBSHIFT+uip->dev->slave);
 1146                 uip->b_seekaddr = 0;
 1147                 cip->b_rberr = 0;
 1148                 cip->b_status=fdiseek(uip, cmdp->c_saddr);
 1149         }
 1150         if(cip->b_status)
 1151                 intrerr0(uip);
 1152 }
 1153 /******************************************************************************
 1154  *
 1155  *      seek interrupt routine
 1156  *
 1157  *****************************************************************************/
 1158 seekintr(uip)
 1159 struct unit_info *uip;
 1160 {
 1161         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1162         struct fdcmd            *cmdp = uip->b_cmd;
 1163 
 1164         cmdp->c_intr &= ~SKFLAG;
 1165         if(cip->b_status)
 1166                 seekierr(uip, cmdp->c_saddr);
 1167         else {
 1168                 uip->b_seekaddr = cmdp->c_saddr;
 1169                 cip->b_status = outicmd(uip);
 1170         }
 1171         if(cip->b_status)
 1172                 intrerr0(uip);
 1173         else
 1174                 cip->b_seekerr = 0;
 1175 }
 1176 /*****************************************************************************
 1177  *
 1178  *      seek error retry interrupt routine
 1179  *
 1180  *****************************************************************************/
 1181 seekintre(uip)
 1182 struct unit_info *uip;
 1183 {
 1184         register char           seekpoint;
 1185         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1186         struct fdcmd            *cmdp = uip->b_cmd;
 1187 
 1188         cmdp->c_intr &= ~(SKEFLAG|SKFLAG);
 1189         if(cmdp->c_saddr > 2)
 1190                 seekpoint = cmdp->c_saddr-2;
 1191         else
 1192                 seekpoint = cmdp->c_saddr+2;
 1193         if(cip->b_status)
 1194                 seekierr(uip, seekpoint);
 1195         else {
 1196                 uip->b_seekaddr = seekpoint;
 1197                 cip->b_status = fdiseek(uip, cmdp->c_saddr);
 1198         }
 1199         if(cip->b_status)
 1200                 intrerr0(uip);
 1201         else
 1202                 cip->b_seekerr = 0;
 1203 }
 1204 /*****************************************************************************
 1205  *
 1206  *      seek error routine
 1207  *
 1208  *****************************************************************************/
 1209 seekierr(uip, seekpoint)
 1210 struct unit_info *uip;
 1211 register char           seekpoint;
 1212 {
 1213         struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
 1214 
 1215         if((++cip->b_seekerr&SRMASK)<SRETRY)
 1216                 cip->b_status=fdiseek(uip, seekpoint);
 1217         else {
 1218                 cip->b_seekerr = (cip->b_seekerr&MRMASK) + MINC;
 1219                 if((cip->b_seekerr&MRMASK)<MRETRY)
 1220                         cip->b_status=rbirate(uip);
 1221         }
 1222         if(cip->b_status)
 1223                 intrerr0(uip);
 1224 }
 1225 /*****************************************************************************
 1226  *
 1227  * TITLE:       m765sweep
 1228  *
 1229  * ABSTRACT:    Perform an initialization sweep.  
 1230  *
 1231  **************************************************************************/
 1232 m765sweep(uip, cdr)
 1233 struct unit_info *uip;
 1234 register struct fddrtab  *cdr;  /* device initialization data */
 1235 {
 1236         register struct fddrtab *dr = &uip->d_drtab;
 1237 
 1238         dr->dr_ncyl = cdr->dr_ncyl;
 1239         dr->dr_nsec = cdr->dr_nsec;
 1240         dr->dr_spc  = cdr->dr_spc;
 1241         dr->p_nsec  = cdr->p_nsec;
 1242         dr->dr_type = cdr->dr_type;
 1243         dr->dr_rwgpl= cdr->dr_rwgpl;
 1244         dr->dr_fgpl = cdr->dr_fgpl;
 1245 }
 1246 /*****************************************************************************
 1247  *
 1248  *  TITLE:  m765disksort
 1249  *
 1250  *****************************************************************************/
 1251 fd_disksort(uip, bp)
 1252 struct unit_info *uip;          /*  Pointer to head of active queue     */
 1253 register struct buf *bp;        /*  Pointer to buffer to be inserted    */
 1254 {
 1255         register struct buf *bp2; /*  Pointer to next buffer in queue   */
 1256         register struct buf *bp1; /*  Pointer where to insert buffer    */
 1257 
 1258         if (!(bp1 = uip->av_forw)) {
 1259                 /* No other buffers to compare against */
 1260                 uip->av_forw = bp;
 1261                 bp->av_forw = 0;
 1262                 return;
 1263         }
 1264         bp2 = bp1->av_forw;
 1265         while(bp2 && (relative(bp1->b_pfcent,bp->b_pfcent) >=
 1266                       relative(bp1->b_pfcent,bp2->b_pfcent))) {
 1267                 bp1 = bp2;
 1268                 bp2 = bp1->av_forw;
 1269         }
 1270         bp1->av_forw = bp;
 1271         bp->av_forw = bp2;
 1272 }
 1273 /*****************************************************************************
 1274  *
 1275  *      Set Interrupt error and FDC reset
 1276  *
 1277  *****************************************************************************/
 1278 intrerr0(uip)
 1279 struct unit_info *uip;
 1280 {
 1281         struct buf              *bp; /* Pointer to next buffer in queue */
 1282         int                     resid;
 1283         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1284         struct  fdcmd           *cmdp = uip->b_cmd;
 1285         register struct fddrtab *dr = &uip->d_drtab;
 1286 
 1287         if((cip->b_buf->b_flags&(B_READ|B_VERIFY))!=(B_READ|B_VERIFY)){
 1288                 resid = cip->b_xfercount = cip->b_xferdma-1-inb(DMACNT)*0x101;
 1289                 resid = (cip->b_sector + (resid>>9)) % dr->dr_spc;
 1290                 printf("%s %d : %s\n",
 1291                         fderr,
 1292                         uip->dev->slave,
 1293                         fdmsg[cip->b_status&BYTEMASK]);
 1294                 printf("cylinder = %d  ",cmdp->c_saddr);
 1295                 printf("head = %d  sector = %d  byte/sec = %d\n",
 1296                 resid / dr->dr_nsec , (resid % dr->dr_nsec)+1 , 512);
 1297         }
 1298         cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
 1299         cmdp->c_intr = CMDRST;
 1300         if(((cip->b_buf->b_flags&(B_READ|B_VERIFY))!=(B_READ|B_VERIFY)) &&
 1301            uip->dev->slave)
 1302                 dr->dr_type &= ~OKTYPE; 
 1303         bp = cip->b_buf;
 1304         bp->b_flags |= B_ERROR;
 1305         switch(cip->b_status&BYTEMASK){
 1306         case ADDRERR:
 1307         case OVERRUN:
 1308         case FDCERR:
 1309         case TIMEOUT:
 1310                 bp->b_error = EIO;
 1311                 break;
 1312         case WTPRT:
 1313                 bp->b_error = ENXIO;
 1314                 break;
 1315         case NOREC:
 1316                 bp->b_error = EBBHARD;
 1317                 break;
 1318         case CRCERR:
 1319                 bp->b_error = EBBSOFT;
 1320         }
 1321         rstout(uip);
 1322         specify(uip);
 1323         cmdp->c_rbmtr &= RBRST;
 1324         quechk(uip);
 1325 }
 1326 /*****************************************************************************
 1327  *
 1328  *      Next queue check routine
 1329  *
 1330  *****************************************************************************/
 1331 quechk(uip)
 1332 struct unit_info *uip;
 1333 {
 1334         register struct buf     *bp = uip->av_forw;
 1335         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1336         struct unit_info        *loop;
 1337         struct fdcmd            *cmdp = uip->b_cmd;
 1338         /* clear retry count */
 1339         cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
 1340         bp->b_resid = bp->b_resid + cip->b_xfercount;
 1341         uip->av_forw=bp->av_forw;
 1342         if (!uip->av_forw && uip->wakeme) {
 1343                 uip->wakeme = 0;
 1344                 wakeup(uip);
 1345         }
 1346         biodone(bp);
 1347         loop = uip;
 1348         do {
 1349                 loop=loop->b_unitf;
 1350                 if (loop->av_forw) {
 1351                         m765io(loop);
 1352                         return;
 1353                 }
 1354         } while (loop!=uip);
 1355         cip->b_uip = 0;
 1356         cmdp->c_stsflag &= ~MTRFLAG;
 1357         mtr_on(uip);
 1358         cmdp->c_devflag &= ~STRCHK;
 1359         if(cmdp->c_devflag & STRWAIT){
 1360                 cmdp->c_devflag &= ~STRWAIT;
 1361                 wakeup(&cmdp->c_devflag);
 1362         }
 1363 }
 1364 fdprint(dev,str)
 1365 dev_t   dev;
 1366 char    *str;
 1367 {
 1368         printf("floppy disk driver: %s on bad dev %d, partition %d\n",
 1369                         str, UNIT(dev), 0);
 1370 }
 1371 fdsize()
 1372 {
 1373         printf("fdsize()        -- not implemented\n");
 1374 }
 1375 fddump()
 1376 {
 1377         printf("fddump()        -- not implemented\n");
 1378 }
 1379 /*****************************************************************************
 1380  *
 1381  *      fdc reset routine
 1382  *
 1383  *****************************************************************************/
 1384 rstout(uip)
 1385 struct unit_info *uip;
 1386 {
 1387         register int    outd;
 1388 
 1389         outd = ((uip->b_cmd->c_rbmtr&MTRMASK)<<MTR_ON)|uip->dev->slave;
 1390         outb(CTRLREG(uip->addr), outd);
 1391         outd |= FDC_RST;
 1392         outb(CTRLREG(uip->addr), outd);
 1393         outd |= DMAREQ;
 1394         outb(CTRLREG(uip->addr), outd);
 1395 }
 1396 /*****************************************************************************
 1397  *
 1398  *      specify command routine
 1399  *
 1400  *****************************************************************************/
 1401 specify(uip)
 1402 struct unit_info *uip;
 1403 {
 1404         /* status check */
 1405         if(fdc_sts(FD_OSTS, uip))
 1406                 return;
 1407         /* Specify command */
 1408         outb(DATAREG(uip->addr), SPCCMD);
 1409         /* status check */
 1410         if(fdc_sts(FD_OSTS, uip))
 1411                 return;
 1412         /* Step rate,Head unload time */
 1413         outb(DATAREG(uip->addr), SRTHUT);
 1414         /* status check */
 1415         if(fdc_sts(FD_OSTS, uip))
 1416                 return;
 1417         /* Head load time,Non DMA Mode*/
 1418         outb(DATAREG(uip->addr), HLTND);
 1419         return;
 1420 }
 1421 /****************************************************************************
 1422  *
 1423  *      recalibrate command routine
 1424  *
 1425  ****************************************************************************/
 1426 rbrate(mtype,uip)
 1427 char     mtype;
 1428 struct unit_info *uip;
 1429 {
 1430         register int    rtn = 1, rty_flg=2;
 1431         spl_t           x;
 1432         struct  fdcmd   *cmdp = uip->b_cmd;
 1433 
 1434         rbskrate(uip, mtype);                   /* set transfer rate */
 1435         while((rty_flg--)&&rtn){
 1436                 if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
 1437                         break;
 1438                 /*recalibrate command*/
 1439                 outb(DATAREG(uip->addr), RBCMD);
 1440                 if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
 1441                         break;
 1442                 /* Device to wake up specified in open */
 1443                 cmdp->c_intr |= WUPFLAG;
 1444                 x = SPL();
 1445                 outb(DATAREG(uip->addr), uip->dev->slave);
 1446                 rtn = ERROR;
 1447                 while(rtn) {
 1448                         uip->wakeme = 1;
 1449                         sleep(uip, PZERO);
 1450                         if((rtn = sis(uip)) == ST0OK)
 1451                           /* Device to wake up specified in open */
 1452                                 cmdp->c_intr |= WUPFLAG;
 1453                         else
 1454                                 break;
 1455                 }
 1456                 splx(x);
 1457         }
 1458         return(rtn);
 1459 }
 1460 /*****************************************************************************
 1461  *
 1462  *      seek command routine
 1463  *
 1464  ****************************************************************************/
 1465 fdseek(mtype, uip, cylno)
 1466 register char   mtype;
 1467 struct unit_info *uip;
 1468 register int    cylno;
 1469 {
 1470         spl_t           x;
 1471         int             rtn;
 1472         struct  fdcmd   *cmdp = uip->b_cmd;
 1473 
 1474         rbskrate(uip, mtype);
 1475         if(rtn = fdc_sts(FD_OSTS, uip))                 /* status check */
 1476                 return(rtn);
 1477         outb(DATAREG(uip->addr), SEEKCMD);              /* seek command */
 1478         if(rtn = fdc_sts(FD_OSTS, uip))                 /* status check */
 1479                 return(rtn);
 1480         outb(DATAREG(uip->addr), uip->dev->slave);      /* drive number */
 1481         if(rtn = fdc_sts(FD_OSTS, uip))                 /* status check */
 1482                 return(rtn);
 1483         x = SPL();
 1484         /* Device to wake up specified in open */
 1485         cmdp->c_intr |= WUPFLAG;
 1486         outb(DATAREG(uip->addr), cylno);                /* seek count */
 1487         rtn = ERROR;
 1488         while(rtn){     
 1489                 uip->wakeme = 1;
 1490                 sleep(uip, PZERO);
 1491                 if((rtn = sis(uip)) == ST0OK)
 1492                   /* Device to wake up specified in open */
 1493                         cmdp->c_intr |= WUPFLAG;
 1494                 else
 1495                         break;
 1496         }
 1497         splx(x);
 1498         return(rtn);
 1499 }
 1500 /*****************************************************************************
 1501  *
 1502  *      seek commnd routine(use interrupt)
 1503  *
 1504  *****************************************************************************/
 1505 fdiseek(uip, cylno) 
 1506 struct unit_info *uip;
 1507 int     cylno;
 1508 {
 1509         register int    rtn;
 1510 
 1511         D(printf("SK %x ", cylno));
 1512         rbskrate(uip, uip->d_drtab.dr_type);/* set transfer rate */
 1513         if(rtn = fdc_sts(FD_OSTS, uip))         /* status check */
 1514                 goto fdiend;
 1515         outb(DATAREG(uip->addr), SEEKCMD);      /* seek command */
 1516         if(rtn = fdc_sts(FD_OSTS, uip))         /* status check */
 1517                 goto fdiend;
 1518         outb(DATAREG(uip->addr), uip->dev->slave);      /* drive number */
 1519         if(rtn = fdc_sts(FD_OSTS, uip))         /* status check */
 1520                 goto fdiend;
 1521         uip->b_seekaddr = cylno;
 1522         if(uip->d_drtab.dr_type&DOUBLE)
 1523                 cylno = cylno * 2;
 1524         uip->b_cmd->c_intr |= SKFLAG;
 1525         outb(DATAREG(uip->addr), cylno);        /* seek count */
 1526 fdiend: 
 1527         if(rtn)
 1528                 rtn |= SEEKCMD<<8;
 1529         return(rtn);
 1530 }
 1531 /*****************************************************************************
 1532  *
 1533  *      recalibrate command routine(use interrupt)
 1534  *
 1535  *****************************************************************************/
 1536 rbirate(uip)
 1537 struct unit_info *uip;
 1538 {
 1539         register int    rtn;
 1540 
 1541         rbskrate(uip, uip->d_drtab.dr_type);/* set transfer rate */
 1542         if(!(rtn = fdc_sts(FD_OSTS, uip))) {            /* status check */
 1543                 /* recalibrate command */
 1544                 outb(DATAREG(uip->addr), RBCMD);
 1545                 if(!(rtn = fdc_sts(FD_OSTS, uip))) {    /* status check */
 1546                         uip->b_cmd->c_intr |= RBFLAG;
 1547                         outb(DATAREG(uip->addr), uip->dev->slave);
 1548                 }
 1549         }
 1550         return(rtn ? rtn|RBCMD<<8 : 0);
 1551 }
 1552 /*****************************************************************************
 1553  *
 1554  *      read / write / format / verify command out routine(use interrupt)
 1555  *
 1556  *****************************************************************************/
 1557 outicmd(uip)
 1558 struct unit_info *uip;
 1559 {
 1560         int                     rtn;
 1561         register int            *data,cnt0,dmalen;
 1562         register long           address;
 1563         struct ctrl_info        *cip = &ctrl_info[uip->dev->ctlr];
 1564         struct fdcmd            *cmdp = uip->b_cmd;
 1565         spl_t                    x = splhi();
 1566 
 1567         outb(DMACMD1,DMADATA0); /* DMA #1 command register      */
 1568         outb(DMAMSK1,DMADATA1); /* DMA #1 all mask register     */
 1569         /* Perhaps outb(0x0a,0x02); might work better on line above? */
 1570         switch(cmdp->c_rwdata[0]){
 1571         case RDM:
 1572                 D(printf("RDM"));
 1573                 outb(DMABPFF,DMARD);
 1574                 outb(DMAMODE,DMARD);
 1575                 break;
 1576         case WTM:
 1577         case FMTM:
 1578                 D(printf("W"));
 1579                 outb(DMABPFF,DMAWT);
 1580                 outb(DMAMODE,DMAWT);
 1581                 break;
 1582         case RDMV:
 1583                 D(printf("RDMV"));
 1584                 outb(DMABPFF,DMAVRF);
 1585                 outb(DMAMODE,DMAVRF);
 1586         }
 1587         /* get work buffer physical address */
 1588         address = kvtophys((vm_offset_t)cip->b_xferaddr);
 1589         dmalen = i386_trunc_page(address) + I386_PGBYTES - address;
 1590         if ( (cip->b_rwerr&MRMASK) >= 0x10)
 1591                 dmalen = 0x200;
 1592         if (dmalen<=cip->b_xferdma) 
 1593                 cip->b_xferdma = dmalen;
 1594         else
 1595                 dmalen = cip->b_xferdma;
 1596         D(printf(" %x L%x ", address, dmalen));
 1597         /* set buffer address */
 1598         outb(DMAADDR,(int)address&BYTEMASK);
 1599         outb(DMAADDR,(((int)address>>8)&BYTEMASK));
 1600         outb(DMAPAGE,(((int)address>>16)&BYTEMASK));
 1601         /* set transfer count */
 1602         outb(DMACNT,(--dmalen)&BYTEMASK);
 1603         outb(DMACNT,((dmalen>>8)&BYTEMASK));
 1604         outb(DMAMSK,CHANNEL2);
 1605         splx(x);
 1606         trfrate(uip, uip->d_drtab.dr_type);     /* set transfer rate */
 1607         data = &cmdp->c_rwdata[0];
 1608         for(cnt0 = 0; cnt0<cmdp->c_dcount; cnt0++,data++){
 1609                 if(rtn = fdc_sts(FD_OSTS, uip)) /*status check*/
 1610                         break;
 1611                 outb(DATAREG(uip->addr), *data);
 1612         }
 1613         if(!rtn){
 1614                 cmdp->c_intr |= RWFLAG;
 1615                 cmdp->c_stsflag |= INTROUT;
 1616                 cnt0 = ((cip->b_buf->b_flags&(B_READ|B_VERIFY)) ==
 1617                         (B_READ|B_VERIFY))?TOUT:ITOUT;
 1618                 timeout(fdintr,(void *)(int)uip->dev->ctlr,cnt0);
 1619         }
 1620         return(rtn);
 1621 }
 1622 /*****************************************************************************
 1623  *
 1624  *      sense interrupt status routine
 1625  *
 1626  *****************************************************************************/
 1627 sis(uip)
 1628 struct unit_info *uip;
 1629 {
 1630         register int    rtn, st0;
 1631 
 1632         if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
 1633                 return(rtn);
 1634         outb(DATAREG(uip->addr), SISCMD);
 1635         if(rtn = fdc_sts(FD_ISTS, uip)) /* status check */
 1636                 return(rtn);
 1637         st0 = inb(DATAREG(uip->addr)) & ST0OK;  /* get st0 */
 1638         if(rtn = fdc_sts(FD_ISTS, uip)) /* status check */
 1639                 return(rtn);
 1640         inb(DATAREG(uip->addr));        /* get pcn */
 1641         if (st0&(ST0AT|ST0IC))
 1642                 st0 = FDCERR;
 1643         return(st0);
 1644 }
 1645 
 1646 /*****************************************************************************
 1647  *
 1648  *      fdc status get routine
 1649  *
 1650  *****************************************************************************/
 1651 fdc_sts(mode, uip)
 1652 register int    mode;
 1653 struct unit_info *uip;
 1654 {
 1655         register int    ind;
 1656         int             cnt0 = STSCHKCNT;
 1657 
 1658         while(cnt0--)
 1659                 if(((ind=inb(STSREG(uip->addr))) & DATAOK) && 
 1660                    ((ind & DTOCPU) == mode))
 1661                         return(0);
 1662         return(TIMEOUT);
 1663 }
 1664 /*****************************************************************************
 1665  *
 1666  *      motor on routine
 1667  *
 1668  *****************************************************************************/
 1669 mtr_on(uip)
 1670 struct unit_info *uip;
 1671 {
 1672         struct  fdcmd   *cmdp = uip->b_cmd;
 1673 
 1674         if(!(mtr_start(uip))){
 1675                 timeout(wakeup,&cmdp->c_stsflag,hz);
 1676                 sleep(&cmdp->c_stsflag,PZERO);
 1677         }
 1678         cmdp->c_stsflag |= MTROFF;
 1679         timeout(mtr_off,uip,MTRSTOP);
 1680 }
 1681 /*****************************************************************************
 1682  *
 1683  *      motor start routine
 1684  *
 1685  *****************************************************************************/
 1686 mtr_start(uip)
 1687 struct unit_info *uip;
 1688 {
 1689         int             status;
 1690         struct  fdcmd   *cmdp = uip->b_cmd;
 1691         int             slave = uip->dev->slave;
 1692         if(cmdp->c_stsflag & MTROFF){
 1693                 untimeout(mtr_off, uip);
 1694                 cmdp->c_stsflag &= ~MTROFF;
 1695         }
 1696         status = cmdp->c_rbmtr&(1<<slave);
 1697         cmdp->c_rbmtr |= (1<<slave);
 1698         outb(CTRLREG(uip->addr), ((cmdp->c_rbmtr&MTRMASK)<<MTR_ON)|
 1699                                      FDC_RST|slave|DMAREQ);
 1700         return(status);
 1701 }
 1702 /*****************************************************************************
 1703  *
 1704  *      motor off routine
 1705  *
 1706  *****************************************************************************/
 1707 void mtr_off(
 1708         struct unit_info *uip)
 1709 {
 1710         struct  fdcmd   *cmdp = uip->b_cmd;
 1711 
 1712         cmdp->c_stsflag &= ~MTROFF;
 1713         if(!(cmdp->c_stsflag&MTRFLAG)){
 1714                 cmdp->c_rbmtr &= MTRRST;
 1715                 outb(CTRLREG(uip->addr), FDC_RST | DMAREQ);
 1716         }
 1717 }

Cache object: ece10473fca74f7a2337b0dd2437b0c2


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