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/pc98/pc98/wd.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  * William Jolitz.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      from: @(#)wd.c  7.2 (Berkeley) 5/9/91
   37  * $FreeBSD: releng/5.0/sys/pc98/pc98/wd.c 105242 2002-10-16 13:41:12Z phk $
   38  */
   39 
   40 /* TODO:
   41  *      o Bump error count after timeout.
   42  *      o Satisfy ATA timing in all cases.
   43  *      o Finish merging berry/sos timeout code (bump error count...).
   44  *      o Don't use polling except for initialization.  Need to
   45  *        reorganize the state machine.  Then "extra" interrupts
   46  *        shouldn't happen (except maybe one for initialization).
   47  *      o Support extended DOS partitions.
   48  *      o Support swapping to DOS partitions.
   49  *      o Handle bad sectors, clustering, disklabelling, DOS
   50  *        partitions and swapping driver-independently.  Use
   51  *        i386/dkbad.c for bad sectors.  Swapping will need new
   52  *        driver entries for polled reinit and polled write).
   53  */
   54 
   55 #include "wdc.h"
   56 #undef NWD
   57 #define NWD (NWDC * 4)          /* 4 drives per wdc on PC98 */
   58 
   59 #if     NWDC > 0
   60 
   61 #include "opt_hw_wdog.h"
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/kernel.h>
   66 #include <sys/conf.h>
   67 #include <sys/bus.h>
   68 #include <sys/disk.h>
   69 #include <sys/disklabel.h>
   70 #include <sys/diskslice.h>
   71 #include <sys/bio.h>
   72 #include <sys/devicestat.h>
   73 #include <sys/malloc.h>
   74 #include <machine/bootinfo.h>
   75 #include <sys/cons.h>
   76 #include <machine/md_var.h>
   77 #ifdef PC98
   78 #include <pc98/pc98/pc98.h>
   79 #include <pc98/pc98/pc98_machdep.h>
   80 #include <pc98/pc98/epsonio.h>
   81 #else
   82 #include <i386/isa/isa.h>
   83 #endif
   84 #include <i386/isa/isa_device.h>
   85 #include <pc98/pc98/wdreg.h>
   86 #include <sys/syslog.h>
   87 #include <vm/vm.h>
   88 #include <vm/pmap.h>
   89 
   90 #include <pc98/pc98/atapi.h>
   91 
   92 #ifndef COMPAT_OLDISA
   93 #error "The wdc device requires the old isa compatibility shims"
   94 #endif
   95 
   96 extern void wdstart(int ctrlr);
   97 
   98 #ifdef IDE_DELAY
   99 #define TIMEOUT         IDE_DELAY
  100 #else
  101 #define TIMEOUT         10000
  102 #endif
  103 #define RETRIES         5       /* number of retries before giving up */
  104 #define RECOVERYTIME    500000  /* usec for controller to recover after err */
  105 #define MAXTRANSFER     255     /* max size of transfer in sectors */
  106                                 /* correct max is 256 but some controllers */
  107                                 /* can't handle that in all cases */
  108 #define WDOPT_32BIT     0x8000
  109 #define WDOPT_SLEEPHACK 0x4000
  110 #define WDOPT_DMA       0x2000
  111 #define WDOPT_LBA       0x1000
  112 #define WDOPT_FORCEHD(x)        (((x)&0x0f00)>>8)
  113 #define WDOPT_MULTIMASK 0x00ff
  114 
  115 #ifdef PC98
  116 static __inline u_char
  117 epson_errorf(int wdc)
  118 {
  119         u_char  wdc_error;
  120 
  121         outb(wdc, inb(0x82) | 0x40);
  122         wdc_error = (u_char)epson_inb(wdc);
  123         outb(wdc, inb(0x82) & ~0x40);
  124         return ((u_char)wdc_error);
  125 }
  126 #endif
  127 
  128 /*
  129  * Drive states.  Used to initialize drive.
  130  */
  131 
  132 #define CLOSED          0       /* disk is closed. */
  133 #define WANTOPEN        1       /* open requested, not started */
  134 #define RECAL           2       /* doing restore */
  135 #define OPEN            3       /* done with open */
  136 
  137 #define PRIMARY         0
  138 
  139 /*
  140  * Disk geometry.  A small part of struct disklabel.
  141  * XXX disklabel.5 contains an old clone of disklabel.h.
  142  */
  143 struct diskgeom {
  144         u_long  d_secsize;              /* # of bytes per sector */
  145         u_long  d_nsectors;             /* # of data sectors per track */
  146         u_long  d_ntracks;              /* # of tracks per cylinder */
  147         u_long  d_ncylinders;           /* # of data cylinders per unit */
  148         u_long  d_secpercyl;            /* # of data sectors per cylinder */
  149         u_long  d_secperunit;           /* # of data sectors per unit */
  150         u_long  d_precompcyl;           /* XXX always 0 */
  151 };
  152 
  153 /*
  154  * The structure of a disk drive.
  155  */
  156 struct softc {
  157         u_int   dk_bc;          /* byte count left */
  158         short   dk_skip;        /* blocks already transferred */
  159         int     dk_ctrlr;       /* physical controller number */
  160         int     dk_ctrlr_cmd640;/* controller number for CMD640 quirk */
  161         u_int32_t       dk_unit;        /* physical unit number */
  162         u_int32_t       dk_lunit;       /* logical unit number */
  163         u_int32_t       dk_interface;   /* interface (two ctrlrs per interface) */
  164         char    dk_state;       /* control state */
  165         u_char  dk_status;      /* copy of status reg. */
  166         u_char  dk_error;       /* copy of error reg. */
  167         u_char  dk_timeout;     /* countdown to next timeout */
  168         u_int32_t       dk_port;        /* i/o port base */
  169         u_int32_t       dk_altport;     /* altstatus port base */
  170         u_long  cfg_flags;      /* configured characteristics */
  171         short   dk_flags;       /* drive characteristics found */
  172 #define DKFL_SINGLE     0x00004 /* sector at a time mode */
  173 #define DKFL_ERROR      0x00008 /* processing a disk error */
  174 #define DKFL_LABELLING  0x00080 /* readdisklabel() in progress */
  175 #define DKFL_32BIT      0x00100 /* use 32-bit i/o mode */
  176 #define DKFL_MULTI      0x00200 /* use multi-i/o mode */
  177 #define DKFL_BADSCAN    0x00400 /* report all errors */
  178 #define DKFL_USEDMA     0x00800 /* use DMA for data transfers */
  179 #define DKFL_DMA        0x01000 /* using DMA on this transfer-- DKFL_SINGLE
  180                                  * overrides this
  181                                  */
  182 #define DKFL_LBA        0x02000 /* use LBA for data transfers */
  183         struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
  184         unsigned int    dk_multi;       /* multi transfers */
  185         int     dk_currentiosize;       /* current io size */
  186         struct diskgeom dk_dd;  /* device configuration data */
  187         struct diskslices *dk_slices;   /* virtual drives */
  188         void    *dk_dmacookie;  /* handle for DMA services */
  189 
  190         struct devstat dk_stats;        /* devstat entry */
  191 
  192         struct disk disk;
  193 };
  194 
  195 #define WD_COUNT_RETRIES
  196 static int wdtest = 0;
  197 
  198 static struct softc *wddrives[NWD];     /* table of units */
  199 static struct bio_queue_head drive_queue[NWD];  /* head of queue per drive */
  200 static struct {
  201         int     b_active;
  202 } wdutab[NWD];
  203 /*
  204 static struct bio wdtab[NWDC];
  205 */
  206 static struct {
  207         struct  bio_queue_head controller_queue;
  208         int     b_errcnt;
  209         int     b_active;
  210 } wdtab[NWDC];
  211 
  212 struct wddma wddma[NWDC];
  213 
  214 #ifdef notyet
  215 static struct bio rwdbuf[NWD];  /* buffers for raw IO */
  216 #endif
  217 #ifdef PC98
  218 static short wd_ctlr;
  219 static int old_epson_note;
  220 #endif
  221 
  222 static int wdprobe(struct isa_device *dvp);
  223 static int wdattach(struct isa_device *dvp);
  224 static void wdustart(struct softc *du);
  225 static int wdcontrol(struct bio *bp);
  226 static int wdcommand(struct softc *du, u_int cylinder, u_int head,
  227                      u_int sector, u_int count, u_int command);
  228 static int wdsetctlr(struct softc *du);
  229 #if 0
  230 static int wdwsetctlr(struct softc *du);
  231 #endif
  232 static int wdsetmode(int mode, void *wdinfo);
  233 static int wdgetctlr(struct softc *du);
  234 static void wderror(struct bio *bp, struct softc *du, char *mesg);
  235 static void wdflushirq(struct softc *du, int old_ipl);
  236 static int wdreset(struct softc *du);
  237 static void wdsleep(int ctrlr, char *wmesg);
  238 static timeout_t wdtimeout;
  239 static int wdunwedge(struct softc *du);
  240 static int wdwait(struct softc *du, u_char bits_wanted, int timeout);
  241 
  242 struct isa_driver wdcdriver = {
  243         INTR_TYPE_BIO,
  244         wdprobe,
  245         wdattach,
  246         "wdc",
  247 };
  248 COMPAT_ISA_DRIVER(wdc, wdcdriver);
  249 
  250 static  d_open_t        wdopen;
  251 static  d_strategy_t    wdstrategy;
  252 
  253 #define CDEV_MAJOR 3
  254 
  255 static struct cdevsw wd_cdevsw = {
  256         /* open */      wdopen,
  257         /* close */     nullclose,
  258         /* read */      physread,
  259         /* write */     physwrite,
  260         /* ioctl */     noioctl,
  261         /* poll */      nopoll,
  262         /* mmap */      nommap,
  263         /* strategy */  wdstrategy,
  264         /* name */      "wd",
  265         /* maj */       CDEV_MAJOR,
  266         /* dump */      nodump,
  267         /* psize */     nopsize,
  268         /* flags */     D_DISK,
  269 };
  270 
  271 static struct cdevsw wddisk_cdevsw;
  272 
  273 static int      atapictrlr;
  274 static int      eide_quirks;
  275 
  276 
  277 /*
  278  *  Here we use the pci-subsystem to find out, whether there is
  279  *  a cmd640b-chip attached on this pci-bus. This public routine
  280  *  will be called by ide_pci.c
  281  */
  282 
  283 void
  284 wdc_pci(int quirks)
  285 {
  286         eide_quirks = quirks;
  287 }
  288 
  289 /*
  290  * Probe for controller.
  291  */
  292 static int
  293 wdprobe(struct isa_device *dvp)
  294 {
  295         int     unit = dvp->id_unit;
  296         int     interface;
  297         struct softc *du;
  298 
  299         if (unit >= NWDC)
  300                 return (0);
  301 
  302         du = malloc(sizeof *du, M_TEMP, M_NOWAIT | M_ZERO);
  303         if (du == NULL)
  304                 return (0);
  305         du->dk_ctrlr = dvp->id_unit;
  306         interface = du->dk_ctrlr / 2;
  307         du->dk_interface = interface;
  308         du->dk_port = dvp->id_iobase;
  309         if (wddma[interface].wdd_candma != NULL) {
  310                 du->dk_dmacookie =
  311                     wddma[interface].wdd_candma(dvp->id_iobase, du->dk_ctrlr,
  312                     du->dk_unit);
  313                 du->dk_altport =
  314                     wddma[interface].wdd_altiobase(du->dk_dmacookie);
  315         }
  316         if (du->dk_altport == 0)
  317                 du->dk_altport = du->dk_port + wd_ctlr;
  318 
  319         /* check if we have registers that work */
  320 #ifdef PC98
  321         /* XXX ATAPI support isn't imported */
  322         wd_ctlr = wd_ctlr_nec;          /* wdreg.h */
  323         old_epson_note=0;
  324 
  325         if (pc98_machine_type & M_EPSON_PC98 ) {
  326             switch (epson_machine_id) {
  327               case 0x20: case 0x22: case 0x2a:  /* note A/W/WR */
  328                 du->dk_port = IO_WD1_EPSON;     /* pc98.h */
  329                 dvp->id_iobase = IO_WD1_EPSON;  /* pc98.h */
  330                 wd_ctlr = wd_ctlr_epson;        /* wdreg.h */
  331                 old_epson_note = 1;             /* for OLD EPSON NOTE */
  332                 break;
  333               default:
  334                 break;
  335             }
  336         }
  337         du->dk_altport = du->dk_port + wd_ctlr;
  338 #if 0
  339         if ((PC98_SYSTEM_PARAMETER(0x55d) & 3) == 0) {
  340                 goto nodevice;
  341         }
  342 #endif
  343         outb(0x432,(du->dk_unit)%2);
  344 #else /* IBM-PC */
  345         outb(du->dk_port + wd_sdh, WDSD_IBM);   /* set unit 0 */
  346         outb(du->dk_port + wd_cyl_lo, 0xa5);    /* wd_cyl_lo is read/write */
  347         if (inb(du->dk_port + wd_cyl_lo) == 0xff) {     /* XXX too weak */
  348                 /* There is no master, try the ATAPI slave. */
  349                 du->dk_unit = 1;
  350                 outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10);
  351                 outb(du->dk_port + wd_cyl_lo, 0xa5);
  352                 if (inb(du->dk_port + wd_cyl_lo) == 0xff)
  353                         goto nodevice;
  354         }
  355 #endif /* PC98 */
  356 
  357         if (wdreset(du) == 0)
  358                 goto reset_ok;
  359         /* test for ATAPI signature */
  360         outb(du->dk_port + wd_sdh, WDSD_IBM);           /* master */
  361         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
  362             inb(du->dk_port + wd_cyl_hi) == 0xeb)
  363                 goto reset_ok;
  364 #ifdef PC98
  365         du->dk_unit = 2;
  366 #else
  367         du->dk_unit = 1;
  368 #endif
  369         outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); /* slave */
  370         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
  371             inb(du->dk_port + wd_cyl_hi) == 0xeb)
  372                 goto reset_ok;
  373 #ifdef PC98
  374         du->dk_unit = 1;
  375         outb(0x432,(du->dk_unit)%2);
  376         if (wdreset(du) == 0)
  377                 goto reset_ok;
  378         /* test for ATAPI signature */
  379         outb(du->dk_port + wd_sdh, WDSD_IBM);           /* master */
  380         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
  381             inb(du->dk_port + wd_cyl_hi) == 0xeb)
  382                 goto reset_ok;
  383         du->dk_unit = 3;
  384         outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); /* slave */
  385         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
  386             inb(du->dk_port + wd_cyl_hi) == 0xeb)
  387                 goto reset_ok;
  388 #endif
  389         DELAY(RECOVERYTIME);
  390         if (wdreset(du) != 0) {
  391                 goto nodevice;
  392         }
  393 reset_ok:
  394 
  395         /* execute a controller only command */
  396         if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
  397             || wdwait(du, 0, TIMEOUT) < 0) {
  398                 goto nodevice;
  399         }
  400 
  401         /*
  402          * drive(s) did not time out during diagnostic :
  403          * Get error status and check that both drives are OK.
  404          * Table 9-2 of ATA specs suggests that we must check for
  405          * a value of 0x01
  406          *
  407          * Strangely, some controllers will return a status of
  408          * 0x81 (drive 0 OK, drive 1 failure), and then when
  409          * the DRV bit is set, return status of 0x01 (OK) for
  410          * drive 2.  (This seems to contradict the ATA spec.)
  411          */
  412         if (old_epson_note)
  413                 du->dk_error = epson_errorf(du->dk_port + wd_error);
  414         else
  415                 du->dk_error = inb(du->dk_port + wd_error);
  416 
  417         if(du->dk_error != 0x01 && du->dk_error != 0) {
  418                 if(du->dk_error & 0x80) { /* drive 1 failure */
  419 
  420                         /* first set the DRV bit */
  421                         u_int sdh;
  422                         if (old_epson_note)
  423                                 sdh = epson_inb(du->dk_port+ wd_sdh);
  424                         else
  425                                 sdh = inb(du->dk_port+ wd_sdh);
  426                         sdh = sdh | 0x10;
  427                         if (old_epson_note)
  428                                 epson_outb(du->dk_port+ wd_sdh, sdh);
  429                         else
  430                                 outb(du->dk_port+ wd_sdh, sdh);
  431 
  432                         /* Wait, to make sure drv 1 has completed diags */
  433                         if ( wdwait(du, 0, TIMEOUT) < 0)
  434                                 goto nodevice;
  435 
  436                         /* Get status for drive 1 */
  437                         if (old_epson_note)
  438                                 du->dk_error = 
  439                                         epson_errorf(du->dk_port + wd_error); 
  440                         else
  441                                 du->dk_error = inb(du->dk_port + wd_error); 
  442                         /* printf("Error (drv 1) : %x\n", du->dk_error); */
  443                         /*
  444                          * Sometimes (apparently mostly with ATAPI
  445                          * drives involved) 0x81 really means 0x81
  446                          * (drive 0 OK, drive 1 failed).
  447                          */
  448                         if(du->dk_error != 0x01 && du->dk_error != 0x81)
  449                                 goto nodevice;
  450                 } else  /* drive 0 fail */
  451                         goto nodevice;
  452         }
  453 
  454 
  455         free(du, M_TEMP);
  456         return (IO_WDCSIZE);
  457 
  458 nodevice:
  459         free(du, M_TEMP);
  460         return (0);
  461 }
  462 
  463 /*
  464  * Attach each drive if possible.
  465  */
  466 static int
  467 wdattach(struct isa_device *dvp)
  468 {
  469         int     unit, lunit, flags, i;
  470         struct softc *du;
  471         struct wdparams *wp;
  472         static char buf[] = "wdcXXX";
  473         const char *dname;
  474         dev_t dev;
  475 
  476         dvp->id_intr = wdintr;
  477 
  478         if (dvp->id_unit >= NWDC)
  479                 return (0);
  480 
  481         if (eide_quirks & Q_CMD640B) {
  482                 if (dvp->id_unit == PRIMARY) {
  483                         printf("wdc0: CMD640B workaround enabled\n");
  484                         bioq_init(&wdtab[PRIMARY].controller_queue);
  485                 }
  486         } else
  487                 bioq_init(&wdtab[dvp->id_unit].controller_queue);
  488 
  489         sprintf(buf, "wdc%d", dvp->id_unit);
  490         i = 0;
  491         while ((resource_find_match(&i, &dname, &lunit, "at", buf)) == 0) {
  492                 if (strcmp(dname, "wd"))
  493                         /* Avoid a bit of foot shooting. */
  494                         continue;
  495 
  496                 if (lunit >= NWD)
  497                         continue;
  498 #ifdef PC98
  499                 if ((lunit%2)!=0) {
  500                         if ((PC98_SYSTEM_PARAMETER(0x457) & 0x40)==0) {
  501                                 continue;
  502                         }
  503                 }
  504 #endif
  505 
  506                 if (resource_int_value("wd", lunit, "drive", &unit) != 0)
  507                         continue;
  508                 if (resource_int_value("wd", lunit, "flags", &flags) != 0)
  509                         flags = 0;
  510 
  511                 du = malloc(sizeof *du, M_TEMP, M_NOWAIT | M_ZERO);
  512                 if (du == NULL)
  513                         continue;
  514                 if (wddrives[lunit] != NULL)
  515                         panic("drive attached twice");
  516                 wddrives[lunit] = du;
  517                 bioq_init(&drive_queue[lunit]);
  518                 du->dk_ctrlr = dvp->id_unit;
  519                 if (eide_quirks & Q_CMD640B) {
  520                         du->dk_ctrlr_cmd640 = PRIMARY;
  521                 } else {
  522                         du->dk_ctrlr_cmd640 = du->dk_ctrlr;
  523                 }
  524                 du->dk_unit = unit;
  525                 du->dk_lunit = lunit;
  526                 du->dk_port = dvp->id_iobase;
  527 
  528                 du->dk_altport = du->dk_port + wd_ctlr;
  529                 /*
  530                  * Use the individual device flags or the controller
  531                  * flags.
  532                  */
  533                 du->cfg_flags = flags |
  534                         ((dvp->id_flags) >> (16 * unit));
  535 
  536                 if (wdgetctlr(du) == 0) {
  537                         /*
  538                          * Print out description of drive.
  539                          * wdp_model may not be null terminated.
  540                          */
  541                         printf("wdc%d: unit %d (wd%d): <%.*s>",
  542                                 dvp->id_unit, unit, lunit,
  543                                 (int)sizeof(du->dk_params.wdp_model),
  544                                 du->dk_params.wdp_model);
  545                         if (du->dk_flags & DKFL_LBA)
  546                                 printf(", LBA");
  547                         if (du->dk_flags & DKFL_USEDMA)
  548                                 printf(", DMA");
  549                         if (du->dk_flags & DKFL_32BIT)
  550                                 printf(", 32-bit");
  551                         if (du->dk_multi > 1)
  552                                 printf(", multi-block-%d", du->dk_multi);
  553                         if (du->cfg_flags & WDOPT_SLEEPHACK)
  554                                 printf(", sleep-hack");
  555                         printf("\n");
  556                         if (du->dk_params.wdp_heads == 0)
  557                                 printf("wd%d: size unknown, using %s values\n",
  558                                        lunit, du->dk_dd.d_secperunit > 17
  559                                               ? "BIOS" : "fake");
  560                         printf( "wd%d: %luMB (%lu sectors), "
  561                                 "%lu cyls, %lu heads, %lu S/T, %lu B/S\n",
  562                                lunit,
  563                                du->dk_dd.d_secperunit
  564                                / ((1024L * 1024L) / du->dk_dd.d_secsize),
  565                                du->dk_dd.d_secperunit,
  566                                du->dk_dd.d_ncylinders,
  567                                du->dk_dd.d_ntracks,
  568                                du->dk_dd.d_nsectors,
  569                                du->dk_dd.d_secsize);
  570 
  571                         if (bootverbose) {
  572                             wp = &du->dk_params;
  573                             printf( "wd%d: ATA INQUIRE valid = %04x, "
  574                                     "dmamword = %04x, apio = %04x, "
  575                                     "udma = %04x\n",
  576                                 du->dk_lunit,
  577                                 wp->wdp_atavalid,
  578                                 wp->wdp_dmamword,
  579                                 wp->wdp_eidepiomodes,
  580                                 wp->wdp_udmamode);
  581                           }
  582 
  583                         /*
  584                          * Start timeout routine for this drive.
  585                          * XXX timeout should be per controller.
  586                          */
  587                         wdtimeout(du);
  588 
  589                         /*
  590                          * Export the drive to the devstat interface.
  591                          */
  592                         devstat_add_entry(&du->dk_stats, "wd", 
  593                                           lunit, du->dk_dd.d_secsize,
  594                                           DEVSTAT_NO_ORDERED_TAGS,
  595                                           DEVSTAT_TYPE_DIRECT |
  596                                           DEVSTAT_TYPE_IF_IDE,
  597                                           DEVSTAT_PRIORITY_DISK);
  598 
  599                         /*
  600                          * Register this media as a disk
  601                          */
  602                         dev = disk_create(lunit, &du->disk, 0, &wd_cdevsw,
  603                                     &wddisk_cdevsw);
  604                         dev->si_drv1 = du;
  605                         
  606                 } else {
  607                         free(du, M_TEMP);
  608                         wddrives[lunit] = NULL;
  609                 }
  610         }
  611         /*
  612          * Probe all free IDE units, searching for ATAPI drives.
  613          */
  614 #ifdef PC98
  615         for (unit=0; unit<4; ++unit) {
  616                 outb(0x432,unit%2);
  617 #else
  618         for (unit=0; unit<2; ++unit) {
  619 #endif /* PC98 */
  620                 for (lunit=0; lunit<NWD; ++lunit)
  621                         if (wddrives[lunit] &&
  622                             wddrives[lunit]->dk_ctrlr == dvp->id_unit &&
  623                             wddrives[lunit]->dk_unit == unit)
  624                                 goto next;
  625                 if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase))
  626                         atapictrlr = dvp->id_unit;
  627 next: ;
  628         }
  629         /*
  630          * Discard any interrupts generated by wdgetctlr().  wdflushirq()
  631          * doesn't work now because the ambient ipl is too high.
  632          */
  633         if (eide_quirks & Q_CMD640B) {
  634                 wdtab[PRIMARY].b_active = 2;
  635         } else {
  636                 wdtab[dvp->id_unit].b_active = 2;
  637         }
  638 
  639         return (1);
  640 }
  641 
  642 /* Read/write routine for a buffer.  Finds the proper unit, range checks
  643  * arguments, and schedules the transfer.  Does not wait for the transfer
  644  * to complete.  Multi-page transfers are supported.  All I/O requests must
  645  * be a multiple of a sector in length.
  646  */
  647 void
  648 wdstrategy(register struct bio *bp)
  649 {
  650         struct softc *du;
  651         int     lunit;
  652         int     s;
  653 
  654         du = bp->bio_dev->si_drv1;
  655         if (du == NULL ||  bp->bio_blkno < 0 ||
  656             bp->bio_bcount % DEV_BSIZE != 0) {
  657 
  658                 bp->bio_error = EINVAL;
  659                 bp->bio_flags |= BIO_ERROR;
  660                 goto done;
  661         }
  662         lunit = du->dk_lunit;
  663 
  664 #ifdef PC98
  665         outb(0x432,(du->dk_unit)%2);
  666 #endif
  667 
  668         /* queue transfer on drive, activate drive and controller if idle */
  669         s = splbio();
  670 
  671         /* Pick up changes made by readdisklabel(). */
  672         if (du->dk_flags & DKFL_LABELLING && du->dk_state > RECAL) {
  673                 wdsleep(du->dk_ctrlr, "wdlab");
  674                 du->dk_state = WANTOPEN;
  675         }
  676 
  677         bioqdisksort(&drive_queue[lunit], bp);
  678 
  679         if (wdutab[lunit].b_active == 0)
  680                 wdustart(du);   /* start drive */
  681 
  682         if (wdtab[du->dk_ctrlr_cmd640].b_active == 0)
  683                 wdstart(du->dk_ctrlr);  /* start controller */
  684 
  685         /* Tell devstat that we have started a transaction on this drive */
  686         devstat_start_transaction(&du->dk_stats);
  687 
  688         splx(s);
  689         return;
  690 
  691 done:
  692         /* toss transfer, we're done early */
  693         biodone(bp);
  694 }
  695 
  696 /*
  697  * Routine to queue a command to the controller.  The unit's
  698  * request is linked into the active list for the controller.
  699  * If the controller is idle, the transfer is started.
  700  */
  701 static void
  702 wdustart(register struct softc *du)
  703 {
  704         register struct bio *bp;
  705         int     ctrlr = du->dk_ctrlr_cmd640;
  706 
  707 #ifdef PC98
  708         outb(0x432,(du->dk_unit)%2);
  709 #endif
  710         /* unit already active? */
  711         if (wdutab[du->dk_lunit].b_active)
  712                 return;
  713 
  714 
  715         bp = bioq_first(&drive_queue[du->dk_lunit]);
  716         if (bp == NULL) {       /* yes, an assign */
  717                 return;
  718         }
  719         /*
  720          * store away which device we came from.
  721          */
  722         bp->bio_driver1 = du;
  723 
  724         bioq_remove(&drive_queue[du->dk_lunit], bp);
  725 
  726         /* link onto controller queue */
  727         bioq_insert_tail(&wdtab[ctrlr].controller_queue, bp);
  728 
  729         /* mark the drive unit as busy */
  730         wdutab[du->dk_lunit].b_active = 1;
  731 
  732 }
  733 
  734 /*
  735  * Controller startup routine.  This does the calculation, and starts
  736  * a single-sector read or write operation.  Called to start a transfer,
  737  * or from the interrupt routine to continue a multi-sector transfer.
  738  * RESTRICTIONS:
  739  * 1. The transfer length must be an exact multiple of the sector size.
  740  */
  741 
  742 void
  743 wdstart(int ctrlr)
  744 {
  745         register struct softc *du;
  746         register struct bio *bp;
  747         struct diskgeom *lp;    /* XXX sic */
  748         long    blknum;
  749         long    secpertrk, secpercyl;
  750         u_int   lunit;
  751         u_int   count;
  752         int     ctrlr_atapi;
  753 
  754         if (eide_quirks & Q_CMD640B) {
  755                 ctrlr = PRIMARY;
  756                 ctrlr_atapi = atapictrlr;
  757         } else {
  758                 ctrlr_atapi = ctrlr;
  759         }
  760 
  761         if (wdtab[ctrlr].b_active == 2)
  762                 wdtab[ctrlr].b_active = 0;
  763         if (wdtab[ctrlr].b_active)
  764                 return;
  765         /* is there a drive for the controller to do a transfer with? */
  766         bp = bioq_first(&wdtab[ctrlr].controller_queue);
  767         if (bp == NULL) {
  768                 if (atapi_start && atapi_start (ctrlr_atapi))
  769                         /* mark controller active in ATAPI mode */
  770                         wdtab[ctrlr].b_active = 3;
  771                 return;
  772         }
  773 
  774         /* obtain controller and drive information */
  775         du = bp->bio_dev->si_drv1;
  776         lunit = du->dk_lunit;
  777 
  778 #ifdef PC98
  779         outb(0x432,(du->dk_unit)%2);
  780 #endif
  781 
  782         /* if not really a transfer, do control operations specially */
  783         if (du->dk_state < OPEN) {
  784                 if (du->dk_state != WANTOPEN)
  785                         printf("wd%d: wdstart: weird dk_state %d\n",
  786                                du->dk_lunit, du->dk_state);
  787                 if (wdcontrol(bp) != 0)
  788                         printf("wd%d: wdstart: wdcontrol returned nonzero, state = %d\n",
  789                                du->dk_lunit, du->dk_state);
  790                 return;
  791         }
  792 
  793         /* calculate transfer details */
  794         blknum = bp->bio_pblkno + du->dk_skip;
  795 #ifdef WDDEBUG
  796         if (du->dk_skip == 0)
  797                 printf("wd%d: wdstart: %s %d@%d; map ", lunit,
  798                        (bp->bio_cmd == BIO_READ) ? "read" : "write",
  799                        bp->bio_bcount, blknum);
  800         else {
  801                 if (old_epson_note)
  802                         printf(" %d)%x", du->dk_skip, epson_inb(du->dk_altport);
  803                 else
  804                         printf(" %d)%x", du->dk_skip, inb(du->dk_altport);
  805         }
  806 #endif
  807 
  808         lp = &du->dk_dd;
  809         secpertrk = lp->d_nsectors;
  810         secpercyl = lp->d_secpercyl;
  811 
  812         if (du->dk_skip == 0)
  813                 du->dk_bc = bp->bio_bcount;
  814 
  815         wdtab[ctrlr].b_active = 1;      /* mark controller active */
  816 
  817         /* if starting a multisector transfer, or doing single transfers */
  818         if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
  819                 u_int   command;
  820                 u_int   count1;
  821                 long    cylin, head, sector;
  822 
  823                 if (du->dk_flags & DKFL_LBA) {
  824                         sector = (blknum >> 0) & 0xff; 
  825                         cylin = (blknum >> 8) & 0xffff;
  826                         head = ((blknum >> 24) & 0xf) | WDSD_LBA; 
  827                 } else {
  828                         cylin = blknum / secpercyl;
  829                         head = (blknum % secpercyl) / secpertrk;
  830                         sector = blknum % secpertrk;
  831                 }
  832                 /* 
  833                  * XXX this looks like an attempt to skip bad sectors
  834                  * on write.
  835                  */
  836                 if (wdtab[ctrlr].b_errcnt && (bp->bio_cmd == BIO_WRITE))
  837                         du->dk_bc += DEV_BSIZE;
  838 
  839                 count1 = howmany( du->dk_bc, DEV_BSIZE);
  840 
  841                 du->dk_flags &= ~DKFL_MULTI;
  842 
  843                 if (du->dk_flags & DKFL_SINGLE) {
  844                         command = (bp->bio_cmd == BIO_READ)
  845                                   ? WDCC_READ : WDCC_WRITE;
  846                         count1 = 1;
  847                         du->dk_currentiosize = 1;
  848                 } else {
  849                         if((du->dk_flags & DKFL_USEDMA) &&
  850                            wddma[du->dk_interface].wdd_dmaverify(du->dk_dmacookie,
  851                                 (void *)((int)bp->bio_data + 
  852                                      du->dk_skip * DEV_BSIZE),
  853                                 du->dk_bc,
  854                                 bp->bio_cmd == BIO_READ)) {
  855                                 du->dk_flags |= DKFL_DMA;
  856                                 if(bp->bio_cmd == BIO_READ)
  857                                         command = WDCC_READ_DMA;
  858                                 else
  859                                         command = WDCC_WRITE_DMA;
  860                                 du->dk_currentiosize = count1;
  861                         } else if( (count1 > 1) && (du->dk_multi > 1)) {
  862                                 du->dk_flags |= DKFL_MULTI;
  863                                 if(bp->bio_cmd == BIO_READ) {
  864                                         command = WDCC_READ_MULTI;
  865                                 } else {
  866                                         command = WDCC_WRITE_MULTI;
  867                                 }
  868                                 du->dk_currentiosize = du->dk_multi;
  869                                 if( du->dk_currentiosize > count1)
  870                                         du->dk_currentiosize = count1;
  871                         } else {
  872                                 if(bp->bio_cmd == BIO_READ) {
  873                                         command = WDCC_READ;
  874                                 } else {
  875                                         command = WDCC_WRITE;
  876                                 }
  877                                 du->dk_currentiosize = 1;
  878                         }
  879                 }
  880 
  881                 /*
  882                  * XXX this loop may never terminate.  The code to handle
  883                  * counting down of retries and eventually failing the i/o
  884                  * is in wdintr() and we can't get there from here.
  885                  */
  886                 if (wdtest != 0) {
  887                         if (--wdtest == 0) {
  888                                 wdtest = 100;
  889                                 printf("dummy wdunwedge\n");
  890                                 wdunwedge(du);
  891                         }
  892                 }
  893 
  894                 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
  895                         wddma[du->dk_interface].wdd_dmaprep(du->dk_dmacookie,
  896                                            (void *)((int)bp->bio_data + 
  897                                                     du->dk_skip * DEV_BSIZE),
  898                                            du->dk_bc,
  899                                            bp->bio_cmd == BIO_READ);
  900                 }
  901                 while (wdcommand(du, cylin, head, sector, count1, command)
  902                        != 0) {
  903                         wderror(bp, du,
  904                                 "wdstart: timeout waiting to give command");
  905                         wdunwedge(du);
  906                 }
  907 #ifdef WDDEBUG
  908                 printf("cylin %ld head %ld sector %ld addr %x sts ",
  909                        cylin, head, sector,
  910                        (int)bp->bio_data + du->dk_skip * DEV_BSIZE);
  911                 if (old_epson_note)
  912                         printf("%x\n", epson_inb(du->dk_altport));
  913                 else
  914                         printf("%x\n", inb(du->dk_altport));
  915 #endif
  916         }
  917 
  918         /*
  919          * Schedule wdtimeout() to wake up after a few seconds.  Retrying
  920          * unmarked bad blocks can take 3 seconds!  Then it is not good that
  921          * we retry 5 times.
  922          *
  923          * On the first try, we give it 10 seconds, for drives that may need
  924          * to spin up.
  925          *
  926          * XXX wdtimeout() doesn't increment the error count so we may loop
  927          * forever.  More seriously, the loop isn't forever but causes a
  928          * crash.
  929          *
  930          * TODO fix b_resid bug elsewhere (fd.c....).  Fix short but positive
  931          * counts being discarded after there is an error (in physio I
  932          * think).  Discarding them would be OK if the (special) file offset
  933          * was not advanced.
  934          */
  935         if (wdtab[ctrlr].b_errcnt == 0)
  936                 du->dk_timeout = 1 + 10;
  937         else
  938                 du->dk_timeout = 1 + 3;
  939 
  940         /* if this is a DMA op, start DMA and go away until it's done. */
  941         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
  942                 wddma[du->dk_interface].wdd_dmastart(du->dk_dmacookie);
  943                 return;
  944         }
  945 
  946         /* If this is a read operation, just go away until it's done. */
  947         if (bp->bio_cmd == BIO_READ)
  948                 return;
  949 
  950         /* Ready to send data? */
  951         if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) < 0) {
  952                 wderror(bp, du, "wdstart: timeout waiting for DRQ");
  953                 /*
  954                  * XXX what do we do now?  If we've just issued the command,
  955                  * then we can treat this failure the same as a command
  956                  * failure.  But if we are continuing a multi-sector write,
  957                  * the command was issued ages ago, so we can't simply
  958                  * restart it.
  959                  *
  960                  * XXX we waste a lot of time unnecessarily translating block
  961                  * numbers to cylin/head/sector for continued i/o's.
  962                  */
  963         }
  964 
  965         count = 1;
  966         if( du->dk_flags & DKFL_MULTI) {
  967                 count = howmany(du->dk_bc, DEV_BSIZE);
  968                 if( count > du->dk_multi)
  969                         count = du->dk_multi;
  970                 if( du->dk_currentiosize > count)
  971                         du->dk_currentiosize = count;
  972         }
  973         if (!old_epson_note) {
  974                 if (du->dk_flags & DKFL_32BIT)
  975                         outsl(du->dk_port + wd_data,
  976                               (void *)((int)bp->bio_data
  977                                                 + du->dk_skip * DEV_BSIZE),
  978                               (count * DEV_BSIZE) / sizeof(long));
  979                 else
  980                         outsw(du->dk_port + wd_data,
  981                               (void *)((int)bp->bio_data
  982                                                 + du->dk_skip * DEV_BSIZE),
  983                               (count * DEV_BSIZE) / sizeof(short));
  984                 }
  985         else
  986                 epson_outsw(du->dk_port + wd_data,
  987                       (void *)((int)bp->bio_data + du->dk_skip * DEV_BSIZE),
  988                       (count * DEV_BSIZE) / sizeof(short));
  989                 
  990         du->dk_bc -= DEV_BSIZE * count;
  991 }
  992 
  993 /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
  994  * errors on the current operation, mark it done if necessary, and start
  995  * the next request.  Also check for a partially done transfer, and
  996  * continue with the next chunk if so.
  997  */
  998 
  999 void
 1000 wdintr(void *unitnum)
 1001 {
 1002         register struct softc *du;
 1003         register struct bio *bp;
 1004         int dmastat = 0;                        /* Shut up GCC */
 1005         int unit = (int)unitnum;
 1006 
 1007         int ctrlr_atapi;
 1008 
 1009         if (eide_quirks & Q_CMD640B) {
 1010                 unit = PRIMARY;
 1011                 ctrlr_atapi = atapictrlr;
 1012         } else {
 1013                 ctrlr_atapi = unit;
 1014         }
 1015 
 1016         if (wdtab[unit].b_active == 2)
 1017                 return;         /* intr in wdflushirq() */
 1018         if (!wdtab[unit].b_active) {
 1019 #ifdef WDDEBUG
 1020                 /*
 1021                  * These happen mostly because the power-mgt part of the
 1022                  * bios shuts us down, and we just manage to see the
 1023                  * interrupt from the "SLEEP" command.
 1024                  */
 1025                 printf("wdc%d: extra interrupt\n", unit);
 1026 #endif
 1027                 return;
 1028         }
 1029         if (wdtab[unit].b_active == 3) {
 1030                 /* process an ATAPI interrupt */
 1031                 if (atapi_intr && atapi_intr (ctrlr_atapi))
 1032                         /* ATAPI op continues */
 1033                         return;
 1034                 /* controller is free, start new op */
 1035                 wdtab[unit].b_active = 0;
 1036                 wdstart (unit);
 1037                 return;
 1038         }
 1039         bp = bioq_first(&wdtab[unit].controller_queue);
 1040         du = bp->bio_dev->si_drv1;
 1041 
 1042 #ifdef PC98
 1043         outb(0x432,(du->dk_unit)%2);
 1044 #endif
 1045         /* finish off DMA */
 1046         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
 1047                 /* XXX SMP boxes sometimes generate an early intr.  Why? */
 1048                 if ((wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie) & 
 1049                     WDDS_INTERRUPT) == 0)
 1050                         return;
 1051                 dmastat = wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
 1052         }
 1053 
 1054         du->dk_timeout = 0;
 1055 
 1056         /* check drive status/failure */
 1057         if (wdwait(du, 0, TIMEOUT) < 0) {
 1058                 wderror(bp, du, "wdintr: timeout waiting for status");
 1059                 du->dk_status |= WDCS_ERR;      /* XXX */
 1060         }
 1061 
 1062         /* is it not a transfer, but a control operation? */
 1063         if (du->dk_state < OPEN) {
 1064                 wdtab[unit].b_active = 0;
 1065                 switch (wdcontrol(bp)) {
 1066                 case 0:
 1067                         return;
 1068                 case 1:
 1069                         wdstart(unit);
 1070                         return;
 1071                 case 2:
 1072                         goto done;
 1073                 }
 1074         }
 1075 
 1076         /* have we an error? */
 1077         if ((du->dk_status & (WDCS_ERR | WDCS_ECCCOR))
 1078             || (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1079                 && dmastat != WDDS_INTERRUPT)) {
 1080 
 1081                 unsigned int errstat;
 1082 oops:
 1083                 /*
 1084                  * XXX bogus inb() here
 1085                  */
 1086                 errstat = inb(du->dk_port + wd_error);
 1087 
 1088                 if(((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
 1089                    (errstat & WDERR_ABORT)) {
 1090                         wderror(bp, du, "reverting to PIO mode");
 1091                         du->dk_flags &= ~DKFL_USEDMA;
 1092                 } else if((du->dk_flags & DKFL_MULTI) &&
 1093                     (errstat & WDERR_ABORT)) {
 1094                         wderror(bp, du, "reverting to non-multi sector mode");
 1095                         du->dk_multi = 1;
 1096                 }
 1097 
 1098                 if (!(du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) &&
 1099                     (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) && 
 1100                      (dmastat != WDDS_INTERRUPT)))
 1101                         printf("wd%d: DMA failure, DMA status %b\n", 
 1102                                du->dk_lunit, dmastat, WDDS_BITS);
 1103 #ifdef WDDEBUG
 1104                 wderror(bp, du, "wdintr");
 1105 #endif
 1106                 if ((du->dk_flags & DKFL_SINGLE) == 0) {
 1107                         du->dk_flags |= DKFL_ERROR;
 1108                         goto outt;
 1109                 }
 1110 
 1111                 if (du->dk_status & WDCS_ERR) {
 1112                         if (++wdtab[unit].b_errcnt < RETRIES) {
 1113                                 wdtab[unit].b_active = 0;
 1114                         } else {
 1115                                 wderror(bp, du, "hard error");
 1116                                 bp->bio_error = EIO;
 1117                                 bp->bio_flags |= BIO_ERROR;     /* flag the error */
 1118                         }
 1119                 } else if (du->dk_status & WDCS_ECCCOR)
 1120                         wderror(bp, du, "soft ecc");
 1121         }
 1122 
 1123         /*
 1124          * If this was a successful read operation, fetch the data.
 1125          */
 1126         if (bp->bio_cmd == BIO_READ && !(bp->bio_flags & BIO_ERROR)
 1127             && !((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1128             && wdtab[unit].b_active) {
 1129                 u_int   chk, dummy, multisize;
 1130                 multisize = chk = du->dk_currentiosize * DEV_BSIZE;
 1131                 if( du->dk_bc < chk) {
 1132                         chk = du->dk_bc;
 1133                         if( ((chk + DEV_BSIZE - 1) / DEV_BSIZE) < du->dk_currentiosize) {
 1134                                 du->dk_currentiosize = (chk + DEV_BSIZE - 1) / DEV_BSIZE;
 1135                                 multisize = du->dk_currentiosize * DEV_BSIZE;
 1136                         }
 1137                 }
 1138 
 1139                 /* ready to receive data? */
 1140                 if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
 1141                     != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
 1142                         wderror(bp, du, "wdintr: read intr arrived early");
 1143                 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
 1144                         wderror(bp, du, "wdintr: read error detected late");
 1145                         goto oops;
 1146                 }
 1147 
 1148                 /* suck in data */
 1149                 if( du->dk_flags & DKFL_32BIT)
 1150                         insl(du->dk_port + wd_data,
 1151                              (void *)((int)bp->bio_data + du->dk_skip * DEV_BSIZE),
 1152                                         chk / sizeof(long));
 1153                 else
 1154                         insw(du->dk_port + wd_data,
 1155                              (void *)((int)bp->bio_data + du->dk_skip * DEV_BSIZE),
 1156                                         chk / sizeof(short));
 1157                 du->dk_bc -= chk;
 1158 
 1159                 /* XXX for obsolete fractional sector reads. */
 1160                 while (chk < multisize) {
 1161                         insw(du->dk_port + wd_data, &dummy, 1);
 1162                         chk += sizeof(short);
 1163                 }
 1164 
 1165         }
 1166 
 1167         /* final cleanup on DMA */
 1168         if (((bp->bio_flags & BIO_ERROR) == 0)
 1169             && ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1170             && wdtab[unit].b_active) {
 1171                 int iosize;
 1172 
 1173                 iosize = du->dk_currentiosize * DEV_BSIZE;
 1174 
 1175                 du->dk_bc -= iosize;
 1176 
 1177         }
 1178 
 1179 outt:
 1180         if (wdtab[unit].b_active) {
 1181                 if ((bp->bio_flags & BIO_ERROR) == 0) {
 1182                         du->dk_skip += du->dk_currentiosize;/* add to successful sectors */
 1183                         if (wdtab[unit].b_errcnt)
 1184                                 wderror(bp, du, "soft error");
 1185                         wdtab[unit].b_errcnt = 0;
 1186 
 1187                         /* see if more to transfer */
 1188                         if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
 1189                                 if( (du->dk_flags & DKFL_SINGLE) ||
 1190                                         (bp->bio_cmd == BIO_WRITE)) {
 1191                                         wdtab[unit].b_active = 0;
 1192                                         wdstart(unit);
 1193                                 } else {
 1194                                         du->dk_timeout = 1 + 3;
 1195                                 }
 1196                                 return; /* next chunk is started */
 1197                         } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR))
 1198                                    == DKFL_ERROR) {
 1199                                 du->dk_skip = 0;
 1200                                 du->dk_flags &= ~DKFL_ERROR;
 1201                                 du->dk_flags |= DKFL_SINGLE;
 1202                                 wdtab[unit].b_active = 0;
 1203                                 wdstart(unit);
 1204                                 return; /* redo xfer sector by sector */
 1205                         }
 1206                 }
 1207 
 1208 done: ;
 1209                 /* done with this transfer, with or without error */
 1210                 du->dk_flags &= ~(DKFL_SINGLE|DKFL_DMA);
 1211                 bioq_remove( &wdtab[unit].controller_queue, bp);
 1212                 wdtab[unit].b_errcnt = 0;
 1213                 bp->bio_resid = bp->bio_bcount - du->dk_skip * DEV_BSIZE;
 1214                 wdutab[du->dk_lunit].b_active = 0;
 1215                 du->dk_skip = 0;
 1216                 biofinish(bp, &du->dk_stats, 0);
 1217         }
 1218 
 1219         /* controller idle */
 1220         wdtab[unit].b_active = 0;
 1221 
 1222         /* anything more on drive queue? */
 1223         wdustart(du);
 1224         /* anything more for controller to do? */
 1225         wdstart(unit);
 1226 }
 1227 
 1228 /*
 1229  * Initialize a drive.
 1230  */
 1231 int
 1232 wdopen(dev_t dev, int flags, int fmt, struct thread *td)
 1233 {
 1234         register struct softc *du;
 1235 
 1236         du = dev->si_drv1;
 1237         if (du == NULL)
 1238                 return (ENXIO);
 1239 
 1240         dev->si_iosize_max = 248 * 512;
 1241 #ifdef PC98
 1242         outb(0x432,(du->dk_unit)%2);
 1243 #endif
 1244 
 1245         /* Finish flushing IRQs left over from wdattach(). */
 1246         if (wdtab[du->dk_ctrlr_cmd640].b_active == 2)
 1247                 wdtab[du->dk_ctrlr_cmd640].b_active = 0;
 1248 
 1249         du->dk_flags &= ~DKFL_BADSCAN;
 1250 
 1251         /* spin waiting for anybody else reading the disk label */
 1252         while (du->dk_flags & DKFL_LABELLING)
 1253                 tsleep((caddr_t)&du->dk_flags, PZERO - 1, "wdopen", 1);
 1254 
 1255         wdsleep(du->dk_ctrlr, "wdopn1");
 1256         du->dk_flags |= DKFL_LABELLING;
 1257         du->dk_state = WANTOPEN;
 1258 
 1259         du->disk.d_sectorsize = du->dk_dd.d_secsize;
 1260         du->disk.d_mediasize = du->dk_dd.d_secperunit * du->dk_dd.d_secsize;
 1261         du->disk.d_fwsectors = du->dk_dd.d_nsectors;
 1262         du->disk.d_fwheads = du->dk_dd.d_ntracks;
 1263 
 1264         du->dk_flags &= ~DKFL_LABELLING;
 1265         wdsleep(du->dk_ctrlr, "wdopn2");
 1266 
 1267         return 0;
 1268 }
 1269 
 1270 /*
 1271  * Implement operations other than read/write.
 1272  * Called from wdstart or wdintr during opens.
 1273  * Uses finite-state-machine to track progress of operation in progress.
 1274  * Returns 0 if operation still in progress, 1 if completed, 2 if error.
 1275  */
 1276 static int
 1277 wdcontrol(register struct bio *bp)
 1278 {
 1279         register struct softc *du;
 1280         int     ctrlr;
 1281 
 1282         du = bp->bio_dev->si_drv1;
 1283         ctrlr = du->dk_ctrlr_cmd640;
 1284 
 1285 #ifdef PC98
 1286         outb(0x432,(du->dk_unit)%2);
 1287 #endif
 1288 
 1289         switch (du->dk_state) {
 1290         case WANTOPEN:
 1291 tryagainrecal:
 1292                 wdtab[ctrlr].b_active = 1;
 1293                 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) {
 1294                         wderror(bp, du, "wdcontrol: wdcommand failed");
 1295                         goto maybe_retry;
 1296                 }
 1297                 du->dk_state = RECAL;
 1298                 return (0);
 1299         case RECAL:
 1300                 if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) {
 1301                         wderror(bp, du, "wdcontrol: recal failed");
 1302 maybe_retry:
 1303                         if (du->dk_status & WDCS_ERR)
 1304                                 wdunwedge(du);
 1305                         du->dk_state = WANTOPEN;
 1306                         if (++wdtab[ctrlr].b_errcnt < RETRIES)
 1307                                 goto tryagainrecal;
 1308                         bp->bio_error = ENXIO;  /* XXX needs translation */
 1309                         bp->bio_flags |= BIO_ERROR;
 1310                         return (2);
 1311                 }
 1312                 wdtab[ctrlr].b_errcnt = 0;
 1313                 du->dk_state = OPEN;
 1314                 /*
 1315                  * The rest of the initialization can be done by normal
 1316                  * means.
 1317                  */
 1318                 return (1);
 1319         }
 1320         panic("wdcontrol");
 1321         return (2);
 1322 }
 1323 
 1324 /*
 1325  * Wait uninterruptibly until controller is not busy, then send it a command.
 1326  * The wait usually terminates immediately because we waited for the previous
 1327  * command to terminate.
 1328  */
 1329 static int
 1330 wdcommand(struct softc *du, u_int cylinder, u_int head, u_int sector,
 1331           u_int count, u_int command)
 1332 {
 1333         u_int   wdc;
 1334 #ifdef PC98
 1335         unsigned char   u_addr;
 1336 #endif
 1337 
 1338         wdc = du->dk_port;
 1339         if (du->cfg_flags & WDOPT_SLEEPHACK) {
 1340                 /* OK, so the APM bios has put the disk into SLEEP mode,
 1341                  * how can we tell ?  Uhm, we can't.  There is no 
 1342                  * standardized way of finding out, and the only way to
 1343                  * wake it up is to reset it.  Bummer.
 1344                  *
 1345                  * All the many and varied versions of the IDE/ATA standard
 1346                  * explicitly tells us not to look at these registers if
 1347                  * the disk is in SLEEP mode.  Well, too bad really, we
 1348                  * have to find out if it's in sleep mode before we can 
 1349                  * avoid reading the registers.
 1350                  *
 1351                  * I have reason to belive that most disks will return
 1352                  * either 0xff or 0x00 in all but the status register 
 1353                  * when in SLEEP mode, but I have yet to see one return 
 1354                  * 0x00, so we don't check for that yet.
 1355                  *
 1356                  * The check for WDCS_BUSY is for the case where the
 1357                  * bios spins up the disk for us, but doesn't initialize
 1358                  * it correctly                                 /phk
 1359                  */
 1360                 if (old_epson_note) {
 1361                         if(epson_inb(wdc + wd_precomp) + epson_inb(wdc + wd_cyl_lo) +
 1362                            epson_inb(wdc + wd_cyl_hi) + epson_inb(wdc + wd_sdh) +
 1363                            epson_inb(wdc + wd_sector) +
 1364                            epson_inb(wdc + wd_seccnt) == 6 * 0xff) {
 1365                                 if (bootverbose)
 1366                                         printf("wd(%d,%d): disk aSLEEP\n",
 1367                                                    du->dk_ctrlr, du->dk_unit);
 1368                                 wdunwedge(du);
 1369                         } else if(epson_inb(wdc + wd_status) == WDCS_BUSY) {
 1370                                 if (bootverbose)
 1371                                         printf("wd(%d,%d): disk is BUSY\n",
 1372                                                    du->dk_ctrlr, du->dk_unit);
 1373                                 wdunwedge(du);
 1374                         }
 1375                 } else {
 1376                         if(inb(wdc + wd_precomp) + inb(wdc + wd_cyl_lo) +
 1377                            inb(wdc + wd_cyl_hi) + inb(wdc + wd_sdh) +
 1378                            inb(wdc + wd_sector) + inb(wdc + wd_seccnt) == 6 * 0xff) {
 1379                                 if (bootverbose)
 1380                                         printf("wd(%d,%d): disk aSLEEP\n",
 1381                                                    du->dk_ctrlr, du->dk_unit);
 1382                                 wdunwedge(du);
 1383                         } else if(inb(wdc + wd_status) == WDCS_BUSY) {
 1384                                 if (bootverbose)
 1385                                         printf("wd(%d,%d): disk is BUSY\n",
 1386                                                    du->dk_ctrlr, du->dk_unit);
 1387                                 wdunwedge(du);
 1388                         }
 1389                 }
 1390         }
 1391 
 1392         if (wdwait(du, 0, TIMEOUT) < 0)
 1393                 return (1);
 1394 #ifdef PC98
 1395 /*      u_addr = (du->dk_unit & 0xfe);  */
 1396         u_addr = ((du->dk_unit)/2)<<4;
 1397 #endif /* PC98 */
 1398         if( command == WDCC_FEATURES) {
 1399                 if (old_epson_note)
 1400                         epson_outb(wdc + wd_features, count);
 1401                 else {
 1402                         outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
 1403                         outb(wdc + wd_features, count);
 1404                         if ( count == WDFEA_SETXFER )
 1405                                 outb(wdc + wd_seccnt, sector);
 1406                 }
 1407         } else {
 1408                 if (old_epson_note) {
 1409                         epson_outb(wdc + wd_precomp, du->dk_dd.d_precompcyl/4);
 1410                         epson_outb(wdc + wd_cyl_lo, cylinder);
 1411                         epson_outb(wdc + wd_cyl_hi, cylinder >> 8);
 1412                         epson_outb(wdc + wd_sdh, WDSD_IBM | u_addr | head);
 1413                         epson_outb(wdc + wd_sector, sector + 1);
 1414                         epson_outb(wdc + wd_seccnt, count);
 1415                 }
 1416                 else {
 1417                         outb(wdc + wd_precomp, du->dk_dd.d_precompcyl / 4);
 1418                         outb(wdc + wd_cyl_lo, cylinder);
 1419                         outb(wdc + wd_cyl_hi, cylinder >> 8);
 1420 #ifdef PC98
 1421                         outb(wdc + wd_sdh, WDSD_IBM | u_addr | head);
 1422 #else
 1423                         outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit<<4) | head);
 1424 #endif
 1425                 if (head & WDSD_LBA)
 1426                         outb(wdc + wd_sector, sector);
 1427                 else
 1428                         outb(wdc + wd_sector, sector + 1);
 1429                 outb(wdc + wd_seccnt, count);
 1430                 }
 1431         }
 1432         if (wdwait(du, (command == WDCC_DIAGNOSE || command == WDCC_IDC)
 1433                        ? 0 : WDCS_READY, TIMEOUT) < 0)
 1434                 return (1);
 1435         if (old_epson_note)
 1436                 epson_outb(wdc + wd_command, command);
 1437         else
 1438                 outb(wdc + wd_command, command);
 1439         return (0);
 1440 }
 1441 
 1442 static void
 1443 wdsetmulti(struct softc *du)
 1444 {
 1445         /*
 1446          * The config option flags low 8 bits define the maximum multi-block
 1447          * transfer size.  If the user wants the maximum that the drive
 1448          * is capable of, just set the low bits of the config option to
 1449          * 0x00ff.
 1450          */
 1451         if ((du->cfg_flags & WDOPT_MULTIMASK) != 0 && (du->dk_multi > 1)) {
 1452                 int configval = du->cfg_flags & WDOPT_MULTIMASK;
 1453                 du->dk_multi = min(du->dk_multi, configval);
 1454                 if (wdcommand(du, 0, 0, 0, du->dk_multi, WDCC_SET_MULTI)) {
 1455                         du->dk_multi = 1;
 1456                 } else {
 1457                         if (wdwait(du, WDCS_READY, TIMEOUT) < 0) {
 1458                                 du->dk_multi = 1;
 1459                         }
 1460                 }
 1461         } else {
 1462                 du->dk_multi = 1;
 1463         }
 1464 }
 1465 
 1466 /*
 1467  * issue IDC to drive to tell it just what geometry it is to be.
 1468  */
 1469 static int
 1470 wdsetctlr(struct softc *du)
 1471 {
 1472         int error = 0;
 1473 #ifdef PC98
 1474         outb(0x432,(du->dk_unit)%2);
 1475 #endif
 1476 #ifdef WDDEBUG
 1477         printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
 1478                du->dk_ctrlr, du->dk_unit,
 1479                du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
 1480                du->dk_dd.d_nsectors);
 1481 #endif
 1482         if (!(du->dk_flags & DKFL_LBA)) {
 1483                 if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
 1484                         struct wdparams *wp;
 1485         
 1486                         printf("wd%d: can't handle %lu heads from partition table ",
 1487                         du->dk_lunit, du->dk_dd.d_ntracks);
 1488                         /* obtain parameters */
 1489                         wp = &du->dk_params;
 1490                         if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
 1491                                 printf("(controller value %u restored)\n",
 1492                                         wp->wdp_heads);
 1493                                 du->dk_dd.d_ntracks = wp->wdp_heads;
 1494                         }
 1495                         else {
 1496                                 printf("(truncating to 16)\n");
 1497                                 du->dk_dd.d_ntracks = 16;
 1498                         }
 1499                 }
 1500         
 1501                 if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
 1502                         printf("wd%d: cannot handle %lu sectors (max 255)\n",
 1503                         du->dk_lunit, du->dk_dd.d_nsectors);
 1504                         error = 1;
 1505                 }
 1506                 if (error) {
 1507                         wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES;
 1508                         return (1);
 1509                 }
 1510                 if (wdcommand(du, du->dk_dd.d_ncylinders,                                                     du->dk_dd.d_ntracks - 1, 0,
 1511                               du->dk_dd.d_nsectors, WDCC_IDC) != 0
 1512                               || wdwait(du, WDCS_READY, TIMEOUT) < 0) {
 1513                         wderror((struct bio *)NULL, du, "wdsetctlr failed");
 1514                         return (1);
 1515                 }
 1516         }
 1517 
 1518         wdsetmulti(du);
 1519 
 1520 #ifdef NOTYET
 1521 /* set read caching and write caching */
 1522         wdcommand(du, 0, 0, 0, WDFEA_RCACHE, WDCC_FEATURES);
 1523         wdwait(du, WDCS_READY, TIMEOUT);
 1524 
 1525         wdcommand(du, 0, 0, 0, WDFEA_WCACHE, WDCC_FEATURES);
 1526         wdwait(du, WDCS_READY, TIMEOUT);
 1527 #endif
 1528 
 1529         return (0);
 1530 }
 1531 
 1532 #if 0
 1533 /*
 1534  * Wait until driver is inactive, then set up controller.
 1535  */
 1536 static int
 1537 wdwsetctlr(struct softc *du)
 1538 {
 1539         int     stat;
 1540         int     x;
 1541 
 1542         wdsleep(du->dk_ctrlr, "wdwset");
 1543         x = splbio();
 1544         stat = wdsetctlr(du);
 1545         wdflushirq(du, x);
 1546         splx(x);
 1547         return (stat);
 1548 }
 1549 #endif
 1550 
 1551 /*
 1552  * gross little callback function for wdddma interface. returns 1 for
 1553  * success, 0 for failure.
 1554  */
 1555 static int
 1556 wdsetmode(int mode, void *wdinfo)
 1557 {
 1558     int i;
 1559     struct softc *du;
 1560 
 1561     du = wdinfo;
 1562     if (bootverbose)
 1563         printf("wd%d: wdsetmode() setting transfer mode to %02x\n", 
 1564                du->dk_lunit, mode);
 1565     i = wdcommand(du, 0, 0, mode, WDFEA_SETXFER, 
 1566                   WDCC_FEATURES) == 0 &&
 1567         wdwait(du, WDCS_READY, TIMEOUT) == 0;
 1568     return i;
 1569 }
 1570 
 1571 /*
 1572  * issue READP to drive to ask it what it is.
 1573  */
 1574 static int
 1575 wdgetctlr(struct softc *du)
 1576 {
 1577         int     i;
 1578         char    tb[DEV_BSIZE], tb2[DEV_BSIZE];
 1579         struct wdparams *wp = NULL;
 1580         u_long flags = du->cfg_flags;
 1581 #ifdef PC98
 1582         outb(0x432,(du->dk_unit)%2);
 1583 #endif
 1584 
 1585 again:
 1586         if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
 1587             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
 1588 
 1589 #ifdef  PC98
 1590                 if ( du->dk_unit > 1 )
 1591                         return(1);
 1592 #endif
 1593                 /*
 1594                  * if we failed on the second try, assume non-32bit
 1595                  */
 1596                 if( du->dk_flags & DKFL_32BIT)
 1597                         goto failed;
 1598 
 1599                 /* XXX need to check error status after final transfer. */
 1600                 /*
 1601                  * Old drives don't support WDCC_READP.  Try a seek to 0.
 1602                  * Some IDE controllers return trash if there is no drive
 1603                  * attached, so first test that the drive can be selected.
 1604                  * This also avoids long waits for nonexistent drives.
 1605                  */
 1606                 if (wdwait(du, 0, TIMEOUT) < 0)
 1607                         return (1);
 1608                 if (old_epson_note) {
 1609                         epson_outb(du->dk_port + wd_sdh,
 1610                                                 WDSD_IBM | (du->dk_unit << 4));
 1611                         DELAY(5000);    /* usually unnecessary; drive select is fast */
 1612                         if ((epson_inb(du->dk_port + wd_status)
 1613                                                 & (WDCS_BUSY | WDCS_READY))
 1614                             != WDCS_READY
 1615                             || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
 1616                             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
 1617                                 return (1);
 1618                 }
 1619                 else {
 1620                         outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
 1621                         DELAY(5000);    /* usually unnecessary; drive select is fast */
 1622                 /*
 1623                  * Do this twice: may get a false WDCS_READY the first time.
 1624                  */
 1625                 inb(du->dk_port + wd_status);
 1626                         if ((inb(du->dk_port + wd_status) & (WDCS_BUSY | WDCS_READY))
 1627                             != WDCS_READY
 1628                             || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
 1629                             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
 1630                                 return (1);
 1631                 }
 1632                 if (du->dk_unit == bootinfo.bi_n_bios_used) {
 1633                         du->dk_dd.d_secsize = DEV_BSIZE;
 1634                         du->dk_dd.d_nsectors =
 1635                             bootinfo.bi_bios_geom[du->dk_unit] & 0xff;
 1636                         du->dk_dd.d_ntracks =
 1637                             ((bootinfo.bi_bios_geom[du->dk_unit] >> 8) & 0xff)
 1638                             + 1;
 1639                         /* XXX Why 2 ? */
 1640                         du->dk_dd.d_ncylinders =
 1641                             (bootinfo.bi_bios_geom[du->dk_unit] >> 16) + 2;
 1642                         du->dk_dd.d_secpercyl =
 1643                             du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
 1644                         du->dk_dd.d_secperunit =
 1645                             du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
 1646 #if 0
 1647                         du->dk_dd.d_partitions[WDRAW].p_size =
 1648                                 du->dk_dd.d_secperunit;
 1649                         du->dk_dd.d_type = DTYPE_ST506;
 1650                         du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
 1651                         strncpy(du->dk_dd.d_typename, "Bios geometry",
 1652                                 sizeof du->dk_dd.d_typename);
 1653                         strncpy(du->dk_params.wdp_model, "ST506",
 1654                                 sizeof du->dk_params.wdp_model);
 1655 #endif
 1656                         bootinfo.bi_n_bios_used ++;
 1657                         return 0;
 1658                 }
 1659                 /*
 1660                  * Fake minimal drive geometry for reading the MBR.
 1661                  * readdisklabel() may enlarge it to read the label and the
 1662                  * bad sector table.
 1663                  */
 1664                 du->dk_dd.d_secsize = DEV_BSIZE;
 1665                 du->dk_dd.d_nsectors = 17;
 1666                 du->dk_dd.d_ntracks = 1;
 1667                 du->dk_dd.d_ncylinders = 1;
 1668                 du->dk_dd.d_secpercyl = 17;
 1669                 du->dk_dd.d_secperunit = 17;
 1670 
 1671 #if 0
 1672                 /*
 1673                  * Fake maximal drive size for writing the label.
 1674                  */
 1675                 du->dk_dd.d_partitions[RAW_PART].p_size = 64 * 16 * 1024;
 1676 
 1677                 /*
 1678                  * Fake some more of the label for printing by disklabel(1)
 1679                  * in case there is no real label.
 1680                  */
 1681                 du->dk_dd.d_type = DTYPE_ST506;
 1682                 du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
 1683                 strncpy(du->dk_dd.d_typename, "Fake geometry",
 1684                         sizeof du->dk_dd.d_typename);
 1685 #endif
 1686 
 1687                 /* Fake the model name for printing by wdattach(). */
 1688                 strncpy(du->dk_params.wdp_model, "unknown",
 1689                         sizeof du->dk_params.wdp_model);
 1690 
 1691                 return (0);
 1692         }
 1693 
 1694         /* obtain parameters */
 1695         wp = &du->dk_params;
 1696         if (!old_epson_note) {
 1697                 if (du->dk_flags & DKFL_32BIT)
 1698                         insl(du->dk_port + wd_data, tb,
 1699                                                 sizeof(tb) / sizeof(long));
 1700                 else
 1701                         insw(du->dk_port + wd_data, tb,
 1702                                                 sizeof(tb) / sizeof(short));
 1703         }
 1704         else
 1705                 epson_insw(du->dk_port + wd_data, tb,
 1706                                                 sizeof(tb) / sizeof(short));
 1707 
 1708         /* try 32-bit data path (VLB IDE controller) */
 1709         if (flags & WDOPT_32BIT) {
 1710                 if (! (du->dk_flags & DKFL_32BIT)) {
 1711                         bcopy(tb, tb2, sizeof(struct wdparams));
 1712                         du->dk_flags |= DKFL_32BIT;
 1713                         goto again;
 1714                 }
 1715 
 1716                 /* check that we really have 32-bit controller */
 1717                 if (bcmp (tb, tb2, sizeof(struct wdparams)) != 0) {
 1718 failed:
 1719                         /* test failed, use 16-bit i/o mode */
 1720                         bcopy(tb2, tb, sizeof(struct wdparams));
 1721                         du->dk_flags &= ~DKFL_32BIT;
 1722                 }
 1723         }
 1724 
 1725         bcopy(tb, wp, sizeof(struct wdparams));
 1726 
 1727         /* shuffle string byte order */
 1728         for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i += 2) {
 1729                 u_short *p;
 1730 
 1731                 p = (u_short *) (wp->wdp_model + i);
 1732                 *p = ntohs(*p);
 1733         }
 1734         /*
 1735          * Clean up the wdp_model by converting nulls to spaces, and
 1736          * then removing the trailing spaces.
 1737          */
 1738         for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i++) {
 1739                 if (wp->wdp_model[i] == '\0') {
 1740                         wp->wdp_model[i] = ' ';
 1741                 }
 1742         }
 1743         for (i = sizeof(wp->wdp_model) - 1;
 1744             (i >= 0 && wp->wdp_model[i] == ' '); i--) {
 1745                 wp->wdp_model[i] = '\0';
 1746         }
 1747 
 1748         /*
 1749          * find out the drives maximum multi-block transfer capability
 1750          */
 1751         du->dk_multi = wp->wdp_nsecperint & 0xff;
 1752         wdsetmulti(du);
 1753 
 1754         /*
 1755          * check drive's DMA capability
 1756          */
 1757         if (wddma[du->dk_interface].wdd_candma) {
 1758                 du->dk_dmacookie = wddma[du->dk_interface].wdd_candma(
 1759                     du->dk_port, du->dk_ctrlr, du->dk_unit);
 1760         /* does user want this? */
 1761                 if ((du->cfg_flags & WDOPT_DMA) &&
 1762             /* have we got a DMA controller? */
 1763                      du->dk_dmacookie &&
 1764                     /* can said drive do DMA? */
 1765                      wddma[du->dk_interface].wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)) {
 1766                     du->dk_flags |= DKFL_USEDMA;
 1767                 }
 1768         } else {
 1769                 du->dk_dmacookie = NULL;
 1770         }
 1771 
 1772 #ifdef WDDEBUG
 1773         printf(
 1774 "\nwd(%d,%d): wdgetctlr: gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
 1775                du->dk_ctrlr, du->dk_unit, wp->wdp_config, wp->wdp_cylinders,
 1776                wp->wdp_heads, wp->wdp_sectors, wp->wdp_buffertype,
 1777                wp->wdp_buffersize, wp->wdp_model);
 1778 #endif
 1779 #ifdef PC98
 1780         /* for larger than 40MB */
 1781         {
 1782           long cyl = wp->wdp_cylinders * wp->wdp_heads * wp->wdp_sectors;
 1783 
 1784           if ( du->dk_unit > 1 ) {
 1785                  wp->wdp_sectors = 17;
 1786                  wp->wdp_heads = 8;
 1787           } else {
 1788                  wp->wdp_sectors = bootinfo.bi_bios_geom[du->dk_unit] & 0xff;
 1789                  wp->wdp_heads = (bootinfo.bi_bios_geom[du->dk_unit] >> 8) & 0xff;
 1790           }
 1791 
 1792           wp->wdp_cylinders = cyl / (wp->wdp_heads * wp->wdp_sectors);
 1793         }
 1794 #endif
 1795 
 1796         /* update disklabel given drive information */
 1797         du->dk_dd.d_secsize = DEV_BSIZE;
 1798         if ((du->cfg_flags & WDOPT_LBA) && wp->wdp_lbasize) {
 1799                 du->dk_dd.d_nsectors = 63;
 1800                 if (wp->wdp_lbasize < 16*63*1024) {             /* <=528.4 MB */
 1801                         du->dk_dd.d_ntracks = 16;
 1802                 }
 1803                 else if (wp->wdp_lbasize < 32*63*1024) {        /* <=1.057 GB */
 1804                         du->dk_dd.d_ntracks = 32;
 1805                 }
 1806                 else if (wp->wdp_lbasize < 64*63*1024) {        /* <=2.114 GB */
 1807                         du->dk_dd.d_ntracks = 64;
 1808                 }
 1809                 else if (wp->wdp_lbasize < 128*63*1024) {       /* <=4.228 GB */
 1810                         du->dk_dd.d_ntracks = 128;
 1811                 }
 1812                 else if (wp->wdp_lbasize < 255*63*1024) {       /* <=8.422 GB */
 1813                         du->dk_dd.d_ntracks = 255;
 1814                 }
 1815                 else {                                          /* >8.422 GB */
 1816                         du->dk_dd.d_ntracks = 255;              /* XXX */
 1817                 }
 1818                 du->dk_dd.d_secpercyl= du->dk_dd.d_ntracks*du->dk_dd.d_nsectors;
 1819                 du->dk_dd.d_ncylinders = wp->wdp_lbasize/du->dk_dd.d_secpercyl;
 1820                 du->dk_dd.d_secperunit = wp->wdp_lbasize;
 1821                 du->dk_flags |= DKFL_LBA;
 1822         }
 1823         else {
 1824                 du->dk_dd.d_ncylinders = wp->wdp_cylinders;     /* +- 1 */
 1825                 du->dk_dd.d_ntracks = wp->wdp_heads;
 1826                 du->dk_dd.d_nsectors = wp->wdp_sectors;
 1827                 du->dk_dd.d_secpercyl = 
 1828                         du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
 1829                 du->dk_dd.d_secperunit = 
 1830                         du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
 1831                 if (wp->wdp_cylinders == 16383 &&
 1832                     du->dk_dd.d_secperunit < wp->wdp_lbasize) {
 1833                         du->dk_dd.d_secperunit = wp->wdp_lbasize;
 1834                         du->dk_dd.d_ncylinders = 
 1835                                 du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
 1836                 }
 1837         }
 1838         if (WDOPT_FORCEHD(du->cfg_flags)) {
 1839                 du->dk_dd.d_ntracks = WDOPT_FORCEHD(du->cfg_flags);
 1840                 du->dk_dd.d_secpercyl = 
 1841                     du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
 1842                 du->dk_dd.d_ncylinders =
 1843                     du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
 1844         }
 1845         if (du->dk_dd.d_ncylinders > 0x10000 && !(du->cfg_flags & WDOPT_LBA)) {
 1846                 du->dk_dd.d_ncylinders = 0x10000;
 1847                 du->dk_dd.d_secperunit = du->dk_dd.d_secpercyl *
 1848                     du->dk_dd.d_ncylinders;
 1849                 printf(
 1850                     "wd%d: cannot handle %d total sectors; truncating to %lu\n",
 1851                     du->dk_lunit, wp->wdp_lbasize, du->dk_dd.d_secperunit);
 1852         }
 1853 #if 0
 1854         du->dk_dd.d_partitions[RAW_PART].p_size = du->dk_dd.d_secperunit;
 1855         /* dubious ... */
 1856         bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
 1857         bcopy(wp->wdp_model + 20, du->dk_dd.d_packname, 14 - 1);
 1858         /* better ... */
 1859         du->dk_dd.d_type = DTYPE_ESDI;
 1860         du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
 1861 #endif
 1862 
 1863         return (0);
 1864 }
 1865 
 1866 static void
 1867 wderror(struct bio *bp, struct softc *du, char *mesg)
 1868 {
 1869         if (bp == NULL)
 1870                 printf("wd%d: %s", du->dk_lunit, mesg);
 1871         else
 1872                 disk_err(bp, mesg, du->dk_skip, 0);
 1873         printf(" (status %b error %b)\n",
 1874                du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS);
 1875 }
 1876 
 1877 /*
 1878  * Discard any interrupts that were latched by the interrupt system while
 1879  * we were doing polled i/o.
 1880  */
 1881 static void
 1882 wdflushirq(struct softc *du, int old_ipl)
 1883 {
 1884         wdtab[du->dk_ctrlr_cmd640].b_active = 2;
 1885         splx(old_ipl);
 1886         (void)splbio();
 1887         wdtab[du->dk_ctrlr_cmd640].b_active = 0;
 1888 }
 1889 
 1890 /*
 1891  * Reset the controller.
 1892  */
 1893 static int
 1894 wdreset(struct softc *du)
 1895 {
 1896         int     err = 0;
 1897 
 1898 #ifdef PC98
 1899         outb(0x432,(du->dk_unit)%2);
 1900 #endif
 1901         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1902                 wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
 1903         (void)wdwait(du, 0, TIMEOUT);
 1904 #ifdef PC98
 1905         if (old_epson_note) {
 1906                 epson_outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
 1907                 DELAY(10 * 1000);
 1908                 epson_outb(du->dk_altport, WDCTL_IDS);
 1909                 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
 1910                     || (du->dk_error = epson_errorf(du->dk_port + wd_error)) != 0x01)
 1911                         return (1);
 1912                 epson_outb(du->dk_altport, WDCTL_4BIT);
 1913                 err = 0;
 1914         }
 1915         else {
 1916 #endif
 1917         outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
 1918         DELAY(10 * 1000);
 1919         outb(du->dk_altport, WDCTL_IDS);
 1920         outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
 1921         if (wdwait(du, 0, TIMEOUT) != 0)
 1922                 err = 1;                /* no IDE drive found */
 1923         du->dk_error = inb(du->dk_port + wd_error);
 1924         if (du->dk_error != 0x01)
 1925                 err = 1;                /* the drive is incompatible */
 1926         outb(du->dk_altport, WDCTL_4BIT);
 1927 #ifdef PC98
 1928         }
 1929 #endif
 1930         return (err);
 1931 }
 1932 
 1933 /*
 1934  * Sleep until driver is inactive.
 1935  * This is used only for avoiding rare race conditions, so it is unimportant
 1936  * that the sleep may be far too short or too long.
 1937  */
 1938 static void
 1939 wdsleep(int ctrlr, char *wmesg)
 1940 {
 1941         int s = splbio();
 1942         if (eide_quirks & Q_CMD640B)
 1943                 ctrlr = PRIMARY;
 1944         while (wdtab[ctrlr].b_active)
 1945                 tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
 1946         splx(s);
 1947 }
 1948 
 1949 static void
 1950 wdtimeout(void *cdu)
 1951 {
 1952         struct softc *du;
 1953         int     x;
 1954         static  int     timeouts;
 1955 
 1956         du = (struct softc *)cdu;
 1957         x = splbio();
 1958 #ifdef PC98
 1959         outb(0x432,(du->dk_unit)%2);
 1960 #endif
 1961         if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
 1962                 if(timeouts++ <= 5) {
 1963                         char *msg;
 1964 
 1965                         msg = (timeouts > 5) ?
 1966 "Last time I say: interrupt timeout.  Probably a portable PC." :
 1967 "interrupt timeout";
 1968                         wderror((struct bio *)NULL, du, msg);
 1969                         if (du->dk_dmacookie)
 1970                                 printf("wd%d: wdtimeout() DMA status %b\n", 
 1971                                        du->dk_lunit,
 1972                                        wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie), 
 1973                                        WDDS_BITS);
 1974                 }
 1975                 wdunwedge(du);
 1976                 wdflushirq(du, x);
 1977                 du->dk_skip = 0;
 1978                 du->dk_flags |= DKFL_SINGLE;
 1979                 wdstart(du->dk_ctrlr);
 1980         }
 1981         timeout(wdtimeout, cdu, hz);
 1982         splx(x);
 1983 }
 1984 
 1985 /*
 1986  * Reset the controller after it has become wedged.  This is different from
 1987  * wdreset() so that wdreset() can be used in the probe and so that this
 1988  * can restore the geometry .
 1989  */
 1990 static int
 1991 wdunwedge(struct softc *du)
 1992 {
 1993         struct softc *du1;
 1994         int     lunit;
 1995 
 1996 #ifdef PC98
 1997         outb(0x432,(du->dk_unit)%2);
 1998 #endif
 1999 
 2000         /* Schedule other drives for recalibration. */
 2001         for (lunit = 0; lunit < NWD; lunit++)
 2002                 if ((du1 = wddrives[lunit]) != NULL && du1 != du
 2003                     && du1->dk_ctrlr == du->dk_ctrlr
 2004                     && du1->dk_state > WANTOPEN)
 2005                         du1->dk_state = WANTOPEN;
 2006 
 2007         DELAY(RECOVERYTIME);
 2008         if (wdreset(du) == 0) {
 2009                 /*
 2010                  * XXX - recalibrate current drive now because some callers
 2011                  * aren't prepared to have its state change.
 2012                  */
 2013                 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) == 0
 2014                     && wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) == 0
 2015                     && wdsetctlr(du) == 0)
 2016                         return (0);
 2017         }
 2018         wderror((struct bio *)NULL, du, "wdunwedge failed");
 2019         return (1);
 2020 }
 2021 
 2022 /*
 2023  * Wait uninterruptibly until controller is not busy and either certain
 2024  * status bits are set or an error has occurred.
 2025  * The wait is usually short unless it is for the controller to process
 2026  * an entire critical command.
 2027  * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
 2028  * or 0 for no errors.
 2029  * Return controller status in du->dk_status and, if there was a controller
 2030  * error, return the error code in du->dk_error.
 2031  */
 2032 #ifdef WD_COUNT_RETRIES
 2033 static int min_retries[NWDC];
 2034 #endif
 2035 
 2036 static int
 2037 wdwait(struct softc *du, u_char bits_wanted, int timeout)
 2038 {
 2039         int     wdc;
 2040         u_char  status;
 2041 
 2042 #define POLLING         1000
 2043 
 2044         wdc = du->dk_port;
 2045         timeout += POLLING;
 2046 
 2047 /*
 2048  * This delay is really too long, but does not impact the performance
 2049  * as much when using the multi-sector option.  Shorter delays have
 2050  * caused I/O errors on some drives and system configs.  This should
 2051  * probably be fixed if we develop a better short term delay mechanism.
 2052  */
 2053         DELAY(1);
 2054 
 2055         do {
 2056 #ifdef WD_COUNT_RETRIES
 2057                 if (min_retries[du->dk_ctrlr] > timeout
 2058                     || min_retries[du->dk_ctrlr] == 0)
 2059                         min_retries[du->dk_ctrlr] = timeout;
 2060 #endif
 2061 #ifdef PC98
 2062                 if (old_epson_note)
 2063                         du->dk_status = status = epson_inb(wdc + wd_status);
 2064                 else
 2065                         du->dk_status = status = inb(wdc + wd_status);
 2066 #else
 2067                 du->dk_status = status = inb(wdc + wd_status);
 2068 #endif
 2069                 /*
 2070                  * Atapi drives have a very interesting feature, when attached
 2071                  * as a slave on the IDE bus, and there is no master.
 2072                  * They release the bus after getting the command.
 2073                  * We should reselect the drive here to get the status.
 2074                  */
 2075                 if (status == 0xff) {
 2076                         outb(wdc + wd_sdh, WDSD_IBM | du->dk_unit << 4);
 2077                         du->dk_status = status = inb(wdc + wd_status);
 2078                 }
 2079                 if (!(status & WDCS_BUSY)) {
 2080                         if (status & WDCS_ERR) {
 2081                                 if (old_epson_note)
 2082                                         du->dk_error = epson_errorf(wdc + wd_error);
 2083                                 else
 2084                                         du->dk_error = inb(wdc + wd_error);
 2085                                 /*
 2086                                  * We once returned here.  This is wrong
 2087                                  * because the error bit is apparently only
 2088                                  * valid after the controller has interrupted
 2089                                  * (e.g., the error bit is stale when we wait
 2090                                  * for DRQ for writes).  So we can't depend
 2091                                  * on the error bit at all when polling for
 2092                                  * command completion.
 2093                                  */
 2094                         }
 2095                         if ((status & bits_wanted) == bits_wanted) {
 2096                                 return (status & WDCS_ERR);
 2097                         }
 2098                 }
 2099                 if (timeout < TIMEOUT)
 2100                         /*
 2101                          * Switch to a polling rate of about 1 KHz so that
 2102                          * the timeout is almost machine-independent.  The
 2103                          * controller is taking a long time to respond, so
 2104                          * an extra msec won't matter.
 2105                          */
 2106                         DELAY(1000);
 2107                 else
 2108                         DELAY(1);
 2109         } while (--timeout != 0);
 2110         return (-1);
 2111 }
 2112 
 2113 #endif /* NWDC > 0 */

Cache object: 080c34862d9d3ca83dfc6d0d2bebff25


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