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


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

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/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$
   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 Merge/fix TIH/NetBSD bad144 code.
   45  *      o Don't use polling except for initialization.  Need to
   46  *        reorganize the state machine.  Then "extra" interrupts
   47  *        shouldn't happen (except maybe one for initialization).
   48  *      o Fix disklabel, boot and driver inconsistencies with
   49  *        bad144 in standard versions.
   50  *      o Support extended DOS partitions.
   51  *      o Support swapping to DOS partitions.
   52  *      o Handle bad sectors, clustering, disklabelling, DOS
   53  *        partitions and swapping driver-independently.  Use
   54  *        i386/dkbad.c for bad sectors.  Swapping will need new
   55  *        driver entries for polled reinit and polled write).
   56  */
   57 
   58 #include "wd.h"
   59 #ifdef  NWDC
   60 #undef  NWDC
   61 #endif
   62 
   63 #include "wdc.h"
   64 
   65 #if     NWDC > 0
   66 
   67 #include "opt_atapi.h"
   68 #include "opt_devfs.h"
   69 #include "opt_hw_wdog.h"
   70 #include "opt_ide_delay.h"
   71 #include "opt_wd.h"
   72 
   73 #include <sys/param.h>
   74 #include <sys/dkbad.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/conf.h>
   78 #include <sys/disklabel.h>
   79 #include <sys/diskslice.h>
   80 #include <sys/buf.h>
   81 #include <sys/devicestat.h>
   82 #include <sys/malloc.h>
   83 #ifdef DEVFS
   84 #include <sys/devfsext.h>
   85 #endif /*DEVFS*/
   86 #include <machine/bootinfo.h>
   87 #include <machine/clock.h>
   88 #include <machine/cons.h>
   89 #include <machine/md_var.h>
   90 #include <i386/isa/isa.h>
   91 #include <i386/isa/isa_device.h>
   92 #include <i386/isa/wdreg.h>
   93 #include <sys/syslog.h>
   94 #include <vm/vm.h>
   95 #include <vm/vm_prot.h>
   96 #include <vm/pmap.h>
   97 
   98 
   99 #ifdef ATAPI
  100 #include <i386/isa/atapi.h>
  101 #endif
  102 
  103 #ifdef CMD640
  104 #include <i386/isa/wdc_p.h>
  105 #endif /*CMD640*/
  106 
  107 extern void wdstart(int ctrlr);
  108 
  109 #ifdef IDE_DELAY
  110 #define TIMEOUT         IDE_DELAY
  111 #else
  112 #define TIMEOUT         10000
  113 #endif
  114 #define RETRIES         5       /* number of retries before giving up */
  115 #define RECOVERYTIME    500000  /* usec for controller to recover after err */
  116 #define MAXTRANSFER     255     /* max size of transfer in sectors */
  117                                 /* correct max is 256 but some controllers */
  118                                 /* can't handle that in all cases */
  119 #define WDOPT_32BIT     0x8000
  120 #define WDOPT_SLEEPHACK 0x4000
  121 #define WDOPT_DMA       0x2000
  122 #define WDOPT_LBA       0x1000
  123 #define WDOPT_FORCEHD(x)        (((x)&0x0f00)>>8)
  124 #define WDOPT_MULTIMASK 0x00ff
  125 
  126 /*
  127  * This biotab field doubles as a field for the physical unit number on
  128  * the controller.
  129  */
  130 #define id_physid id_scsiid
  131 
  132 /*
  133  * Drive states.  Used to initialize drive.
  134  */
  135 
  136 #define CLOSED          0       /* disk is closed. */
  137 #define WANTOPEN        1       /* open requested, not started */
  138 #define RECAL           2       /* doing restore */
  139 #define OPEN            3       /* done with open */
  140 
  141 #define PRIMARY         0
  142 
  143 /*
  144  * Disk geometry.  A small part of struct disklabel.
  145  * XXX disklabel.5 contains an old clone of disklabel.h.
  146  */
  147 struct diskgeom {
  148         u_long  d_secsize;              /* # of bytes per sector */
  149         u_long  d_nsectors;             /* # of data sectors per track */
  150         u_long  d_ntracks;              /* # of tracks per cylinder */
  151         u_long  d_ncylinders;           /* # of data cylinders per unit */
  152         u_long  d_secpercyl;            /* # of data sectors per cylinder */
  153         u_long  d_secperunit;           /* # of data sectors per unit */
  154         u_long  d_precompcyl;           /* XXX always 0 */
  155 };
  156 
  157 /*
  158  * The structure of a disk drive.
  159  */
  160 struct disk {
  161         u_int   dk_bc;          /* byte count left */
  162         short   dk_skip;        /* blocks already transferred */
  163         int     dk_ctrlr;       /* physical controller number */
  164 #ifdef CMD640
  165         int     dk_ctrlr_cmd640;/* controller number for CMD640 quirk */
  166 #endif
  167         u_int32_t       dk_unit;        /* physical unit number */
  168         u_int32_t       dk_lunit;       /* logical unit number */
  169         u_int32_t       dk_interface;   /* interface (two ctrlrs per interface) */
  170         char    dk_state;       /* control state */
  171         u_char  dk_status;      /* copy of status reg. */
  172         u_char  dk_error;       /* copy of error reg. */
  173         u_char  dk_timeout;     /* countdown to next timeout */
  174         u_int32_t       dk_port;        /* i/o port base */
  175         u_int32_t       dk_altport;     /* altstatus port base */
  176 #ifdef  DEVFS
  177         void    *dk_bdev;       /* devfs token for whole disk */
  178         void    *dk_cdev;       /* devfs token for raw whole disk */
  179 #endif  /* DEVFS */
  180         u_long  cfg_flags;      /* configured characteristics */
  181         short   dk_flags;       /* drive characteristics found */
  182 #define DKFL_SINGLE     0x00004 /* sector at a time mode */
  183 #define DKFL_ERROR      0x00008 /* processing a disk error */
  184 #define DKFL_LABELLING  0x00080 /* readdisklabel() in progress */
  185 #define DKFL_32BIT      0x00100 /* use 32-bit i/o mode */
  186 #define DKFL_MULTI      0x00200 /* use multi-i/o mode */
  187 #define DKFL_BADSCAN    0x00400 /* report all errors */
  188 #define DKFL_USEDMA     0x00800 /* use DMA for data transfers */
  189 #define DKFL_DMA        0x01000 /* using DMA on this transfer-- DKFL_SINGLE
  190                                  * overrides this
  191                                  */
  192 #define DKFL_LBA        0x02000 /* use LBA for data transfers */
  193         struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
  194         unsigned int    dk_multi;       /* multi transfers */
  195         int     dk_currentiosize;       /* current io size */
  196         struct diskgeom dk_dd;  /* device configuration data */
  197         struct diskslices *dk_slices;   /* virtual drives */
  198         void    *dk_dmacookie;  /* handle for DMA services */
  199 
  200         struct devstat dk_stats;        /* devstat entry */
  201 };
  202 
  203 #define WD_COUNT_RETRIES
  204 static int wdtest = 0;
  205 
  206 static struct disk *wddrives[NWD];      /* table of units */
  207 static struct buf_queue_head drive_queue[NWD];  /* head of queue per drive */
  208 static struct {
  209         int     b_active;
  210 } wdutab[NWD];
  211 /*
  212 static struct buf wdtab[NWDC];
  213 */
  214 static struct {
  215         struct  buf_queue_head controller_queue;
  216         int     b_errcnt;
  217         int     b_active;
  218 } wdtab[NWDC];
  219 
  220 struct wddma wddma[NWDC];
  221 
  222 #ifdef notyet
  223 static struct buf rwdbuf[NWD];  /* buffers for raw IO */
  224 #endif
  225 
  226 static int wdprobe(struct isa_device *dvp);
  227 static int wdattach(struct isa_device *dvp);
  228 static void wdustart(struct disk *du);
  229 static int wdcontrol(struct buf *bp);
  230 static int wdcommand(struct disk *du, u_int cylinder, u_int head,
  231                      u_int sector, u_int count, u_int command);
  232 static int wdsetctlr(struct disk *du);
  233 #if 0
  234 static int wdwsetctlr(struct disk *du);
  235 #endif
  236 static int wdsetmode(int mode, void *wdinfo);
  237 static int wdgetctlr(struct disk *du);
  238 static void wderror(struct buf *bp, struct disk *du, char *mesg);
  239 static void wdflushirq(struct disk *du, int old_ipl);
  240 static int wdreset(struct disk *du);
  241 static void wdsleep(int ctrlr, char *wmesg);
  242 static void wdstrategy1(struct buf *bp);
  243 static timeout_t wdtimeout;
  244 static int wdunwedge(struct disk *du);
  245 static int wdwait(struct disk *du, u_char bits_wanted, int timeout);
  246 
  247 struct isa_driver wdcdriver = {
  248         wdprobe, wdattach, "wdc",
  249 };
  250 
  251 
  252 
  253 static  d_open_t        wdopen;
  254 static  d_read_t        wdread;
  255 static  d_write_t       wdwrite;
  256 static  d_close_t       wdclose;
  257 static  d_strategy_t    wdstrategy;
  258 static  d_ioctl_t       wdioctl;
  259 static  d_dump_t        wddump;
  260 static  d_psize_t       wdsize;
  261 
  262 #define CDEV_MAJOR 3
  263 #define BDEV_MAJOR 0
  264 
  265 
  266 static struct cdevsw wd_cdevsw = {
  267           wdopen,       wdclose,        wdread,         wdwrite,
  268           wdioctl,      nostop,         nullreset,      nodevtotty,
  269           seltrue,      nommap,         wdstrategy,     "wd",
  270           NULL,         -1,             wddump,         wdsize,
  271           D_DISK,       0,              -1 };
  272 
  273 
  274 #ifdef CMD640
  275 static int      atapictrlr;
  276 static int      eide_quirks;
  277 #endif
  278 
  279 
  280 /*
  281  *  Here we use the pci-subsystem to find out, whether there is
  282  *  a cmd640b-chip attached on this pci-bus. This public routine
  283  *  will be called by wdc_p.c .
  284  */
  285 
  286 #ifdef CMD640
  287 void
  288 wdc_pci(int quirks)
  289 {
  290         eide_quirks = quirks;
  291 }
  292 #endif
  293 
  294 /*
  295  * Probe for controller.
  296  */
  297 static int
  298 wdprobe(struct isa_device *dvp)
  299 {
  300         int     unit = dvp->id_unit;
  301         int     interface;
  302         struct disk *du;
  303 
  304         if (unit >= NWDC)
  305                 return (0);
  306 
  307         du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
  308         if (du == NULL)
  309                 return (0);
  310         bzero(du, sizeof *du);
  311         du->dk_ctrlr = dvp->id_unit;
  312         interface = du->dk_ctrlr / 2;
  313         du->dk_interface = interface;
  314         du->dk_port = dvp->id_iobase;
  315         if (wddma[interface].wdd_candma != NULL) {
  316                 du->dk_dmacookie =
  317                     wddma[interface].wdd_candma(dvp->id_iobase, du->dk_ctrlr,
  318                     du->dk_unit);
  319                 du->dk_altport =
  320                     wddma[interface].wdd_altiobase(du->dk_dmacookie);
  321         }
  322         if (du->dk_altport == 0)
  323                 du->dk_altport = du->dk_port + wd_ctlr;
  324 
  325         /* check if we have registers that work */
  326         outb(du->dk_port + wd_sdh, WDSD_IBM);   /* set unit 0 */
  327         outb(du->dk_port + wd_cyl_lo, 0xa5);    /* wd_cyl_lo is read/write */
  328         if (inb(du->dk_port + wd_cyl_lo) == 0xff) {     /* XXX too weak */
  329 #ifdef ATAPI
  330                 /* There is no master, try the ATAPI slave. */
  331                 du->dk_unit = 1;
  332                 outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10);
  333                 outb(du->dk_port + wd_cyl_lo, 0xa5);
  334                 if (inb(du->dk_port + wd_cyl_lo) == 0xff)
  335 #endif
  336                         goto nodevice;
  337         }
  338 
  339         if (wdreset(du) == 0)
  340                 goto reset_ok;
  341 #ifdef ATAPI
  342         /* test for ATAPI signature */
  343         outb(du->dk_port + wd_sdh, WDSD_IBM);           /* master */
  344         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
  345             inb(du->dk_port + wd_cyl_hi) == 0xeb)
  346                 goto reset_ok;
  347         du->dk_unit = 1;
  348         outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); /* slave */
  349         if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
  350             inb(du->dk_port + wd_cyl_hi) == 0xeb)
  351                 goto reset_ok;
  352 #endif
  353         DELAY(RECOVERYTIME);
  354         if (wdreset(du) != 0) {
  355                 goto nodevice;
  356         }
  357 reset_ok:
  358 
  359         /* execute a controller only command */
  360         if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
  361             || wdwait(du, 0, TIMEOUT) < 0) {
  362                 goto nodevice;
  363         }
  364 
  365         /*
  366          * drive(s) did not time out during diagnostic :
  367          * Get error status and check that both drives are OK.
  368          * Table 9-2 of ATA specs suggests that we must check for
  369          * a value of 0x01
  370          *
  371          * Strangely, some controllers will return a status of
  372          * 0x81 (drive 0 OK, drive 1 failure), and then when
  373          * the DRV bit is set, return status of 0x01 (OK) for
  374          * drive 2.  (This seems to contradict the ATA spec.)
  375          */
  376         du->dk_error = inb(du->dk_port + wd_error);
  377         if(du->dk_error != 0x01 && du->dk_error != 0) {
  378                 if(du->dk_error & 0x80) { /* drive 1 failure */
  379 
  380                         /* first set the DRV bit */
  381                         u_int sdh;
  382                         sdh = inb(du->dk_port+ wd_sdh);
  383                         sdh = sdh | 0x10;
  384                         outb(du->dk_port+ wd_sdh, sdh);
  385 
  386                         /* Wait, to make sure drv 1 has completed diags */
  387                         if ( wdwait(du, 0, TIMEOUT) < 0)
  388                                 goto nodevice;
  389 
  390                         /* Get status for drive 1 */
  391                         du->dk_error = inb(du->dk_port + wd_error);
  392                         /* printf("Error (drv 1) : %x\n", du->dk_error); */
  393                         /*
  394                          * Sometimes (apparently mostly with ATAPI
  395                          * drives involved) 0x81 really means 0x81
  396                          * (drive 0 OK, drive 1 failed).
  397                          */
  398                         if(du->dk_error != 0x01 && du->dk_error != 0x81)
  399                                 goto nodevice;
  400                 } else  /* drive 0 fail */
  401                         goto nodevice;
  402         }
  403 
  404 
  405         free(du, M_TEMP);
  406         return (IO_WDCSIZE);
  407 
  408 nodevice:
  409         free(du, M_TEMP);
  410         return (0);
  411 }
  412 
  413 /*
  414  * Attach each drive if possible.
  415  */
  416 static int
  417 wdattach(struct isa_device *dvp)
  418 {
  419 #if defined(DEVFS)
  420         int     mynor;
  421 #endif
  422         u_int   unit, lunit;
  423         struct isa_device *wdup;
  424         struct disk *du;
  425         struct wdparams *wp;
  426 
  427         dvp->id_intr = wdintr;
  428 
  429         if (dvp->id_unit >= NWDC)
  430                 return (0);
  431 
  432 #ifdef CMD640
  433         if (eide_quirks & Q_CMD640B) {
  434                 if (dvp->id_unit == PRIMARY) {
  435                         printf("wdc0: CMD640B workaround enabled\n");
  436                         bufq_init(&wdtab[PRIMARY].controller_queue);
  437                 }
  438         } else
  439                 bufq_init(&wdtab[dvp->id_unit].controller_queue);
  440 
  441 #else
  442         bufq_init(&wdtab[dvp->id_unit].controller_queue);
  443 #endif
  444 
  445         for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) {
  446                 if (wdup->id_iobase != dvp->id_iobase)
  447                         continue;
  448                 lunit = wdup->id_unit;
  449                 if (lunit >= NWD)
  450                         continue;
  451 
  452                 unit = wdup->id_physid;
  453 
  454                 du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
  455                 if (du == NULL)
  456                         continue;
  457                 if (wddrives[lunit] != NULL)
  458                         panic("drive attached twice");
  459                 wddrives[lunit] = du;
  460                 bufq_init(&drive_queue[lunit]);
  461                 bzero(du, sizeof *du);
  462                 du->dk_ctrlr = dvp->id_unit;
  463 #ifdef CMD640
  464                 if (eide_quirks & Q_CMD640B) {
  465                         du->dk_ctrlr_cmd640 = PRIMARY;
  466                 } else {
  467                         du->dk_ctrlr_cmd640 = du->dk_ctrlr;
  468                 }
  469 #endif
  470                 du->dk_unit = unit;
  471                 du->dk_lunit = lunit;
  472                 du->dk_port = dvp->id_iobase;
  473 
  474                 du->dk_altport = du->dk_port + wd_ctlr;
  475                 /*
  476                  * Use the individual device flags or the controller
  477                  * flags.
  478                  */
  479                 du->cfg_flags = wdup->id_flags |
  480                         ((dvp->id_flags) >> (16 * unit));
  481 
  482                 if (wdgetctlr(du) == 0) {
  483                         /*
  484                          * Print out description of drive.
  485                          * wdp_model may not be null terminated.
  486                          */
  487                         printf("wdc%d: unit %d (wd%d): <%.*s>",
  488                                 dvp->id_unit, unit, lunit,
  489                                 (int)sizeof(du->dk_params.wdp_model),
  490                                 du->dk_params.wdp_model);
  491                         if (du->dk_flags & DKFL_LBA)
  492                                 printf(", LBA");
  493                         if (du->dk_flags & DKFL_USEDMA)
  494                                 printf(", DMA");
  495                         if (du->dk_flags & DKFL_32BIT)
  496                                 printf(", 32-bit");
  497                         if (du->dk_multi > 1)
  498                                 printf(", multi-block-%d", du->dk_multi);
  499                         if (du->cfg_flags & WDOPT_SLEEPHACK)
  500                                 printf(", sleep-hack");
  501                         printf("\n");
  502                         if (du->dk_params.wdp_heads == 0)
  503                                 printf("wd%d: size unknown, using %s values\n",
  504                                        lunit, du->dk_dd.d_secperunit > 17
  505                                               ? "BIOS" : "fake");
  506                         printf( "wd%d: %luMB (%lu sectors), "
  507                                 "%lu cyls, %lu heads, %lu S/T, %lu B/S\n",
  508                                lunit,
  509                                du->dk_dd.d_secperunit
  510                                / ((1024L * 1024L) / du->dk_dd.d_secsize),
  511                                du->dk_dd.d_secperunit,
  512                                du->dk_dd.d_ncylinders,
  513                                du->dk_dd.d_ntracks,
  514                                du->dk_dd.d_nsectors,
  515                                du->dk_dd.d_secsize);
  516 
  517                         if (bootverbose) {
  518                             wp = &du->dk_params;
  519                             printf( "wd%d: ATA INQUIRE valid = %04x, "
  520                                     "dmamword = %04x, apio = %04x, "
  521                                     "udma = %04x\n",
  522                                 du->dk_lunit,
  523                                 wp->wdp_atavalid,
  524                                 wp->wdp_dmamword,
  525                                 wp->wdp_eidepiomodes,
  526                                 wp->wdp_udmamode);
  527                           }
  528 
  529                         /*
  530                          * Start timeout routine for this drive.
  531                          * XXX timeout should be per controller.
  532                          */
  533                         wdtimeout(du);
  534 
  535 #ifdef DEVFS
  536                         mynor = dkmakeminor(lunit, WHOLE_DISK_SLICE, RAW_PART);
  537                         du->dk_bdev = devfs_add_devswf(&wd_cdevsw, mynor,
  538                                                        DV_BLK, UID_ROOT,
  539                                                        GID_OPERATOR, 0640,
  540                                                        "wd%d", lunit);
  541                         du->dk_cdev = devfs_add_devswf(&wd_cdevsw, mynor,
  542                                                        DV_CHR, UID_ROOT,
  543                                                        GID_OPERATOR, 0640,
  544                                                        "rwd%d", lunit);
  545 #endif
  546 
  547                         /*
  548                          * Export the drive to the devstat interface.
  549                          */
  550                         devstat_add_entry(&du->dk_stats, "wd", 
  551                                           lunit, du->dk_dd.d_secsize,
  552                                           DEVSTAT_NO_ORDERED_TAGS,
  553                                           DEVSTAT_TYPE_DIRECT |
  554                                           DEVSTAT_TYPE_IF_IDE,
  555                                           DEVSTAT_PRIORITY_WD);
  556 
  557                 } else {
  558                         free(du, M_TEMP);
  559                         wddrives[lunit] = NULL;
  560                 }
  561         }
  562 #ifdef ATAPI
  563         /*
  564          * Probe all free IDE units, searching for ATAPI drives.
  565          */
  566         for (unit=0; unit<2; ++unit) {
  567                 for (lunit=0; lunit<NWD; ++lunit)
  568                         if (wddrives[lunit] &&
  569                             wddrives[lunit]->dk_ctrlr == dvp->id_unit &&
  570                             wddrives[lunit]->dk_unit == unit)
  571                                 goto next;
  572 #ifdef CMD640
  573                 if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase))
  574                         atapictrlr = dvp->id_unit;
  575 #else
  576                 atapi_attach (dvp->id_unit, unit, dvp->id_iobase);
  577 #endif
  578 next: ;
  579         }
  580 #endif
  581         /*
  582          * Discard any interrupts generated by wdgetctlr().  wdflushirq()
  583          * doesn't work now because the ambient ipl is too high.
  584          */
  585 #ifdef CMD640
  586         if (eide_quirks & Q_CMD640B) {
  587                 wdtab[PRIMARY].b_active = 2;
  588         } else {
  589                 wdtab[dvp->id_unit].b_active = 2;
  590         }
  591 #else
  592         wdtab[dvp->id_unit].b_active = 2;
  593 #endif
  594 
  595         return (1);
  596 }
  597 
  598 
  599 
  600 static int
  601 wdread(dev_t dev, struct uio *uio, int ioflag)
  602 {
  603         return (physio(wdstrategy, NULL, dev, 1, minphys, uio));
  604 }
  605 
  606 static int
  607 wdwrite(dev_t dev, struct uio *uio, int ioflag)
  608 {
  609         return (physio(wdstrategy, NULL, dev, 0, minphys, uio));
  610 }
  611 
  612 /* Read/write routine for a buffer.  Finds the proper unit, range checks
  613  * arguments, and schedules the transfer.  Does not wait for the transfer
  614  * to complete.  Multi-page transfers are supported.  All I/O requests must
  615  * be a multiple of a sector in length.
  616  */
  617 void
  618 wdstrategy(register struct buf *bp)
  619 {
  620         struct disk *du;
  621         int     lunit = dkunit(bp->b_dev);
  622         int     s;
  623 
  624         /* valid unit, controller, and request?  */
  625         if (lunit >= NWD || bp->b_blkno < 0 || (du = wddrives[lunit]) == NULL
  626             || bp->b_bcount % DEV_BSIZE != 0) {
  627 
  628                 bp->b_error = EINVAL;
  629                 bp->b_flags |= B_ERROR;
  630                 goto done;
  631         }
  632 
  633         /*
  634          * Do bounds checking, adjust transfer, and set b_pblkno.
  635          */
  636         if (dscheck(bp, du->dk_slices) <= 0)
  637                 goto done;
  638 
  639         /*
  640          * Check for *any* block on this transfer being on the bad block list
  641          * if it is, then flag the block as a transfer that requires
  642          * bad block handling.  Also, used as a hint for low level disksort
  643          * clustering code to keep from coalescing a bad transfer into
  644          * a normal transfer.  Single block transfers for a large number of
  645          * blocks associated with a cluster I/O are undesirable.
  646          *
  647          * XXX the old disksort() doesn't look at B_BAD.  Coalescing _is_
  648          * desirable.  We should split the results at bad blocks just
  649          * like we should split them at MAXTRANSFER boundaries.
  650          */
  651         if (dsgetbad(bp->b_dev, du->dk_slices) != NULL) {
  652                 long *badsect = dsgetbad(bp->b_dev, du->dk_slices)->bi_bad;
  653                 int i;
  654                 int nsecs = howmany(bp->b_bcount, DEV_BSIZE);
  655                 /* XXX pblkno is too physical. */
  656                 daddr_t nspblkno = bp->b_pblkno
  657                     - du->dk_slices->dss_slices[dkslice(bp->b_dev)].ds_offset;
  658                 int blkend = nspblkno + nsecs;
  659 
  660                 for (i = 0; badsect[i] != -1 && badsect[i] < blkend; i++) {
  661                         if (badsect[i] >= nspblkno) {
  662                                 bp->b_flags |= B_BAD;
  663                                 break;
  664                         }
  665                 }
  666         }
  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         bufqdisksort(&drive_queue[lunit], bp);
  678 
  679         if (wdutab[lunit].b_active == 0)
  680                 wdustart(du);   /* start drive */
  681 
  682 #ifdef CMD640
  683         if (wdtab[du->dk_ctrlr_cmd640].b_active == 0)
  684 #else
  685         if (wdtab[du->dk_ctrlr].b_active == 0)
  686 #endif
  687                 wdstart(du->dk_ctrlr);  /* start controller */
  688 
  689         /* Tell devstat that we have started a transaction on this drive */
  690         devstat_start_transaction(&du->dk_stats);
  691 
  692         splx(s);
  693         return;
  694 
  695 done:
  696         /* toss transfer, we're done early */
  697         biodone(bp);
  698 }
  699 
  700 static void
  701 wdstrategy1(struct buf *bp)
  702 {
  703         /*
  704          * XXX - do something to make wdstrategy() but not this block while
  705          * we're doing dsinit() and dsioctl().
  706          */
  707         wdstrategy(bp);
  708 }
  709 
  710 /*
  711  * Routine to queue a command to the controller.  The unit's
  712  * request is linked into the active list for the controller.
  713  * If the controller is idle, the transfer is started.
  714  */
  715 static void
  716 wdustart(register struct disk *du)
  717 {
  718         register struct buf *bp;
  719 #ifdef CMD640
  720         int     ctrlr = du->dk_ctrlr_cmd640;
  721 #else
  722         int     ctrlr = du->dk_ctrlr;
  723 #endif
  724 
  725         /* unit already active? */
  726         if (wdutab[du->dk_lunit].b_active)
  727                 return;
  728 
  729 
  730         bp = bufq_first(&drive_queue[du->dk_lunit]);
  731         if (bp == NULL) {       /* yes, an assign */
  732                 return;
  733         }
  734         /*
  735          * store away which device we came from.
  736          */
  737         bp->b_driver1 = du;
  738 
  739         bufq_remove(&drive_queue[du->dk_lunit], bp);
  740 
  741         /* link onto controller queue */
  742         bufq_insert_tail(&wdtab[ctrlr].controller_queue, bp);
  743 
  744         /* mark the drive unit as busy */
  745         wdutab[du->dk_lunit].b_active = 1;
  746 
  747 }
  748 
  749 /*
  750  * Controller startup routine.  This does the calculation, and starts
  751  * a single-sector read or write operation.  Called to start a transfer,
  752  * or from the interrupt routine to continue a multi-sector transfer.
  753  * RESTRICTIONS:
  754  * 1. The transfer length must be an exact multiple of the sector size.
  755  */
  756 
  757 void
  758 wdstart(int ctrlr)
  759 {
  760         register struct disk *du;
  761         register struct buf *bp;
  762         struct diskgeom *lp;    /* XXX sic */
  763         long    blknum;
  764         long    secpertrk, secpercyl;
  765         u_int   lunit;
  766         u_int   count;
  767 #ifdef CMD640
  768         int     ctrlr_atapi;
  769 
  770         if (eide_quirks & Q_CMD640B) {
  771                 ctrlr = PRIMARY;
  772                 ctrlr_atapi = atapictrlr;
  773         } else {
  774                 ctrlr_atapi = ctrlr;
  775         }
  776 #endif
  777 
  778 #ifdef ATAPI
  779         if (wdtab[ctrlr].b_active == 2)
  780                 wdtab[ctrlr].b_active = 0;
  781         if (wdtab[ctrlr].b_active)
  782                 return;
  783 #endif
  784         /* is there a drive for the controller to do a transfer with? */
  785         bp = bufq_first(&wdtab[ctrlr].controller_queue);
  786         if (bp == NULL) {
  787 #ifdef ATAPI
  788 #ifdef CMD640
  789                 if (atapi_start && atapi_start (ctrlr_atapi))
  790                         wdtab[ctrlr].b_active = 3;
  791 #else
  792                 if (atapi_start && atapi_start (ctrlr))
  793                         /* mark controller active in ATAPI mode */
  794                         wdtab[ctrlr].b_active = 3;
  795 #endif
  796 #endif
  797                 return;
  798         }
  799 
  800         /* obtain controller and drive information */
  801         lunit = dkunit(bp->b_dev);
  802         du = wddrives[lunit];
  803 
  804         /* if not really a transfer, do control operations specially */
  805         if (du->dk_state < OPEN) {
  806                 if (du->dk_state != WANTOPEN)
  807                         printf("wd%d: wdstart: weird dk_state %d\n",
  808                                du->dk_lunit, du->dk_state);
  809                 if (wdcontrol(bp) != 0)
  810                         printf("wd%d: wdstart: wdcontrol returned nonzero, state = %d\n",
  811                                du->dk_lunit, du->dk_state);
  812                 return;
  813         }
  814 
  815         /* calculate transfer details */
  816         blknum = bp->b_pblkno + du->dk_skip;
  817 #ifdef WDDEBUG
  818         if (du->dk_skip == 0)
  819                 printf("wd%d: wdstart: %s %d@%d; map ", lunit,
  820                        (bp->b_flags & B_READ) ? "read" : "write",
  821                        bp->b_bcount, blknum);
  822         else
  823                 printf(" %d)%x", du->dk_skip, inb(du->dk_altport));
  824 #endif
  825 
  826         lp = &du->dk_dd;
  827         secpertrk = lp->d_nsectors;
  828         secpercyl = lp->d_secpercyl;
  829 
  830         if (du->dk_skip == 0) {
  831                 du->dk_bc = bp->b_bcount;
  832 
  833                 if (bp->b_flags & B_BAD
  834                     /*
  835                      * XXX handle large transfers inefficiently instead
  836                      * of crashing on them.
  837                      */
  838                     || howmany(du->dk_bc, DEV_BSIZE) > MAXTRANSFER)
  839                         du->dk_flags |= DKFL_SINGLE;
  840         }
  841 
  842         if (du->dk_flags & DKFL_SINGLE
  843             && dsgetbad(bp->b_dev, du->dk_slices) != NULL) {
  844                 /* XXX */
  845                 u_long ds_offset =
  846                     du->dk_slices->dss_slices[dkslice(bp->b_dev)].ds_offset;
  847 
  848                 blknum = transbad144(dsgetbad(bp->b_dev, du->dk_slices),
  849                                      blknum - ds_offset) + ds_offset;
  850         }
  851 
  852         wdtab[ctrlr].b_active = 1;      /* mark controller active */
  853 
  854         /* if starting a multisector transfer, or doing single transfers */
  855         if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
  856                 u_int   command;
  857                 u_int   count1;
  858                 long    cylin, head, sector;
  859 
  860                 if (du->dk_flags & DKFL_LBA) {
  861                         sector = (blknum >> 0) & 0xff; 
  862                         cylin = (blknum >> 8) & 0xffff;
  863                         head = ((blknum >> 24) & 0xf) | WDSD_LBA; 
  864                 } else {
  865                         cylin = blknum / secpercyl;
  866                         head = (blknum % secpercyl) / secpertrk;
  867                         sector = blknum % secpertrk;
  868                 }
  869                 /* 
  870                  * XXX this looks like an attempt to skip bad sectors
  871                  * on write.
  872                  */
  873                 if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0)
  874                         du->dk_bc += DEV_BSIZE;
  875 
  876                 count1 = howmany( du->dk_bc, DEV_BSIZE);
  877 
  878                 du->dk_flags &= ~DKFL_MULTI;
  879 
  880 #ifdef B_FORMAT
  881                 if (bp->b_flags & B_FORMAT) {
  882                         command = WDCC_FORMAT;
  883                         count1 = lp->d_nsectors;
  884                         sector = lp->d_gap3 - 1;        /* + 1 later */
  885                 } else
  886 #endif
  887 
  888                 {
  889                         if (du->dk_flags & DKFL_SINGLE) {
  890                                 command = (bp->b_flags & B_READ)
  891                                           ? WDCC_READ : WDCC_WRITE;
  892                                 count1 = 1;
  893                                 du->dk_currentiosize = 1;
  894                         } else {
  895                                 if((du->dk_flags & DKFL_USEDMA) &&
  896                                    wddma[du->dk_interface].wdd_dmaverify(du->dk_dmacookie,
  897                                         (void *)((int)bp->b_data + 
  898                                              du->dk_skip * DEV_BSIZE),
  899                                         du->dk_bc,
  900                                         bp->b_flags & B_READ)) {
  901                                         du->dk_flags |= DKFL_DMA;
  902                                         if( bp->b_flags & B_READ)
  903                                                 command = WDCC_READ_DMA;
  904                                         else
  905                                                 command = WDCC_WRITE_DMA;
  906                                         du->dk_currentiosize = count1;
  907                                 } else if( (count1 > 1) && (du->dk_multi > 1)) {
  908                                         du->dk_flags |= DKFL_MULTI;
  909                                         if( bp->b_flags & B_READ) {
  910                                                 command = WDCC_READ_MULTI;
  911                                         } else {
  912                                                 command = WDCC_WRITE_MULTI;
  913                                         }
  914                                         du->dk_currentiosize = du->dk_multi;
  915                                         if( du->dk_currentiosize > count1)
  916                                                 du->dk_currentiosize = count1;
  917                                 } else {
  918                                         if( bp->b_flags & B_READ) {
  919                                                 command = WDCC_READ;
  920                                         } else {
  921                                                 command = WDCC_WRITE;
  922                                         }
  923                                         du->dk_currentiosize = 1;
  924                                 }
  925                         }
  926                 }
  927 
  928                 /*
  929                  * XXX this loop may never terminate.  The code to handle
  930                  * counting down of retries and eventually failing the i/o
  931                  * is in wdintr() and we can't get there from here.
  932                  */
  933                 if (wdtest != 0) {
  934                         if (--wdtest == 0) {
  935                                 wdtest = 100;
  936                                 printf("dummy wdunwedge\n");
  937                                 wdunwedge(du);
  938                         }
  939                 }
  940 
  941                 if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
  942                         wddma[du->dk_interface].wdd_dmaprep(du->dk_dmacookie,
  943                                            (void *)((int)bp->b_data + 
  944                                                     du->dk_skip * DEV_BSIZE),
  945                                            du->dk_bc,
  946                                            bp->b_flags & B_READ);
  947                 }
  948                 while (wdcommand(du, cylin, head, sector, count1, command)
  949                        != 0) {
  950                         wderror(bp, du,
  951                                 "wdstart: timeout waiting to give command");
  952                         wdunwedge(du);
  953                 }
  954 #ifdef WDDEBUG
  955                 printf("cylin %ld head %ld sector %ld addr %x sts %x\n",
  956                        cylin, head, sector,
  957                        (int)bp->b_data + du->dk_skip * DEV_BSIZE,
  958                        inb(du->dk_altport));
  959 #endif
  960         }
  961 
  962         /*
  963          * Schedule wdtimeout() to wake up after a few seconds.  Retrying
  964          * unmarked bad blocks can take 3 seconds!  Then it is not good that
  965          * we retry 5 times.
  966          *
  967          * On the first try, we give it 10 seconds, for drives that may need
  968          * to spin up.
  969          *
  970          * XXX wdtimeout() doesn't increment the error count so we may loop
  971          * forever.  More seriously, the loop isn't forever but causes a
  972          * crash.
  973          *
  974          * TODO fix b_resid bug elsewhere (fd.c....).  Fix short but positive
  975          * counts being discarded after there is an error (in physio I
  976          * think).  Discarding them would be OK if the (special) file offset
  977          * was not advanced.
  978          */
  979         if (wdtab[ctrlr].b_errcnt == 0)
  980                 du->dk_timeout = 1 + 10;
  981         else
  982                 du->dk_timeout = 1 + 3;
  983 
  984         /* if this is a DMA op, start DMA and go away until it's done. */
  985         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
  986                 wddma[du->dk_interface].wdd_dmastart(du->dk_dmacookie);
  987                 return;
  988         }
  989 
  990         /* If this is a read operation, just go away until it's done. */
  991         if (bp->b_flags & B_READ)
  992                 return;
  993 
  994         /* Ready to send data? */
  995         if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) < 0) {
  996                 wderror(bp, du, "wdstart: timeout waiting for DRQ");
  997                 /*
  998                  * XXX what do we do now?  If we've just issued the command,
  999                  * then we can treat this failure the same as a command
 1000                  * failure.  But if we are continuing a multi-sector write,
 1001                  * the command was issued ages ago, so we can't simply
 1002                  * restart it.
 1003                  *
 1004                  * XXX we waste a lot of time unnecessarily translating block
 1005                  * numbers to cylin/head/sector for continued i/o's.
 1006                  */
 1007         }
 1008 
 1009         count = 1;
 1010         if( du->dk_flags & DKFL_MULTI) {
 1011                 count = howmany(du->dk_bc, DEV_BSIZE);
 1012                 if( count > du->dk_multi)
 1013                         count = du->dk_multi;
 1014                 if( du->dk_currentiosize > count)
 1015                         du->dk_currentiosize = count;
 1016         }
 1017 
 1018         if (du->dk_flags & DKFL_32BIT)
 1019                 outsl(du->dk_port + wd_data,
 1020                       (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
 1021                       (count * DEV_BSIZE) / sizeof(long));
 1022         else
 1023                 outsw(du->dk_port + wd_data,
 1024                       (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
 1025                       (count * DEV_BSIZE) / sizeof(short));
 1026         du->dk_bc -= DEV_BSIZE * count;
 1027 }
 1028 
 1029 /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
 1030  * errors on the current operation, mark it done if necessary, and start
 1031  * the next request.  Also check for a partially done transfer, and
 1032  * continue with the next chunk if so.
 1033  */
 1034 
 1035 void
 1036 wdintr(void *unitnum)
 1037 {
 1038         register struct disk *du;
 1039         register struct buf *bp;
 1040         int dmastat = 0;                        /* Shut up GCC */
 1041         int unit = (int)unitnum;
 1042 
 1043 #ifdef CMD640
 1044         int ctrlr_atapi;
 1045 
 1046         if (eide_quirks & Q_CMD640B) {
 1047                 unit = PRIMARY;
 1048                 ctrlr_atapi = atapictrlr;
 1049         } else {
 1050                 ctrlr_atapi = unit;
 1051         }
 1052 #endif
 1053 
 1054         if (wdtab[unit].b_active == 2)
 1055                 return;         /* intr in wdflushirq() */
 1056         if (!wdtab[unit].b_active) {
 1057 #ifdef WDDEBUG
 1058                 /*
 1059                  * These happen mostly because the power-mgt part of the
 1060                  * bios shuts us down, and we just manage to see the
 1061                  * interrupt from the "SLEEP" command.
 1062                  */
 1063                 printf("wdc%d: extra interrupt\n", unit);
 1064 #endif
 1065                 return;
 1066         }
 1067 #ifdef ATAPI
 1068         if (wdtab[unit].b_active == 3) {
 1069                 /* process an ATAPI interrupt */
 1070 #ifdef CMD640
 1071                 if (atapi_intr && atapi_intr (ctrlr_atapi))
 1072 #else
 1073                 if (atapi_intr && atapi_intr (unit))
 1074 #endif
 1075                         /* ATAPI op continues */
 1076                         return;
 1077                 /* controller is free, start new op */
 1078                 wdtab[unit].b_active = 0;
 1079                 wdstart (unit);
 1080                 return;
 1081         }
 1082 #endif
 1083         bp = bufq_first(&wdtab[unit].controller_queue);
 1084         du = wddrives[dkunit(bp->b_dev)];
 1085 
 1086         /* finish off DMA */
 1087         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
 1088                 /* XXX SMP boxes sometimes generate an early intr.  Why? */
 1089                 if ((wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie) & 
 1090                     WDDS_INTERRUPT) == 0)
 1091                         return;
 1092                 dmastat = wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
 1093         }
 1094 
 1095         du->dk_timeout = 0;
 1096 
 1097         /* check drive status/failure */
 1098         if (wdwait(du, 0, TIMEOUT) < 0) {
 1099                 wderror(bp, du, "wdintr: timeout waiting for status");
 1100                 du->dk_status |= WDCS_ERR;      /* XXX */
 1101         }
 1102 
 1103         /* is it not a transfer, but a control operation? */
 1104         if (du->dk_state < OPEN) {
 1105                 wdtab[unit].b_active = 0;
 1106                 switch (wdcontrol(bp)) {
 1107                 case 0:
 1108                         return;
 1109                 case 1:
 1110                         wdstart(unit);
 1111                         return;
 1112                 case 2:
 1113                         goto done;
 1114                 }
 1115         }
 1116 
 1117         /* have we an error? */
 1118         if ((du->dk_status & (WDCS_ERR | WDCS_ECCCOR))
 1119             || (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1120                 && dmastat != WDDS_INTERRUPT)) {
 1121 
 1122                 unsigned int errstat;
 1123 oops:
 1124                 /*
 1125                  * XXX bogus inb() here
 1126                  */
 1127                 errstat = inb(du->dk_port + wd_error);
 1128 
 1129                 if(((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
 1130                    (errstat & WDERR_ABORT)) {
 1131                         wderror(bp, du, "reverting to PIO mode");
 1132                         du->dk_flags &= ~DKFL_USEDMA;
 1133                 } else if((du->dk_flags & DKFL_MULTI) &&
 1134                     (errstat & WDERR_ABORT)) {
 1135                         wderror(bp, du, "reverting to non-multi sector mode");
 1136                         du->dk_multi = 1;
 1137                 }
 1138 
 1139                 if (!(du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) &&
 1140                     (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) && 
 1141                      (dmastat != WDDS_INTERRUPT)))
 1142                         printf("wd%d: DMA failure, DMA status %b\n", 
 1143                                du->dk_lunit, dmastat, WDDS_BITS);
 1144 #ifdef WDDEBUG
 1145                 wderror(bp, du, "wdintr");
 1146 #endif
 1147                 if ((du->dk_flags & DKFL_SINGLE) == 0) {
 1148                         du->dk_flags |= DKFL_ERROR;
 1149                         goto outt;
 1150                 }
 1151 #ifdef B_FORMAT
 1152                 if (bp->b_flags & B_FORMAT) {
 1153                         bp->b_error = EIO;
 1154                         bp->b_flags |= B_ERROR;
 1155                         goto done;
 1156                 }
 1157 #endif
 1158 
 1159                 if (du->dk_flags & DKFL_BADSCAN) {
 1160                         bp->b_error = EIO;
 1161                         bp->b_flags |= B_ERROR;
 1162                 } else if (du->dk_status & WDCS_ERR) {
 1163                         if (++wdtab[unit].b_errcnt < RETRIES) {
 1164                                 wdtab[unit].b_active = 0;
 1165                         } else {
 1166                                 wderror(bp, du, "hard error");
 1167                                 bp->b_error = EIO;
 1168                                 bp->b_flags |= B_ERROR; /* flag the error */
 1169                         }
 1170                 } else if (du->dk_status & WDCS_ECCCOR)
 1171                         wderror(bp, du, "soft ecc");
 1172         }
 1173 
 1174         /*
 1175          * If this was a successful read operation, fetch the data.
 1176          */
 1177         if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ)
 1178             && !((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1179             && wdtab[unit].b_active) {
 1180                 u_int   chk, dummy, multisize;
 1181                 multisize = chk = du->dk_currentiosize * DEV_BSIZE;
 1182                 if( du->dk_bc < chk) {
 1183                         chk = du->dk_bc;
 1184                         if( ((chk + DEV_BSIZE - 1) / DEV_BSIZE) < du->dk_currentiosize) {
 1185                                 du->dk_currentiosize = (chk + DEV_BSIZE - 1) / DEV_BSIZE;
 1186                                 multisize = du->dk_currentiosize * DEV_BSIZE;
 1187                         }
 1188                 }
 1189 
 1190                 /* ready to receive data? */
 1191                 if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
 1192                     != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
 1193                         wderror(bp, du, "wdintr: read intr arrived early");
 1194                 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
 1195                         wderror(bp, du, "wdintr: read error detected late");
 1196                         goto oops;
 1197                 }
 1198 
 1199                 /* suck in data */
 1200                 if( du->dk_flags & DKFL_32BIT)
 1201                         insl(du->dk_port + wd_data,
 1202                              (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
 1203                                         chk / sizeof(long));
 1204                 else
 1205                         insw(du->dk_port + wd_data,
 1206                              (void *)((int)bp->b_data + du->dk_skip * DEV_BSIZE),
 1207                                         chk / sizeof(short));
 1208                 du->dk_bc -= chk;
 1209 
 1210                 /* XXX for obsolete fractional sector reads. */
 1211                 while (chk < multisize) {
 1212                         insw(du->dk_port + wd_data, &dummy, 1);
 1213                         chk += sizeof(short);
 1214                 }
 1215 
 1216         }
 1217 
 1218         /* final cleanup on DMA */
 1219         if (((bp->b_flags & B_ERROR) == 0)
 1220             && ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 1221             && wdtab[unit].b_active) {
 1222                 int iosize;
 1223 
 1224                 iosize = du->dk_currentiosize * DEV_BSIZE;
 1225 
 1226                 du->dk_bc -= iosize;
 1227 
 1228         }
 1229 
 1230 outt:
 1231         if (wdtab[unit].b_active) {
 1232                 if ((bp->b_flags & B_ERROR) == 0) {
 1233                         du->dk_skip += du->dk_currentiosize;/* add to successful sectors */
 1234                         if (wdtab[unit].b_errcnt)
 1235                                 wderror(bp, du, "soft error");
 1236                         wdtab[unit].b_errcnt = 0;
 1237 
 1238                         /* see if more to transfer */
 1239                         if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
 1240                                 if( (du->dk_flags & DKFL_SINGLE) ||
 1241                                         ((bp->b_flags & B_READ) == 0)) {
 1242                                         wdtab[unit].b_active = 0;
 1243                                         wdstart(unit);
 1244                                 } else {
 1245                                         du->dk_timeout = 1 + 3;
 1246                                 }
 1247                                 return; /* next chunk is started */
 1248                         } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR))
 1249                                    == DKFL_ERROR) {
 1250                                 du->dk_skip = 0;
 1251                                 du->dk_flags &= ~DKFL_ERROR;
 1252                                 du->dk_flags |= DKFL_SINGLE;
 1253                                 wdtab[unit].b_active = 0;
 1254                                 wdstart(unit);
 1255                                 return; /* redo xfer sector by sector */
 1256                         }
 1257                 }
 1258 
 1259 done: ;
 1260                 /* done with this transfer, with or without error */
 1261                 du->dk_flags &= ~(DKFL_SINGLE|DKFL_DMA);
 1262                 bufq_remove( &wdtab[unit].controller_queue, bp);
 1263                 wdtab[unit].b_errcnt = 0;
 1264                 bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE;
 1265                 wdutab[du->dk_lunit].b_active = 0;
 1266                 du->dk_skip = 0;
 1267 
 1268                 /* Update device stats */
 1269                 devstat_end_transaction(&du->dk_stats,
 1270                                         bp->b_bcount - bp->b_resid,
 1271                                         DEVSTAT_TAG_NONE,
 1272                                         (bp->b_flags & B_READ) ? DEVSTAT_READ : DEVSTAT_WRITE);
 1273 
 1274                 biodone(bp);
 1275         }
 1276 
 1277         /* controller idle */
 1278         wdtab[unit].b_active = 0;
 1279 
 1280         /* anything more on drive queue? */
 1281         wdustart(du);
 1282         /* anything more for controller to do? */
 1283 #ifndef ATAPI
 1284         /* This is not valid in ATAPI mode. */
 1285         if (bufq_first(&wdtab[unit].controller_queue) != NULL)
 1286 #endif
 1287                 wdstart(unit);
 1288 }
 1289 
 1290 /*
 1291  * Initialize a drive.
 1292  */
 1293 int
 1294 wdopen(dev_t dev, int flags, int fmt, struct proc *p)
 1295 {
 1296         register unsigned int lunit;
 1297         register struct disk *du;
 1298         int     error;
 1299 
 1300         lunit = dkunit(dev);
 1301         if (lunit >= NWD || dktype(dev) != 0)
 1302                 return (ENXIO);
 1303         du = wddrives[lunit];
 1304         if (du == NULL)
 1305                 return (ENXIO);
 1306 
 1307         /* Finish flushing IRQs left over from wdattach(). */
 1308 #ifdef CMD640
 1309         if (wdtab[du->dk_ctrlr_cmd640].b_active == 2)
 1310                 wdtab[du->dk_ctrlr_cmd640].b_active = 0;
 1311 #else
 1312         if (wdtab[du->dk_ctrlr].b_active == 2)
 1313                 wdtab[du->dk_ctrlr].b_active = 0;
 1314 #endif
 1315 
 1316         du->dk_flags &= ~DKFL_BADSCAN;
 1317 
 1318         /* spin waiting for anybody else reading the disk label */
 1319         while (du->dk_flags & DKFL_LABELLING)
 1320                 tsleep((caddr_t)&du->dk_flags, PZERO - 1, "wdopen", 1);
 1321 #if 1
 1322         wdsleep(du->dk_ctrlr, "wdopn1");
 1323         du->dk_flags |= DKFL_LABELLING;
 1324         du->dk_state = WANTOPEN;
 1325         {
 1326         struct disklabel label;
 1327 
 1328         bzero(&label, sizeof label);
 1329         label.d_secsize = du->dk_dd.d_secsize;
 1330         label.d_nsectors = du->dk_dd.d_nsectors;
 1331         label.d_ntracks = du->dk_dd.d_ntracks;
 1332         label.d_ncylinders = du->dk_dd.d_ncylinders;
 1333         label.d_secpercyl = du->dk_dd.d_secpercyl;
 1334         label.d_secperunit = du->dk_dd.d_secperunit;
 1335         error = dsopen("wd", dev, fmt, 0, &du->dk_slices, &label, wdstrategy1,
 1336                        (ds_setgeom_t *)NULL, &wd_cdevsw);
 1337         }
 1338         du->dk_flags &= ~DKFL_LABELLING;
 1339         wdsleep(du->dk_ctrlr, "wdopn2");
 1340         return (error);
 1341 #else
 1342         if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
 1343                 /*
 1344                  * wdtab[ctrlr].b_active != 0 implies  XXX applicable now ??
 1345                  * drive_queue[lunit].b_act == NULL (?)  XXX applicable now ??
 1346                  * so the following guards most things (until the next i/o).
 1347                  * It doesn't guard against a new i/o starting and being
 1348                  * affected by the label being changed.  Sigh.
 1349                  */
 1350                 wdsleep(du->dk_ctrlr, "wdopn1");
 1351 
 1352                 du->dk_flags |= DKFL_LABELLING;
 1353                 du->dk_state = WANTOPEN;
 1354 
 1355                 error = dsinit(dkmodpart(dev, RAW_PART), wdstrategy,
 1356                                &du->dk_dd, &du->dk_slices);
 1357                 if (error != 0) {
 1358                         du->dk_flags &= ~DKFL_LABELLING;
 1359                         return (error);
 1360                 }
 1361                 /* XXX check value returned by wdwsetctlr(). */
 1362                 wdwsetctlr(du);
 1363                 if (dkslice(dev) == WHOLE_DISK_SLICE) {
 1364                         dsopen(dev, fmt, du->dk_slices);
 1365                         return (0);
 1366                 }
 1367 
 1368                 /*
 1369                  * Read label using RAW_PART partition.
 1370                  *
 1371                  * If the drive has an MBR, then the current geometry (from
 1372                  * wdgetctlr()) is used to read it; then the BIOS/DOS
 1373                  * geometry is inferred and used to read the label off the
 1374                  * 'c' partition.  Otherwise the label is read using the
 1375                  * current geometry.  The label gives the final geometry.
 1376                  * If bad sector handling is enabled, then this geometry
 1377                  * is used to read the bad sector table.  The geometry
 1378                  * changes occur inside readdisklabel() and are propagated
 1379                  * to the driver by resetting the state machine.
 1380                  *
 1381                  * XXX can now handle changes directly since dsinit() doesn't
 1382                  * do too much.
 1383                  */
 1384                 msg = correct_readdisklabel(dkmodpart(dev, RAW_PART), wdstrategy,
 1385                                             &du->dk_dd);
 1386                 /* XXX check value returned by wdwsetctlr(). */
 1387                 wdwsetctlr(du);
 1388                 if (msg == NULL && du->dk_dd.d_flags & D_BADSECT)
 1389                         msg = readbad144(dkmodpart(dev, RAW_PART), wdstrategy,
 1390                                          &du->dk_dd, &du->dk_bad);
 1391                 du->dk_flags &= ~DKFL_LABELLING;
 1392                 if (msg != NULL) {
 1393                         log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
 1394                             lunit, msg);
 1395                         if (part != RAW_PART)
 1396                                 return (EINVAL);  /* XXX needs translation */
 1397                         /*
 1398                          * Soon return.  This is how slices without labels
 1399                          * are allowed.  They only work on the raw partition.
 1400                          */
 1401                 } else {
 1402                         unsigned long newsize, offset, size;
 1403 #if 0
 1404                         /*
 1405                          * Force RAW_PART partition to be the whole disk.
 1406                          */
 1407                         offset = du->dk_dd.d_partitions[RAW_PART].p_offset;
 1408                         if (offset != 0) {
 1409                                 printf(
 1410                 "wd%d: changing offset of '%c' partition from %lu to 0\n",
 1411                                        du->dk_lunit, 'a' + RAW_PART, offset);
 1412                                 du->dk_dd.d_partitions[RAW_PART].p_offset = 0;
 1413                         }
 1414                         size = du->dk_dd.d_partitions[RAW_PART].p_size;
 1415                         newsize = du->dk_dd.d_secperunit;       /* XXX */
 1416                         if (size != newsize) {
 1417                                 printf(
 1418                 "wd%d: changing size of '%c' partition from %lu to %lu\n",
 1419                                        du->dk_lunit, 'a' + RAW_PART, size,
 1420                                        newsize);
 1421                                 du->dk_dd.d_partitions[RAW_PART].p_size
 1422                                         = newsize;
 1423                         }
 1424 #endif
 1425                 }
 1426 
 1427                 /* Pick up changes made by readdisklabel(). */
 1428                 wdsleep(du->dk_ctrlr, "wdopn2");
 1429                 du->dk_state = WANTOPEN;
 1430         }
 1431 
 1432         /*
 1433          * Warn if a partion is opened that overlaps another partition which
 1434          * is open unless one is the "raw" partition (whole disk).
 1435          */
 1436         if ((du->dk_openpart & mask) == 0 && part != RAW_PART) {
 1437                 int     start, end;
 1438 
 1439                 pp = &du->dk_dd.d_partitions[part];
 1440                 start = pp->p_offset;
 1441                 end = pp->p_offset + pp->p_size;
 1442                 for (pp = du->dk_dd.d_partitions;
 1443                      pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
 1444                      pp++) {
 1445                         if (pp->p_offset + pp->p_size <= start ||
 1446                             pp->p_offset >= end)
 1447                                 continue;
 1448                         if (pp - du->dk_dd.d_partitions == RAW_PART)
 1449                                 continue;
 1450                         if (du->dk_openpart
 1451                             & (1 << (pp - du->dk_dd.d_partitions)))
 1452                                 log(LOG_WARNING,
 1453                                     "wd%d%c: overlaps open partition (%c)\n",
 1454                                     lunit, part + 'a',
 1455                                     pp - du->dk_dd.d_partitions + 'a');
 1456                 }
 1457         }
 1458         if (part >= du->dk_dd.d_npartitions && part != RAW_PART)
 1459                 return (ENXIO);
 1460 
 1461         dsopen(dev, fmt, du->dk_slices);
 1462 
 1463         return (0);
 1464 #endif
 1465 }
 1466 
 1467 /*
 1468  * Implement operations other than read/write.
 1469  * Called from wdstart or wdintr during opens and formats.
 1470  * Uses finite-state-machine to track progress of operation in progress.
 1471  * Returns 0 if operation still in progress, 1 if completed, 2 if error.
 1472  */
 1473 static int
 1474 wdcontrol(register struct buf *bp)
 1475 {
 1476         register struct disk *du;
 1477         int     ctrlr;
 1478 
 1479         du = wddrives[dkunit(bp->b_dev)];
 1480 #ifdef CMD640
 1481         ctrlr = du->dk_ctrlr_cmd640;
 1482 #else
 1483         ctrlr = du->dk_ctrlr;
 1484 #endif
 1485 
 1486         switch (du->dk_state) {
 1487         case WANTOPEN:
 1488 tryagainrecal:
 1489                 wdtab[ctrlr].b_active = 1;
 1490                 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) {
 1491                         wderror(bp, du, "wdcontrol: wdcommand failed");
 1492                         goto maybe_retry;
 1493                 }
 1494                 du->dk_state = RECAL;
 1495                 return (0);
 1496         case RECAL:
 1497                 if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) {
 1498                         wderror(bp, du, "wdcontrol: recal failed");
 1499 maybe_retry:
 1500                         if (du->dk_status & WDCS_ERR)
 1501                                 wdunwedge(du);
 1502                         du->dk_state = WANTOPEN;
 1503                         if (++wdtab[ctrlr].b_errcnt < RETRIES)
 1504                                 goto tryagainrecal;
 1505                         bp->b_error = ENXIO;    /* XXX needs translation */
 1506                         bp->b_flags |= B_ERROR;
 1507                         return (2);
 1508                 }
 1509                 wdtab[ctrlr].b_errcnt = 0;
 1510                 du->dk_state = OPEN;
 1511                 /*
 1512                  * The rest of the initialization can be done by normal
 1513                  * means.
 1514                  */
 1515                 return (1);
 1516         }
 1517         panic("wdcontrol");
 1518         return (2);
 1519 }
 1520 
 1521 /*
 1522  * Wait uninterruptibly until controller is not busy, then send it a command.
 1523  * The wait usually terminates immediately because we waited for the previous
 1524  * command to terminate.
 1525  */
 1526 static int
 1527 wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
 1528           u_int count, u_int command)
 1529 {
 1530         u_int   wdc;
 1531 
 1532         wdc = du->dk_port;
 1533         if (du->cfg_flags & WDOPT_SLEEPHACK) {
 1534                 /* OK, so the APM bios has put the disk into SLEEP mode,
 1535                  * how can we tell ?  Uhm, we can't.  There is no 
 1536                  * standardized way of finding out, and the only way to
 1537                  * wake it up is to reset it.  Bummer.
 1538                  *
 1539                  * All the many and varied versions of the IDE/ATA standard
 1540                  * explicitly tells us not to look at these registers if
 1541                  * the disk is in SLEEP mode.  Well, too bad really, we
 1542                  * have to find out if it's in sleep mode before we can 
 1543                  * avoid reading the registers.
 1544                  *
 1545                  * I have reason to belive that most disks will return
 1546                  * either 0xff or 0x00 in all but the status register 
 1547                  * when in SLEEP mode, but I have yet to see one return 
 1548                  * 0x00, so we don't check for that yet.
 1549                  *
 1550                  * The check for WDCS_BUSY is for the case where the
 1551                  * bios spins up the disk for us, but doesn't initialize
 1552                  * it correctly                                 /phk
 1553                  */
 1554                 if(inb(wdc + wd_precomp) + inb(wdc + wd_cyl_lo) +
 1555                     inb(wdc + wd_cyl_hi) + inb(wdc + wd_sdh) +
 1556                     inb(wdc + wd_sector) + inb(wdc + wd_seccnt) == 6 * 0xff) {
 1557                         if (bootverbose)
 1558                                 printf("wd(%d,%d): disk aSLEEP\n",
 1559                                         du->dk_ctrlr, du->dk_unit);
 1560                         wdunwedge(du);
 1561                 } else if(inb(wdc + wd_status) == WDCS_BUSY) {
 1562                         if (bootverbose)
 1563                                 printf("wd(%d,%d): disk is BUSY\n",
 1564                                         du->dk_ctrlr, du->dk_unit);
 1565                         wdunwedge(du);
 1566                 }
 1567         }
 1568 
 1569         if (wdwait(du, 0, TIMEOUT) < 0)
 1570                 return (1);
 1571         if( command == WDCC_FEATURES) {
 1572                 outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
 1573                 outb(wdc + wd_features, count);
 1574                 if ( count == WDFEA_SETXFER )
 1575                         outb(wdc + wd_seccnt, sector);
 1576         } else {
 1577                 outb(wdc + wd_precomp, du->dk_dd.d_precompcyl / 4);
 1578                 outb(wdc + wd_cyl_lo, cylinder);
 1579                 outb(wdc + wd_cyl_hi, cylinder >> 8);
 1580                 outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
 1581                 if (head & WDSD_LBA)
 1582                         outb(wdc + wd_sector, sector);
 1583                 else
 1584                         outb(wdc + wd_sector, sector + 1);
 1585                 outb(wdc + wd_seccnt, count);
 1586         }
 1587         if (wdwait(du, (command == WDCC_DIAGNOSE || command == WDCC_IDC)
 1588                        ? 0 : WDCS_READY, TIMEOUT) < 0)
 1589                 return (1);
 1590         outb(wdc + wd_command, command);
 1591         return (0);
 1592 }
 1593 
 1594 static void
 1595 wdsetmulti(struct disk *du)
 1596 {
 1597         /*
 1598          * The config option flags low 8 bits define the maximum multi-block
 1599          * transfer size.  If the user wants the maximum that the drive
 1600          * is capable of, just set the low bits of the config option to
 1601          * 0x00ff.
 1602          */
 1603         if ((du->cfg_flags & WDOPT_MULTIMASK) != 0 && (du->dk_multi > 1)) {
 1604                 int configval = du->cfg_flags & WDOPT_MULTIMASK;
 1605                 du->dk_multi = min(du->dk_multi, configval);
 1606                 if (wdcommand(du, 0, 0, 0, du->dk_multi, WDCC_SET_MULTI)) {
 1607                         du->dk_multi = 1;
 1608                 } else {
 1609                         if (wdwait(du, WDCS_READY, TIMEOUT) < 0) {
 1610                                 du->dk_multi = 1;
 1611                         }
 1612                 }
 1613         } else {
 1614                 du->dk_multi = 1;
 1615         }
 1616 }
 1617 
 1618 /*
 1619  * issue IDC to drive to tell it just what geometry it is to be.
 1620  */
 1621 static int
 1622 wdsetctlr(struct disk *du)
 1623 {
 1624         int error = 0;
 1625 #ifdef WDDEBUG
 1626         printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
 1627                du->dk_ctrlr, du->dk_unit,
 1628                du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
 1629                du->dk_dd.d_nsectors);
 1630 #endif
 1631         if (!(du->dk_flags & DKFL_LBA)) {
 1632                 if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
 1633                         struct wdparams *wp;
 1634         
 1635                         printf("wd%d: can't handle %lu heads from partition table ",
 1636                         du->dk_lunit, du->dk_dd.d_ntracks);
 1637                         /* obtain parameters */
 1638                         wp = &du->dk_params;
 1639                         if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
 1640                                 printf("(controller value %u restored)\n",
 1641                                         wp->wdp_heads);
 1642                                 du->dk_dd.d_ntracks = wp->wdp_heads;
 1643                         }
 1644                         else {
 1645                                 printf("(truncating to 16)\n");
 1646                                 du->dk_dd.d_ntracks = 16;
 1647                         }
 1648                 }
 1649         
 1650                 if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
 1651                         printf("wd%d: cannot handle %lu sectors (max 255)\n",
 1652                         du->dk_lunit, du->dk_dd.d_nsectors);
 1653                         error = 1;
 1654                 }
 1655                 if (error) {
 1656 #ifdef CMD640 
 1657                         wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES;
 1658 #else
 1659                         wdtab[du->dk_ctrlr].b_errcnt += RETRIES;
 1660 #endif
 1661                         return (1);
 1662                 }
 1663                 if (wdcommand(du, du->dk_dd.d_ncylinders,                                                     du->dk_dd.d_ntracks - 1, 0,
 1664                               du->dk_dd.d_nsectors, WDCC_IDC) != 0
 1665                               || wdwait(du, WDCS_READY, TIMEOUT) < 0) {
 1666                         wderror((struct buf *)NULL, du, "wdsetctlr failed");
 1667                         return (1);
 1668                 }
 1669         }
 1670 
 1671         wdsetmulti(du);
 1672 
 1673 #ifdef NOTYET
 1674 /* set read caching and write caching */
 1675         wdcommand(du, 0, 0, 0, WDFEA_RCACHE, WDCC_FEATURES);
 1676         wdwait(du, WDCS_READY, TIMEOUT);
 1677 
 1678         wdcommand(du, 0, 0, 0, WDFEA_WCACHE, WDCC_FEATURES);
 1679         wdwait(du, WDCS_READY, TIMEOUT);
 1680 #endif
 1681 
 1682         return (0);
 1683 }
 1684 
 1685 #if 0
 1686 /*
 1687  * Wait until driver is inactive, then set up controller.
 1688  */
 1689 static int
 1690 wdwsetctlr(struct disk *du)
 1691 {
 1692         int     stat;
 1693         int     x;
 1694 
 1695         wdsleep(du->dk_ctrlr, "wdwset");
 1696         x = splbio();
 1697         stat = wdsetctlr(du);
 1698         wdflushirq(du, x);
 1699         splx(x);
 1700         return (stat);
 1701 }
 1702 #endif
 1703 
 1704 /*
 1705  * gross little callback function for wdddma interface. returns 1 for
 1706  * success, 0 for failure.
 1707  */
 1708 static int
 1709 wdsetmode(int mode, void *wdinfo)
 1710 {
 1711     int i;
 1712     struct disk *du;
 1713 
 1714     du = wdinfo;
 1715     if (bootverbose)
 1716         printf("wd%d: wdsetmode() setting transfer mode to %02x\n", 
 1717                du->dk_lunit, mode);
 1718     i = wdcommand(du, 0, 0, mode, WDFEA_SETXFER, 
 1719                   WDCC_FEATURES) == 0 &&
 1720         wdwait(du, WDCS_READY, TIMEOUT) == 0;
 1721     return i;
 1722 }
 1723 
 1724 /*
 1725  * issue READP to drive to ask it what it is.
 1726  */
 1727 static int
 1728 wdgetctlr(struct disk *du)
 1729 {
 1730         int     i;
 1731         char    tb[DEV_BSIZE], tb2[DEV_BSIZE];
 1732         struct wdparams *wp = NULL;
 1733         u_long flags = du->cfg_flags;
 1734 again:
 1735         if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
 1736             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
 1737 
 1738                 /*
 1739                  * if we failed on the second try, assume non-32bit
 1740                  */
 1741                 if( du->dk_flags & DKFL_32BIT)
 1742                         goto failed;
 1743 
 1744                 /* XXX need to check error status after final transfer. */
 1745                 /*
 1746                  * Old drives don't support WDCC_READP.  Try a seek to 0.
 1747                  * Some IDE controllers return trash if there is no drive
 1748                  * attached, so first test that the drive can be selected.
 1749                  * This also avoids long waits for nonexistent drives.
 1750                  */
 1751                 if (wdwait(du, 0, TIMEOUT) < 0)
 1752                         return (1);
 1753                 outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
 1754                 DELAY(5000);    /* usually unnecessary; drive select is fast */
 1755                 /*
 1756                  * Do this twice: may get a false WDCS_READY the first time.
 1757                  */
 1758                 inb(du->dk_port + wd_status);
 1759                 if ((inb(du->dk_port + wd_status) & (WDCS_BUSY | WDCS_READY))
 1760                     != WDCS_READY
 1761                     || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
 1762                     || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
 1763                         return (1);
 1764 
 1765                 if (du->dk_unit == bootinfo.bi_n_bios_used) {
 1766                         du->dk_dd.d_secsize = DEV_BSIZE;
 1767                         du->dk_dd.d_nsectors =
 1768                             bootinfo.bi_bios_geom[du->dk_unit] & 0xff;
 1769                         du->dk_dd.d_ntracks =
 1770                             ((bootinfo.bi_bios_geom[du->dk_unit] >> 8) & 0xff)
 1771                             + 1;
 1772                         /* XXX Why 2 ? */
 1773                         du->dk_dd.d_ncylinders =
 1774                             (bootinfo.bi_bios_geom[du->dk_unit] >> 16) + 2;
 1775                         du->dk_dd.d_secpercyl =
 1776                             du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
 1777                         du->dk_dd.d_secperunit =
 1778                             du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
 1779 #if 0
 1780                         du->dk_dd.d_partitions[WDRAW].p_size =
 1781                                 du->dk_dd.d_secperunit;
 1782                         du->dk_dd.d_type = DTYPE_ST506;
 1783                         du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
 1784                         strncpy(du->dk_dd.d_typename, "Bios geometry",
 1785                                 sizeof du->dk_dd.d_typename);
 1786                         strncpy(du->dk_params.wdp_model, "ST506",
 1787                                 sizeof du->dk_params.wdp_model);
 1788 #endif
 1789                         bootinfo.bi_n_bios_used ++;
 1790                         return 0;
 1791                 }
 1792                 /*
 1793                  * Fake minimal drive geometry for reading the MBR.
 1794                  * readdisklabel() may enlarge it to read the label and the
 1795                  * bad sector table.
 1796                  */
 1797                 du->dk_dd.d_secsize = DEV_BSIZE;
 1798                 du->dk_dd.d_nsectors = 17;
 1799                 du->dk_dd.d_ntracks = 1;
 1800                 du->dk_dd.d_ncylinders = 1;
 1801                 du->dk_dd.d_secpercyl = 17;
 1802                 du->dk_dd.d_secperunit = 17;
 1803 
 1804 #if 0
 1805                 /*
 1806                  * Fake maximal drive size for writing the label.
 1807                  */
 1808                 du->dk_dd.d_partitions[RAW_PART].p_size = 64 * 16 * 1024;
 1809 
 1810                 /*
 1811                  * Fake some more of the label for printing by disklabel(1)
 1812                  * in case there is no real label.
 1813                  */
 1814                 du->dk_dd.d_type = DTYPE_ST506;
 1815                 du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
 1816                 strncpy(du->dk_dd.d_typename, "Fake geometry",
 1817                         sizeof du->dk_dd.d_typename);
 1818 #endif
 1819 
 1820                 /* Fake the model name for printing by wdattach(). */
 1821                 strncpy(du->dk_params.wdp_model, "unknown",
 1822                         sizeof du->dk_params.wdp_model);
 1823 
 1824                 return (0);
 1825         }
 1826 
 1827         /* obtain parameters */
 1828         wp = &du->dk_params;
 1829         if (du->dk_flags & DKFL_32BIT)
 1830                 insl(du->dk_port + wd_data, tb, sizeof(tb) / sizeof(long));
 1831         else
 1832                 insw(du->dk_port + wd_data, tb, sizeof(tb) / sizeof(short));
 1833 
 1834         /* try 32-bit data path (VLB IDE controller) */
 1835         if (flags & WDOPT_32BIT) {
 1836                 if (! (du->dk_flags & DKFL_32BIT)) {
 1837                         bcopy(tb, tb2, sizeof(struct wdparams));
 1838                         du->dk_flags |= DKFL_32BIT;
 1839                         goto again;
 1840                 }
 1841 
 1842                 /* check that we really have 32-bit controller */
 1843                 if (bcmp (tb, tb2, sizeof(struct wdparams)) != 0) {
 1844 failed:
 1845                         /* test failed, use 16-bit i/o mode */
 1846                         bcopy(tb2, tb, sizeof(struct wdparams));
 1847                         du->dk_flags &= ~DKFL_32BIT;
 1848                 }
 1849         }
 1850 
 1851         bcopy(tb, wp, sizeof(struct wdparams));
 1852 
 1853         /* shuffle string byte order */
 1854         for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i += 2) {
 1855                 u_short *p;
 1856 
 1857                 p = (u_short *) (wp->wdp_model + i);
 1858                 *p = ntohs(*p);
 1859         }
 1860         /*
 1861          * Clean up the wdp_model by converting nulls to spaces, and
 1862          * then removing the trailing spaces.
 1863          */
 1864         for (i = 0; (unsigned)i < sizeof(wp->wdp_model); i++) {
 1865                 if (wp->wdp_model[i] == '\0') {
 1866                         wp->wdp_model[i] = ' ';
 1867                 }
 1868         }
 1869         for (i = sizeof(wp->wdp_model) - 1;
 1870             (i >= 0 && wp->wdp_model[i] == ' '); i--) {
 1871                 wp->wdp_model[i] = '\0';
 1872         }
 1873 
 1874         /*
 1875          * find out the drives maximum multi-block transfer capability
 1876          */
 1877         du->dk_multi = wp->wdp_nsecperint & 0xff;
 1878         wdsetmulti(du);
 1879 
 1880         /*
 1881          * check drive's DMA capability
 1882          */
 1883         if (wddma[du->dk_interface].wdd_candma) {
 1884                 du->dk_dmacookie = wddma[du->dk_interface].wdd_candma(
 1885                     du->dk_port, du->dk_ctrlr, du->dk_unit);
 1886         /* does user want this? */
 1887                 if ((du->cfg_flags & WDOPT_DMA) &&
 1888             /* have we got a DMA controller? */
 1889                      du->dk_dmacookie &&
 1890                     /* can said drive do DMA? */
 1891                      wddma[du->dk_interface].wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)) {
 1892                     du->dk_flags |= DKFL_USEDMA;
 1893                 }
 1894         } else {
 1895                 du->dk_dmacookie = NULL;
 1896         }
 1897 
 1898 #ifdef WDDEBUG
 1899         printf(
 1900 "\nwd(%d,%d): wdgetctlr: gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
 1901                du->dk_ctrlr, du->dk_unit, wp->wdp_config, wp->wdp_cylinders,
 1902                wp->wdp_heads, wp->wdp_sectors, wp->wdp_buffertype,
 1903                wp->wdp_buffersize, wp->wdp_model);
 1904 #endif
 1905 
 1906         /* update disklabel given drive information */
 1907         du->dk_dd.d_secsize = DEV_BSIZE;
 1908         if ((du->cfg_flags & WDOPT_LBA) && wp->wdp_lbasize) {
 1909                 du->dk_dd.d_nsectors = 63;
 1910                 if (wp->wdp_lbasize < 16*63*1024) {             /* <=528.4 MB */
 1911                         du->dk_dd.d_ntracks = 16;
 1912                 }
 1913                 else if (wp->wdp_lbasize < 32*63*1024) {        /* <=1.057 GB */
 1914                         du->dk_dd.d_ntracks = 32;
 1915                 }
 1916                 else if (wp->wdp_lbasize < 64*63*1024) {        /* <=2.114 GB */
 1917                         du->dk_dd.d_ntracks = 64;
 1918                 }
 1919                 else if (wp->wdp_lbasize < 128*63*1024) {       /* <=4.228 GB */
 1920                         du->dk_dd.d_ntracks = 128;
 1921                 }
 1922                 else if (wp->wdp_lbasize < 255*63*1024) {       /* <=8.422 GB */
 1923                         du->dk_dd.d_ntracks = 255;
 1924                 }
 1925                 else {                                          /* >8.422 GB */
 1926                         du->dk_dd.d_ntracks = 255;              /* XXX */
 1927                 }
 1928                 du->dk_dd.d_secpercyl= du->dk_dd.d_ntracks*du->dk_dd.d_nsectors;
 1929                 du->dk_dd.d_ncylinders = wp->wdp_lbasize/du->dk_dd.d_secpercyl;
 1930                 du->dk_dd.d_secperunit = wp->wdp_lbasize;
 1931                 du->dk_flags |= DKFL_LBA;
 1932         }
 1933         else {
 1934                 du->dk_dd.d_ncylinders = wp->wdp_cylinders;     /* +- 1 */
 1935                 du->dk_dd.d_ntracks = wp->wdp_heads;
 1936                 du->dk_dd.d_nsectors = wp->wdp_sectors;
 1937                 du->dk_dd.d_secpercyl = 
 1938                         du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
 1939                 du->dk_dd.d_secperunit = 
 1940                         du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
 1941                 if (wp->wdp_cylinders == 16383 &&
 1942                     du->dk_dd.d_secperunit < wp->wdp_lbasize) {
 1943                         du->dk_dd.d_secperunit = wp->wdp_lbasize;
 1944                         du->dk_dd.d_ncylinders = 
 1945                                 du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
 1946                 }
 1947         }
 1948         if (WDOPT_FORCEHD(du->cfg_flags)) {
 1949                 du->dk_dd.d_ntracks = WDOPT_FORCEHD(du->cfg_flags);
 1950                 du->dk_dd.d_secpercyl = 
 1951                     du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
 1952                 du->dk_dd.d_ncylinders =
 1953                     du->dk_dd.d_secperunit / du->dk_dd.d_secpercyl;
 1954         }
 1955         if (du->dk_dd.d_ncylinders > 0x10000 && !(du->cfg_flags & WDOPT_LBA)) {
 1956                 du->dk_dd.d_ncylinders = 0x10000;
 1957                 du->dk_dd.d_secperunit = du->dk_dd.d_secpercyl *
 1958                     du->dk_dd.d_ncylinders;
 1959                 printf(
 1960                     "wd%d: cannot handle %d total sectors; truncating to %lu\n",
 1961                     du->dk_lunit, wp->wdp_lbasize, du->dk_dd.d_secperunit);
 1962         }
 1963 #if 0
 1964         du->dk_dd.d_partitions[RAW_PART].p_size = du->dk_dd.d_secperunit;
 1965         /* dubious ... */
 1966         bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
 1967         bcopy(wp->wdp_model + 20, du->dk_dd.d_packname, 14 - 1);
 1968         /* better ... */
 1969         du->dk_dd.d_type = DTYPE_ESDI;
 1970         du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
 1971 #endif
 1972 
 1973         return (0);
 1974 }
 1975 
 1976 int
 1977 wdclose(dev_t dev, int flags, int fmt, struct proc *p)
 1978 {
 1979         dsclose(dev, fmt, wddrives[dkunit(dev)]->dk_slices);
 1980         return (0);
 1981 }
 1982 
 1983 int
 1984 wdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
 1985 {
 1986         int     lunit = dkunit(dev);
 1987         register struct disk *du;
 1988         int     error;
 1989 #ifdef notyet
 1990         struct uio auio;
 1991         struct iovec aiov;
 1992         struct format_op *fop;
 1993 #endif
 1994 
 1995         du = wddrives[lunit];
 1996         wdsleep(du->dk_ctrlr, "wdioct");
 1997         error = dsioctl("wd", dev, cmd, addr, flags, &du->dk_slices,
 1998                         wdstrategy1, (ds_setgeom_t *)NULL);
 1999         if (error != ENOIOCTL)
 2000                 return (error);
 2001         switch (cmd) {
 2002         case DIOCSBADSCAN:
 2003                 if (*(int *)addr)
 2004                         du->dk_flags |= DKFL_BADSCAN;
 2005                 else
 2006                         du->dk_flags &= ~DKFL_BADSCAN;
 2007                 return (0);
 2008 #ifdef notyet
 2009         case DIOCWFORMAT:
 2010                 if (!(flag & FWRITE))
 2011                         return (EBADF);
 2012                 fop = (struct format_op *)addr;
 2013                 aiov.iov_base = fop->df_buf;
 2014                 aiov.iov_len = fop->df_count;
 2015                 auio.uio_iov = &aiov;
 2016                 auio.uio_iovcnt = 1;
 2017                 auio.uio_resid = fop->df_count;
 2018                 auio.uio_segflg = 0;
 2019                 auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize;
 2020 #error /* XXX the 386BSD interface is different */
 2021                 error = physio(wdformat, &rwdbuf[lunit], 0, dev, B_WRITE,
 2022                                minphys, &auio);
 2023                 fop->df_count -= auio.uio_resid;
 2024                 fop->df_reg[0] = du->dk_status;
 2025                 fop->df_reg[1] = du->dk_error;
 2026                 return (error);
 2027 #endif
 2028 
 2029         default:
 2030                 return (ENOTTY);
 2031         }
 2032 }
 2033 
 2034 #ifdef B_FORMAT
 2035 int
 2036 wdformat(struct buf *bp)
 2037 {
 2038 
 2039         bp->b_flags |= B_FORMAT;
 2040         wdstrategy(bp);
 2041         /*
 2042          * phk put this here, better that return(wdstrategy(bp));
 2043          * XXX
 2044          */
 2045         return -1;
 2046 }
 2047 #endif
 2048 
 2049 int
 2050 wdsize(dev_t dev)
 2051 {
 2052         struct disk *du;
 2053         int     lunit;
 2054 
 2055         lunit = dkunit(dev);
 2056         if (lunit >= NWD || dktype(dev) != 0)
 2057                 return (-1);
 2058         du = wddrives[lunit];
 2059         if (du == NULL)
 2060                 return (-1);
 2061         return (dssize(dev, &du->dk_slices, wdopen, wdclose));
 2062 }
 2063  
 2064 int
 2065 wddump(dev_t dev)
 2066 {
 2067         register struct disk *du;
 2068         struct disklabel *lp;
 2069         long    num;            /* number of sectors to write */
 2070         int     lunit, part;
 2071         long    blkoff, blknum;
 2072         long    blkchk, blkcnt, blknext;
 2073         u_long  ds_offset;
 2074         u_long  nblocks;
 2075         static int wddoingadump = 0;
 2076         long    cylin, head, sector;
 2077         long    secpertrk, secpercyl;
 2078         char   *addr;
 2079 
 2080         /* Toss any characters present prior to dump. */
 2081         while (cncheckc() != -1)
 2082                 ;
 2083 
 2084         /* Check for acceptable device. */
 2085         /* XXX should reset to maybe allow du->dk_state < OPEN. */
 2086         lunit = dkunit(dev);    /* eventually support floppies? */
 2087         part = dkpart(dev);
 2088         if (lunit >= NWD || (du = wddrives[lunit]) == NULL
 2089             || du->dk_state < OPEN
 2090             || (lp = dsgetlabel(dev, du->dk_slices)) == NULL)
 2091                 return (ENXIO);
 2092 
 2093         /* Size of memory to dump, in disk sectors. */
 2094         num = (u_long)Maxmem * PAGE_SIZE / du->dk_dd.d_secsize;
 2095 
 2096 
 2097         secpertrk = du->dk_dd.d_nsectors;
 2098         secpercyl = du->dk_dd.d_secpercyl;
 2099         nblocks = lp->d_partitions[part].p_size;
 2100         blkoff = lp->d_partitions[part].p_offset;
 2101         /* XXX */
 2102         ds_offset = du->dk_slices->dss_slices[dkslice(dev)].ds_offset;
 2103         blkoff += ds_offset;
 2104 
 2105 #if 0
 2106         printf("part %d, nblocks %lu, dumplo %ld num %ld\n",
 2107             part, nblocks, dumplo, num);
 2108 #endif
 2109 
 2110         /* Check transfer bounds against partition size. */
 2111         if (dumplo < 0 || dumplo + num > nblocks)
 2112                 return (EINVAL);
 2113 
 2114         /* Check if we are being called recursively. */
 2115         if (wddoingadump)
 2116                 return (EFAULT);
 2117 
 2118 #if 0
 2119         /* Mark controller active for if we panic during the dump. */
 2120         wdtab[du->dk_ctrlr].b_active = 1;
 2121 #endif
 2122         wddoingadump = 1;
 2123 
 2124         /* Recalibrate the drive. */
 2125         DELAY(5);               /* ATA spec XXX NOT */
 2126         if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
 2127             || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
 2128             || wdsetctlr(du) != 0) {
 2129                 wderror((struct buf *)NULL, du, "wddump: recalibrate failed");
 2130                 return (EIO);
 2131         }
 2132 
 2133         du->dk_flags |= DKFL_SINGLE;
 2134         addr = (char *) 0;
 2135         blknum = dumplo + blkoff;
 2136         while (num > 0) {
 2137                 blkcnt = num;
 2138                 if (blkcnt > MAXTRANSFER)
 2139                         blkcnt = MAXTRANSFER;
 2140                 if ((du->dk_flags & DKFL_LBA) == 0) {
 2141                         /* XXX keep transfer within current cylinder. */
 2142                         if ((blknum + blkcnt - 1) / secpercyl !=
 2143                             blknum / secpercyl)
 2144                                  blkcnt = secpercyl - (blknum % secpercyl);
 2145                 }
 2146                 blknext = blknum + blkcnt;
 2147 
 2148                 /*
 2149                  * See if one of the sectors is in the bad sector list
 2150                  * (if we have one).  If the first sector is bad, then
 2151                  * reduce the transfer to this one bad sector; if another
 2152                  * sector is bad, then reduce reduce the transfer to
 2153                  * avoid any bad sectors.
 2154                  */
 2155                 if (du->dk_flags & DKFL_SINGLE
 2156                     && dsgetbad(dev, du->dk_slices) != NULL) {
 2157                   for (blkchk = blknum; blkchk < blknum + blkcnt; blkchk++) {
 2158                         daddr_t blknew;
 2159                         blknew = transbad144(dsgetbad(dev, du->dk_slices),
 2160                                              blkchk - ds_offset) + ds_offset;
 2161                         if (blknew != blkchk) {
 2162                                 /* Found bad block. */
 2163                                 blkcnt = blkchk - blknum;
 2164                                 if (blkcnt > 0) {
 2165                                         blknext = blknum + blkcnt;
 2166                                         goto out;
 2167                                 }
 2168                                 blkcnt = 1;
 2169                                 blknext = blknum + blkcnt;
 2170 #if 1 || defined(WDDEBUG)
 2171                                 printf("bad block %ld -> %ld\n",
 2172                                    (long)blknum, (long)blknew);
 2173 #endif
 2174                                 break;
 2175                         }
 2176                     }
 2177                 }
 2178 out:
 2179 
 2180                 /* Compute disk address. */
 2181                 if (du->dk_flags & DKFL_LBA) {
 2182                         sector = (blknum >> 0) & 0xff;
 2183                         cylin = (blknum >> 8) & 0xffff;
 2184                         head = ((blknum >> 24) & 0xf) | WDSD_LBA;
 2185                 } else {
 2186                         cylin = blknum / secpercyl;
 2187                         head = (blknum % secpercyl) / secpertrk;
 2188                         sector = blknum % secpertrk;
 2189                 }
 2190 
 2191 #if 0
 2192                 /* Let's just talk about this first... */
 2193                 printf("cylin %ld head %ld sector %ld addr %p count %ld\n",
 2194                     cylin, head, sector, addr, blkcnt);
 2195                 cngetc();
 2196 #endif
 2197 
 2198                 /* Do the write. */
 2199                 if (wdcommand(du, cylin, head, sector, blkcnt, WDCC_WRITE)
 2200                     != 0) {
 2201                         wderror((struct buf *)NULL, du,
 2202                                 "wddump: timeout waiting to to give command");
 2203                         return (EIO);
 2204                 }
 2205                 while (blkcnt != 0) {
 2206                         if (is_physical_memory((vm_offset_t)addr))
 2207                                 pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
 2208                                            trunc_page((vm_offset_t)addr), VM_PROT_READ, TRUE);
 2209                         else
 2210                                 pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
 2211                                            trunc_page(0), VM_PROT_READ, TRUE);
 2212 
 2213                         /* Ready to send data? */
 2214                         DELAY(5);       /* ATA spec */
 2215                         if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT)
 2216                             < 0) {
 2217                                 wderror((struct buf *)NULL, du,
 2218                                         "wddump: timeout waiting for DRQ");
 2219                                 return (EIO);
 2220                         }
 2221                         if (du->dk_flags & DKFL_32BIT)
 2222                                 outsl(du->dk_port + wd_data,
 2223                                       CADDR1 + ((int)addr & PAGE_MASK),
 2224                                       DEV_BSIZE / sizeof(long));
 2225                         else
 2226                                 outsw(du->dk_port + wd_data,
 2227                                       CADDR1 + ((int)addr & PAGE_MASK),
 2228                                       DEV_BSIZE / sizeof(short));
 2229                         addr += DEV_BSIZE;
 2230                         /*
 2231                          * If we are dumping core, it may take a while.
 2232                          * So reassure the user and hold off any watchdogs.
 2233                          */
 2234                         if ((unsigned)addr % (1024 * 1024) == 0) {
 2235 #ifdef  HW_WDOG
 2236                                 if (wdog_tickler)
 2237                                         (*wdog_tickler)();
 2238 #endif /* HW_WDOG */
 2239                                 printf("%ld ", num / (1024 * 1024 / DEV_BSIZE));
 2240                         }
 2241                         num--;
 2242                         blkcnt--;
 2243                 }
 2244 
 2245                 /* Wait for completion. */
 2246                 DELAY(5);       /* ATA spec XXX NOT */
 2247                 if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) < 0) {
 2248                         wderror((struct buf *)NULL, du,
 2249                                 "wddump: timeout waiting for status");
 2250                         return (EIO);
 2251                 }
 2252 
 2253                 /* Check final status. */
 2254                 if ((du->dk_status
 2255                     & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ | WDCS_ERR))
 2256                     != (WDCS_READY | WDCS_SEEKCMPLT)) {
 2257                         wderror((struct buf *)NULL, du,
 2258                                 "wddump: extra DRQ, or error");
 2259                         return (EIO);
 2260                 }
 2261 
 2262                 /* Update block count. */
 2263                 blknum = blknext;
 2264 
 2265                 /* Operator aborting dump? */
 2266                 if (cncheckc() != -1)
 2267                         return (EINTR);
 2268         }
 2269         return (0);
 2270 }
 2271 
 2272 static void
 2273 wderror(struct buf *bp, struct disk *du, char *mesg)
 2274 {
 2275         if (bp == NULL)
 2276                 printf("wd%d: %s", du->dk_lunit, mesg);
 2277         else
 2278                 diskerr(bp, "wd", mesg, LOG_PRINTF, du->dk_skip,
 2279                         dsgetlabel(bp->b_dev, du->dk_slices));
 2280         printf(" (status %b error %b)\n",
 2281                du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS);
 2282 }
 2283 
 2284 /*
 2285  * Discard any interrupts that were latched by the interrupt system while
 2286  * we were doing polled i/o.
 2287  */
 2288 static void
 2289 wdflushirq(struct disk *du, int old_ipl)
 2290 {
 2291 #ifdef CMD640
 2292         wdtab[du->dk_ctrlr_cmd640].b_active = 2;
 2293         splx(old_ipl);
 2294         (void)splbio();
 2295         wdtab[du->dk_ctrlr_cmd640].b_active = 0;
 2296 #else
 2297         wdtab[du->dk_ctrlr].b_active = 2;
 2298         splx(old_ipl);
 2299         (void)splbio();
 2300         wdtab[du->dk_ctrlr].b_active = 0;
 2301 #endif  
 2302 }
 2303 
 2304 /*
 2305  * Reset the controller.
 2306  */
 2307 static int
 2308 wdreset(struct disk *du)
 2309 {
 2310         int     err = 0;
 2311 
 2312         if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
 2313                 wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie);
 2314         (void)wdwait(du, 0, TIMEOUT);
 2315         outb(du->dk_altport, WDCTL_IDS | WDCTL_RST);
 2316         DELAY(10 * 1000);
 2317         outb(du->dk_altport, WDCTL_IDS);
 2318         outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
 2319 #ifdef ATAPI
 2320         if (wdwait(du, 0, TIMEOUT) != 0)
 2321                 err = 1;                /* no IDE drive found */
 2322         du->dk_error = inb(du->dk_port + wd_error);
 2323         if (du->dk_error != 0x01)
 2324                 err = 1;                /* the drive is incompatible */
 2325 #else
 2326         if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0) {
 2327                 printf("wdreset: error1: 0x%x\n", du->dk_error);
 2328                 return (1);
 2329         }
 2330 #endif
 2331         outb(du->dk_altport, WDCTL_4BIT);
 2332         return (err);
 2333 }
 2334 
 2335 /*
 2336  * Sleep until driver is inactive.
 2337  * This is used only for avoiding rare race conditions, so it is unimportant
 2338  * that the sleep may be far too short or too long.
 2339  */
 2340 static void
 2341 wdsleep(int ctrlr, char *wmesg)
 2342 {
 2343         int s = splbio();
 2344 #ifdef CMD640
 2345         if (eide_quirks & Q_CMD640B)
 2346                 ctrlr = PRIMARY;
 2347 #endif
 2348         while (wdtab[ctrlr].b_active)
 2349                 tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
 2350         splx(s);
 2351 }
 2352 
 2353 static void
 2354 wdtimeout(void *cdu)
 2355 {
 2356         struct disk *du;
 2357         int     x;
 2358         static  int     timeouts;
 2359 
 2360         du = (struct disk *)cdu;
 2361         x = splbio();
 2362         if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
 2363                 if(timeouts++ <= 5) {
 2364                         char *msg;
 2365 
 2366                         msg = (timeouts > 5) ?
 2367 "Last time I say: interrupt timeout.  Probably a portable PC." :
 2368 "interrupt timeout";
 2369                         wderror((struct buf *)NULL, du, msg);
 2370                         if (du->dk_dmacookie)
 2371                                 printf("wd%d: wdtimeout() DMA status %b\n", 
 2372                                        du->dk_lunit,
 2373                                        wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie), 
 2374                                        WDDS_BITS);
 2375                 }
 2376                 wdunwedge(du);
 2377                 wdflushirq(du, x);
 2378                 du->dk_skip = 0;
 2379                 du->dk_flags |= DKFL_SINGLE;
 2380                 wdstart(du->dk_ctrlr);
 2381         }
 2382         timeout(wdtimeout, cdu, hz);
 2383         splx(x);
 2384 }
 2385 
 2386 /*
 2387  * Reset the controller after it has become wedged.  This is different from
 2388  * wdreset() so that wdreset() can be used in the probe and so that this
 2389  * can restore the geometry .
 2390  */
 2391 static int
 2392 wdunwedge(struct disk *du)
 2393 {
 2394         struct disk *du1;
 2395         int     lunit;
 2396 
 2397         /* Schedule other drives for recalibration. */
 2398         for (lunit = 0; lunit < NWD; lunit++)
 2399                 if ((du1 = wddrives[lunit]) != NULL && du1 != du
 2400                     && du1->dk_ctrlr == du->dk_ctrlr
 2401                     && du1->dk_state > WANTOPEN)
 2402                         du1->dk_state = WANTOPEN;
 2403 
 2404         DELAY(RECOVERYTIME);
 2405         if (wdreset(du) == 0) {
 2406                 /*
 2407                  * XXX - recalibrate current drive now because some callers
 2408                  * aren't prepared to have its state change.
 2409                  */
 2410                 if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) == 0
 2411                     && wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) == 0
 2412                     && wdsetctlr(du) == 0)
 2413                         return (0);
 2414         }
 2415         wderror((struct buf *)NULL, du, "wdunwedge failed");
 2416         return (1);
 2417 }
 2418 
 2419 /*
 2420  * Wait uninterruptibly until controller is not busy and either certain
 2421  * status bits are set or an error has occurred.
 2422  * The wait is usually short unless it is for the controller to process
 2423  * an entire critical command.
 2424  * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
 2425  * or 0 for no errors.
 2426  * Return controller status in du->dk_status and, if there was a controller
 2427  * error, return the error code in du->dk_error.
 2428  */
 2429 #ifdef WD_COUNT_RETRIES
 2430 static int min_retries[NWDC];
 2431 #endif
 2432 
 2433 static int
 2434 wdwait(struct disk *du, u_char bits_wanted, int timeout)
 2435 {
 2436         int     wdc;
 2437         u_char  status;
 2438 
 2439 #define POLLING         1000
 2440 
 2441         wdc = du->dk_port;
 2442         timeout += POLLING;
 2443 
 2444 /*
 2445  * This delay is really too long, but does not impact the performance
 2446  * as much when using the multi-sector option.  Shorter delays have
 2447  * caused I/O errors on some drives and system configs.  This should
 2448  * probably be fixed if we develop a better short term delay mechanism.
 2449  */
 2450         DELAY(1);
 2451 
 2452         do {
 2453 #ifdef WD_COUNT_RETRIES
 2454                 if (min_retries[du->dk_ctrlr] > timeout
 2455                     || min_retries[du->dk_ctrlr] == 0)
 2456                         min_retries[du->dk_ctrlr] = timeout;
 2457 #endif
 2458                 du->dk_status = status = inb(wdc + wd_status);
 2459 #ifdef ATAPI
 2460                 /*
 2461                  * Atapi drives have a very interesting feature, when attached
 2462                  * as a slave on the IDE bus, and there is no master.
 2463                  * They release the bus after getting the command.
 2464                  * We should reselect the drive here to get the status.
 2465                  */
 2466                 if (status == 0xff) {
 2467                         outb(wdc + wd_sdh, WDSD_IBM | du->dk_unit << 4);
 2468                         du->dk_status = status = inb(wdc + wd_status);
 2469                 }
 2470 #endif
 2471                 if (!(status & WDCS_BUSY)) {
 2472                         if (status & WDCS_ERR) {
 2473                                 du->dk_error = inb(wdc + wd_error);
 2474                                 /*
 2475                                  * We once returned here.  This is wrong
 2476                                  * because the error bit is apparently only
 2477                                  * valid after the controller has interrupted
 2478                                  * (e.g., the error bit is stale when we wait
 2479                                  * for DRQ for writes).  So we can't depend
 2480                                  * on the error bit at all when polling for
 2481                                  * command completion.
 2482                                  */
 2483                         }
 2484                         if ((status & bits_wanted) == bits_wanted) {
 2485                                 return (status & WDCS_ERR);
 2486                         }
 2487                 }
 2488                 if (timeout < TIMEOUT)
 2489                         /*
 2490                          * Switch to a polling rate of about 1 KHz so that
 2491                          * the timeout is almost machine-independent.  The
 2492                          * controller is taking a long time to respond, so
 2493                          * an extra msec won't matter.
 2494                          */
 2495                         DELAY(1000);
 2496                 else
 2497                         DELAY(1);
 2498         } while (--timeout != 0);
 2499         return (-1);
 2500 }
 2501 
 2502 static wd_devsw_installed = 0;
 2503 
 2504 static void     wd_drvinit(void *unused)
 2505 {
 2506 
 2507         if( ! wd_devsw_installed ) {
 2508                 if (wd_cdevsw.d_maxio == 0)
 2509                         wd_cdevsw.d_maxio = 248 * 512;
 2510                 cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &wd_cdevsw);
 2511                 wd_devsw_installed = 1;
 2512         }
 2513 }
 2514 
 2515 SYSINIT(wddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wd_drvinit,NULL)
 2516 
 2517 
 2518 
 2519 #endif /* NWDC > 0 */

Cache object: e11a537b23880edf69bf77ae9b87b8dd


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