home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / i386 / isa / wd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-09  |  33.1 KB  |  1,208 lines

  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.  *    @(#)wd.c    7.2 (Berkeley) 5/9/91
  37.  */
  38.  
  39. /* TODO:peel out buffer at low ipl,
  40.    speed improvement, rewrite to clean code from garbage artifacts */
  41.  
  42.  
  43. #include "wd.h"
  44. #if    NWD > 0
  45.  
  46. #include "param.h"
  47. #include "dkbad.h"
  48. #include "systm.h"
  49. #include "conf.h"
  50. #include "file.h"
  51. #include "stat.h"
  52. #include "ioctl.h"
  53. #include "disklabel.h"
  54. #include "buf.h"
  55. #include "uio.h"
  56. #include "i386/isa/isa_device.h"
  57. #include "i386/isa/icu.h"
  58. #include "i386/isa/wdreg.h"
  59. #include "syslog.h"
  60. #include "vm/vm.h"
  61.  
  62. #define    RETRIES        5    /* number of retries before giving up */
  63. #define    MAXTRANSFER    32    /* max size of transfer in page clusters */
  64.  
  65. #define wdctlr(dev)    ((minor(dev) & 0x80) >> 7)
  66. #define wdunit(dev)    ((minor(dev) & 0x60) >> 5)
  67. #define wdpart(dev)    ((minor(dev) & 0x1f))
  68.  
  69. #define b_cylin    b_resid        /* cylinder number for doing IO to */
  70.                 /* shares an entry in the buf struct */
  71.  
  72. /*
  73.  * Drive states.  Used for open and format operations.
  74.  * States < OPEN (> 0) are transient, during an open operation.
  75.  * OPENRAW is used for unlabeled disks, and for floppies, to inhibit
  76.  * bad-sector forwarding.
  77.  */
  78. #define RAWDISK        8        /* raw disk operation, no translation*/
  79. #define ISRAWSTATE(s)    (RAWDISK&(s))    /* are we in a raw state? */
  80. #define DISKSTATE(s)    (~RAWDISK&(s))    /* are we in a given state regardless
  81.                        of raw or cooked mode? */
  82.  
  83. #define    CLOSED        0        /* disk is closed. */
  84.                     /* "cooked" disk states */
  85. #define    WANTOPEN    1        /* open requested, not started */
  86. #define    RECAL        2        /* doing restore */
  87. #define    RDLABEL        3        /* reading pack label */
  88. #define    RDBADTBL    4        /* reading bad-sector table */
  89. #define    OPEN        5        /* done with open */
  90.  
  91. #define    WANTOPENRAW    (WANTOPEN|RAWDISK)    /* raw WANTOPEN */
  92. #define    RECALRAW    (RECAL|RAWDISK)    /* raw open, doing restore */
  93. #define    OPENRAW        (OPEN|RAWDISK)    /* open, but unlabeled disk or floppy */
  94.  
  95.  
  96. /*
  97.  * The structure of a disk drive.
  98.  */
  99. struct    disk {
  100.     struct disklabel dk_dd;    /* device configuration data */
  101.     long    dk_bc;        /* byte count left */
  102.     short    dk_skip;    /* blocks already transferred */
  103.     char    dk_unit;    /* physical unit number */
  104.     char    dk_state;    /* control state */
  105.     u_char    dk_status;    /* copy of status reg. */
  106.     u_char    dk_error;    /* copy of error reg. */
  107.     short    dk_open;    /* open/closed refcnt */
  108.         u_long  dk_copenpart;   /* character units open on this drive */
  109.         u_long  dk_bopenpart;   /* block units open on this drive */
  110.         u_long  dk_openpart;    /* all units open on this drive */
  111.     short    dk_wlabel;    /* label writable? */
  112. };
  113.  
  114. /*
  115.  * This label is used as a default when initializing a new or raw disk.
  116.  * It really only lets us access the first track until we know more.
  117.  */
  118. struct disklabel dflt_sizes = {
  119.     DISKMAGIC, DTYPE_ST506, 0, "default", "",
  120.         512,        /* sector size */
  121.         17,        /* # of sectors per track */
  122.         8,        /* # of tracks per cylinder */
  123.         766,        /* # of cylinders per unit */
  124.         17*8,        /* # of sectors per cylinder */
  125.         766*8*17,    /* # of sectors per unit */
  126.         0,        /* # of spare sectors per track */
  127.         0,        /* # of spare sectors per cylinder */
  128.         0,        /* # of alt. cylinders per unit */
  129.         3600,        /* rotational speed */
  130.         1,        /* hardware sector interleave */
  131.         0,        /* sector 0 skew, per track */
  132.         0,        /* sector 0 skew, per cylinder */
  133.         0,        /* head switch time, usec */
  134.         0,        /* track-to-track seek, usec */
  135.         0,        /* generic flags */
  136.         0,0,0,0,0,
  137.         0,0,0,0,0,
  138.         DISKMAGIC,
  139.         0,
  140.         8,
  141.         8192,
  142.         8192,
  143.     
  144.     {{21600,    0, 0,0,0,0},    /* A=root filesystem */
  145.     {21600,    40, 0,0,0,0},
  146.     {660890, 0, 0,0,0,0},    /* C=whole disk */
  147.     {216000,    80, 0,0,0,0},
  148.     {0,    0, 0,0,0,0},
  149.     {0,    0, 0,0,0,0},
  150.     {0,    0, 0,0,0,0},
  151.     {399600,    480, 0,0,0,0}}
  152. };
  153.  
  154. static    struct    dkbad    dkbad[NWD];
  155. struct    disk    wddrives[NWD] = {0};    /* table of units */
  156. struct    buf    wdtab = {0};
  157. struct    buf    wdutab[NWD] = {0};    /* head of queue per drive */
  158. struct    buf    rwdbuf[NWD] = {0};    /* buffers for raw IO */
  159. long    wdxfer[NWD] = {0};        /* count of transfers */
  160. int    writeprotected[NWD] = { 0 };
  161. int    wdprobe(), wdattach(), wdintr();
  162. struct    isa_driver wddriver = {
  163.     wdprobe, wdattach, "wd",
  164. };
  165.  
  166. static wdc;
  167. /*
  168.  * Probe routine
  169.  */
  170. wdprobe(dvp)
  171.     struct isa_device *dvp;
  172. {
  173. wdc = dvp->id_iobase;
  174.  
  175. #ifdef lint
  176.     wdintr(0);
  177. #endif
  178.     /* XXX sorry, needs to be better */
  179.     outb(wdc+wd_error, 0x5a) ;    /* error register not writable */
  180.     outb(wdc+wd_cyl_lo, 0xa5) ;    /* but all of cyllo are implemented */
  181.     if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5)
  182.         return(1) ;
  183.     return (0);
  184. }
  185.  
  186. /*
  187.  * attach each drive if possible.
  188.  */
  189. wdattach(dvp)
  190.     struct isa_device *dvp;
  191. {
  192.     int unit = dvp->id_unit;
  193.  
  194.     outb(wdc+wd_ctlr,12);
  195.     DELAY(1000);
  196.     outb(wdc+wd_ctlr,8);
  197. }
  198.  
  199. /* Read/write routine for a buffer.  Finds the proper unit, range checks
  200.  * arguments, and schedules the transfer.  Does not wait for the transfer
  201.  * to complete.  Multi-page transfers are supported.  All I/O requests must
  202.  * be a multiple of a sector in length.
  203.  */
  204. wdstrategy(bp)
  205.     register struct buf *bp;    /* IO operation to perform */
  206. {
  207.     register struct buf *dp;
  208.     register struct disk *du;    /* Disk unit to do the IO.    */
  209.     register struct partition *p;
  210.     long maxsz, sz;
  211.     int    unit = wdunit(bp->b_dev);
  212.     int    s;
  213.  
  214.     if ((unit >= NWD) || (bp->b_blkno < 0)) {
  215.         printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
  216.             unit, bp->b_blkno, bp->b_bcount);
  217.         pg("wd:error in wdstrategy");
  218.         bp->b_flags |= B_ERROR;
  219.         goto bad;
  220.     }
  221.     if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
  222.         printf("wd%d: write protected\n", unit);
  223.         goto bad;
  224.     }
  225.     du = &wddrives[unit];
  226.     if (DISKSTATE(du->dk_state) != OPEN)
  227.         goto q;
  228. #ifdef old
  229.     /*
  230.      * Convert DEV_BSIZE "blocks" to sectors.
  231.      * Note: doing the conversions this way limits the partition size
  232.      * to about 8 million sectors (1-8 Gb).
  233.      */
  234.     blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize;
  235.     if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) ||
  236.         bp->b_bcount >= MAXTRANSFER * CLBYTES) {
  237.         bp->b_flags |= B_ERROR;
  238.         goto bad;
  239.     }
  240.     nblocks = du->dk_dd.d_partitions[part].p_size;
  241.     cyloff = du->dk_dd.d_partitions[part].p_offset;
  242.     if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) {
  243.         if (blknum == nblocks)
  244.             bp->b_resid = bp->b_bcount;
  245.         else
  246.             bp->b_flags |= B_ERROR;
  247.         goto bad;
  248.     }
  249.     bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff;
  250. #else
  251.         /*
  252.          * Determine the size of the transfer, and make sure it is
  253.          * within the boundaries of the partition.
  254.          */
  255.         p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)];
  256.         maxsz = p->p_size;
  257.         sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
  258.         if (bp->b_blkno + p->p_offset <= LABELSECTOR &&
  259. #if LABELSECTOR != 0
  260.             bp->b_blkno + p->p_offset + sz > LABELSECTOR &&
  261. #endif
  262.             (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) {
  263.                 bp->b_error = EROFS;
  264.                 goto bad;
  265.         }
  266.         if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
  267.                 /* if exactly at end of disk, return an EOF */
  268.                 if (bp->b_blkno == maxsz) {
  269.                         bp->b_resid = bp->b_bcount;
  270.                         biodone(bp);
  271.                         return;
  272.                 }
  273.                 /* or truncate if part of it fits */
  274.                 sz = maxsz - bp->b_blkno;
  275.                 if (sz <= 0)
  276.                         goto bad;
  277.                 bp->b_bcount = sz << DEV_BSHIFT;
  278.         }
  279.         bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl;
  280. #endif
  281. q:
  282.     dp = &wdutab[unit];
  283.     s = splhigh();
  284.     disksort(dp, bp);
  285.     if (dp->b_active == 0)
  286.         wdustart(du);        /* start drive if idle */
  287.     if (wdtab.b_active == 0)
  288.         wdstart(s);        /* start IO if controller idle */
  289.     splx(s);
  290.     return;
  291.  
  292. bad:
  293.     bp->b_error = EINVAL;
  294.     biodone(bp);
  295. }
  296.  
  297. /* Routine to queue a read or write command to the controller.  The request is
  298.  * linked into the active list for the controller.  If the controller is idle,
  299.  * the transfer is started.
  300.  */
  301. wdustart(du)
  302.     register struct disk *du;
  303. {
  304.     register struct buf *bp, *dp;
  305.  
  306.     dp = &wdutab[du->dk_unit];
  307.     if (dp->b_active)
  308.         return;
  309.     bp = dp->b_actf;
  310.     if (bp == NULL)
  311.         return;    
  312.     dp->b_forw = NULL;
  313.     if (wdtab.b_actf  == NULL)        /* link unit into active list */
  314.         wdtab.b_actf = dp;
  315.     else
  316.         wdtab.b_actl->b_forw = dp;
  317.     wdtab.b_actl = dp;
  318.     dp->b_active = 1;        /* mark the drive as busy */
  319. }
  320.  
  321. /*
  322.  * Controller startup routine.  This does the calculation, and starts
  323.  * a single-sector read or write operation.  Called to start a transfer,
  324.  * or from the interrupt routine to continue a multi-sector transfer.
  325.  * RESTRICTIONS:
  326.  * 1.    The transfer length must be an exact multiple of the sector size.
  327.  */
  328.  
  329. static wd_sebyse;
  330.  
  331. wdstart()
  332. {
  333.     register struct disk *du;    /* disk unit for IO */
  334.     register struct buf *bp;
  335.     struct buf *dp;
  336.     register struct bt_bad *bt_ptr;
  337.     long    blknum, pagcnt, cylin, head, sector;
  338.     long    secpertrk, secpercyl, addr, i;
  339.     int    unit, s;
  340.  
  341. loop:
  342.     dp = wdtab.b_actf;
  343.     if (dp == NULL)
  344.         return;
  345.     bp = dp->b_actf;
  346.     if (bp == NULL) {
  347.         wdtab.b_actf = dp->b_forw;
  348.         goto loop;
  349.     }
  350.     unit = wdunit(bp->b_dev);
  351.     du = &wddrives[unit];
  352.     if (DISKSTATE(du->dk_state) <= RDLABEL) {
  353.         if (wdcontrol(bp)) {
  354.             dp->b_actf = bp->av_forw;
  355.             goto loop;    /* done */
  356.         }
  357.         return;
  358.     }
  359.     secpertrk = du->dk_dd.d_nsectors;
  360.     secpercyl = du->dk_dd.d_secpercyl;
  361.     /*
  362.      * Convert DEV_BSIZE "blocks" to sectors.
  363.      */
  364.     blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize
  365.         + du->dk_skip;
  366. #ifdef    WDDEBUG
  367.     if (du->dk_skip == 0) {
  368.         dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
  369.             (bp->b_flags & B_READ) ? "read" : "write",
  370.             bp->b_bcount, blknum);
  371.     } else {
  372.         dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));
  373.     }
  374. #endif
  375.  
  376.     addr = (int) bp->b_un.b_addr;
  377.     if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
  378.     cylin = blknum / secpercyl;
  379.     head = (blknum % secpercyl) / secpertrk;
  380.     sector = blknum % secpertrk;
  381.     if (DISKSTATE(du->dk_state) == OPEN)
  382.         cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset
  383.                 / secpercyl;
  384.  
  385.     /* 
  386.      * See if the current block is in the bad block list.
  387.      * (If we have one, and not formatting.)
  388.      */
  389.     if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)
  390.         for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
  391.         if (bt_ptr->bt_cyl > cylin)
  392.             /* Sorted list, and we passed our cylinder. quit. */
  393.             break;
  394.         if (bt_ptr->bt_cyl == cylin &&
  395.                 bt_ptr->bt_trksec == (head << 8) + sector) {
  396.             /*
  397.              * Found bad block.  Calculate new block addr.
  398.              * This starts at the end of the disk (skip the
  399.              * last track which is used for the bad block list),
  400.              * and works backwards to the front of the disk.
  401.              */
  402. #ifdef    WDDEBUG
  403.                 dprintf(DDSK,"--- badblock code -> Old = %d; ",
  404.                 blknum);
  405. #endif
  406.             blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
  407.                 - (bt_ptr - dkbad[unit].bt_bad) - 1;
  408.             cylin = blknum / secpercyl;
  409.             head = (blknum % secpercyl) / secpertrk;
  410.             sector = blknum % secpertrk;
  411. #ifdef    WDDEBUG
  412.                 dprintf(DDSK, "new = %d\n", blknum);
  413. #endif
  414.             break;
  415.         }
  416.     }
  417.     sector += 1;    /* sectors begin with 1, not 0 */
  418.  
  419.     wdtab.b_active = 1;        /* mark controller active */
  420.  
  421.     if(du->dk_skip==0 || wd_sebyse) {
  422.     if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;
  423.     while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;
  424.     /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/
  425.     outb(wdc+wd_precomp, 0xff);
  426.     /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
  427.     /*if (bp->b_flags & B_FORMAT) {
  428.         wr(wdc+wd_sector, du->dk_dd.dk_gap3);
  429.         wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
  430.     } else {*/
  431.     if(wd_sebyse)
  432.         outb(wdc+wd_seccnt, 1);
  433.     else
  434.         outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));
  435.     outb(wdc+wd_sector, sector);
  436.  
  437.     outb(wdc+wd_cyl_lo, cylin);
  438.     outb(wdc+wd_cyl_hi, cylin >> 8);
  439.  
  440.     /* Set up the SDH register (select drive).     */
  441.     outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
  442.     while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
  443.  
  444.     /*if (bp->b_flags & B_FORMAT)
  445.         wr(wdc+wd_command, WDCC_FORMAT);
  446.     else*/
  447.         outb(wdc+wd_command,
  448.             (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
  449. #ifdef    WDDEBUG
  450.     dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n",
  451.         sector, cylin, head, addr, inb(wdc+wd_altsts));
  452. #endif
  453. }
  454.         
  455.     /* If this is a read operation, just go away until it's done.    */
  456.     if (bp->b_flags & B_READ) return;
  457.  
  458.     /* Ready to send data?    */
  459.     while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
  460.  
  461.     /* ASSUMES CONTIGUOUS MEMORY */
  462.     outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
  463.     du->dk_bc -= 512;
  464. }
  465.  
  466. /*
  467.  * these are globally defined so they can be found
  468.  * by the debugger easily in the case of a system crash
  469.  */
  470. daddr_t wd_errsector;
  471. daddr_t wd_errbn;
  472. unsigned char wd_errstat;
  473.  
  474. /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
  475.  * errors on the current operation, mark it done if necessary, and start
  476.  * the next request.  Also check for a partially done transfer, and
  477.  * continue with the next chunk if so.
  478.  */
  479. wdintr(unit)
  480. {
  481.     register struct    disk *du;
  482.     register struct buf *bp, *dp;
  483.     int status;
  484.     char partch ;
  485.     static wd_haderror;
  486.  
  487.     /* Shouldn't need this, but it may be a slow controller.    */
  488.     while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
  489.     if (!wdtab.b_active) {
  490.         printf("wd: extra interrupt\n");
  491.         return;
  492.     }
  493.  
  494. #ifdef    WDDEBUG
  495.     dprintf(DDSK,"I ");
  496. #endif
  497.     dp = wdtab.b_actf;
  498.     bp = dp->b_actf;
  499.     du = &wddrives[wdunit(bp->b_dev)];
  500.     partch = wdpart(bp->b_dev) + 'a';
  501.     if (DISKSTATE(du->dk_state) <= RDLABEL) {
  502.         if (wdcontrol(bp))
  503.             goto done;
  504.         return;
  505.     }
  506.     if (status & (WDCS_ERR | WDCS_ECCCOR)) {
  507.         wd_errstat = inb(wdc+wd_error);        /* save error status */
  508. #ifdef    WDDEBUG
  509.         printf("status %x error %x\n", status, wd_errstat);
  510. #endif
  511.         if(wd_sebyse == 0) {
  512.             wd_haderror = 1;
  513.             goto outt;
  514.         }
  515.         /*if (bp->b_flags & B_FORMAT) {
  516.             du->dk_status = status;
  517.             du->dk_error = wdp->wd_error;
  518.             bp->b_flags |= B_ERROR;
  519.             goto done;
  520.         }*/
  521.         
  522.         wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
  523.             (((unsigned long) bp->b_blkno * DEV_BSIZE /
  524.                 du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
  525.             du->dk_skip;
  526.         wd_errbn = bp->b_blkno
  527.             + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
  528.         if (status & WDCS_ERR) {
  529.             if (++wdtab.b_errcnt < RETRIES) {
  530.                 wdtab.b_active = 0;
  531.             } else {
  532.                 printf("wd%d%c: ", du->dk_unit, partch);
  533.                 printf(
  534.                 "hard %s error, sn %d bn %d status %b error %b\n",
  535.                     (bp->b_flags & B_READ)? "read":"write",
  536.                     wd_errsector, wd_errbn, status, WDCS_BITS,
  537.                     wd_errstat, WDERR_BITS);
  538.                 bp->b_flags |= B_ERROR;    /* flag the error */
  539.             }
  540.         } else
  541.             log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
  542.                 du->dk_unit, partch, wd_errsector,
  543.                 wd_errbn);
  544.     }
  545. outt:
  546.  
  547.     /*
  548.      * If this was a successful read operation, fetch the data.
  549.      */
  550.     if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
  551.         int chk, dummy;
  552.  
  553.         chk = min(256,du->dk_bc/2);
  554.         /* Ready to receive data?    */
  555.         while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
  556.  
  557. /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
  558.         insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
  559.         du->dk_bc -= 2*chk;
  560.         while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
  561.     }
  562.  
  563.     wdxfer[du->dk_unit]++;
  564.     if (wdtab.b_active) {
  565.         if ((bp->b_flags & B_ERROR) == 0) {
  566.             du->dk_skip++;        /* Add to successful sectors. */
  567.             if (wdtab.b_errcnt) {
  568.                 log(LOG_WARNING, "wd%d%c: ",
  569.                         du->dk_unit, partch);
  570.                 log(LOG_WARNING,
  571.             "soft %s error, sn %d bn %d error %b retries %d\n",
  572.                     (bp->b_flags & B_READ) ? "read" : "write",
  573.                     wd_errsector, wd_errbn, wd_errstat,
  574.                     WDERR_BITS, wdtab.b_errcnt);
  575.             }
  576.             wdtab.b_errcnt = 0;
  577.  
  578.             /* see if more to transfer */
  579.             /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
  580.             if (du->dk_bc > 0 && wd_haderror == 0) {
  581.                 wdstart();
  582.                 return;        /* next chunk is started */
  583.             } else if (wd_haderror && wd_sebyse == 0) {
  584.                 du->dk_skip = 0;
  585.                 wd_haderror = 0;
  586.                 wd_sebyse = 1;
  587.                 wdstart();
  588.                 return;        /* redo xfer sector by sector */
  589.             }
  590.         }
  591.  
  592. done:
  593.         wd_sebyse = 0;
  594.         /* done with this transfer, with or without error */
  595.         wdtab.b_actf = dp->b_forw;
  596.         wdtab.b_errcnt = 0;
  597.         du->dk_skip = 0;
  598.         dp->b_active = 0;
  599.         dp->b_actf = bp->av_forw;
  600.         dp->b_errcnt = 0;
  601.         bp->b_resid = 0;
  602.         biodone(bp);
  603.     }
  604.     wdtab.b_active = 0;
  605.     if (dp->b_actf)
  606.         wdustart(du);        /* requeue disk if more io to do */
  607.     if (wdtab.b_actf)
  608.         wdstart();        /* start IO on next drive */
  609. }
  610.  
  611. /*
  612.  * Initialize a drive.
  613.  */
  614. wdopen(dev, flags, fmt)
  615.         dev_t dev;
  616.         int flags, fmt;
  617. {
  618.     register unsigned int unit;
  619.     register struct buf *bp;
  620.     register struct disk *du;
  621.         int part = wdpart(dev), mask = 1 << part;
  622.         struct partition *pp;
  623.     struct dkbad *db;
  624.     int i, error = 0;
  625.  
  626.     unit = wdunit(dev);
  627.     if (unit >= NWD) return (ENXIO) ;
  628.     du = &wddrives[unit];
  629. #ifdef notdef
  630.     if (du->dk_open){
  631.         du->dk_open++ ;
  632.         return(0);    /* already is open, don't mess with it */
  633.     }
  634. #endif
  635.     du->dk_unit = unit;
  636.     wdutab[unit].b_actf = NULL;
  637.     /*if (flags & O_NDELAY)
  638.         du->dk_state = WANTOPENRAW;
  639.     else*/
  640.         du->dk_state = WANTOPEN;
  641.     /*
  642.      * Use the default sizes until we've read the label,
  643.      * or longer if there isn't one there.
  644.      */
  645.     du->dk_dd = dflt_sizes;
  646.  
  647.     /*
  648.      * Recal, read of disk label will be done in wdcontrol
  649.      * during first read operation.
  650.      */
  651.     bp = geteblk(512);
  652.     bp->b_dev = dev & 0xff00;
  653.     bp->b_bcount = 0;
  654.     bp->b_blkno = LABELSECTOR;
  655.     bp->b_flags = B_READ;
  656.     wdstrategy(bp);
  657.     biowait(bp);
  658.     if (bp->b_flags & B_ERROR) {
  659.         error = ENXIO;
  660.         du->dk_state = CLOSED;
  661.         goto done;
  662.     }
  663.     if (du->dk_state == OPENRAW) {
  664.         du->dk_state = OPENRAW;
  665.         goto done;
  666.     }
  667.     /*
  668.      * Read bad sector table into memory.
  669.      */
  670.     i = 0;
  671.     do {
  672.         bp->b_flags = B_BUSY | B_READ;
  673.         bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
  674.             + i;
  675.         if (du->dk_dd.d_secsize > DEV_BSIZE)
  676.             bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
  677.         else
  678.             bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
  679.         bp->b_bcount = du->dk_dd.d_secsize;
  680.         bp->b_cylin = du->dk_dd.d_ncylinders - 1;
  681.         wdstrategy(bp);
  682.         biowait(bp);
  683.     } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
  684.         i < du->dk_dd.d_nsectors);
  685.     db = (struct dkbad *)(bp->b_un.b_addr);
  686. #define DKBAD_MAGIC 0x4321
  687.     if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
  688.         db->bt_flag == DKBAD_MAGIC) {
  689.         dkbad[unit] = *db;
  690.         du->dk_state = OPEN;
  691.     } else {
  692.         printf("wd%d: %s bad-sector file\n", unit,
  693.             (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
  694.         error = ENXIO ;
  695.         du->dk_state = OPENRAW;
  696.     }
  697. done:
  698.     bp->b_flags = B_INVAL | B_AGE;
  699.     brelse(bp);
  700.     if (error == 0)
  701.         du->dk_open = 1;
  702.  
  703.         /*
  704.          * Warn if a partion is opened
  705.          * that overlaps another partition which is open
  706.          * unless one is the "raw" partition (whole disk).
  707.          */
  708. #define RAWPART         8               /* 'x' partition */     /* XXX */
  709.         if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
  710.         int    start, end;
  711.  
  712.                 pp = &du->dk_dd.d_partitions[part];
  713.                 start = pp->p_offset;
  714.                 end = pp->p_offset + pp->p_size;
  715.                 for (pp = du->dk_dd.d_partitions;
  716.                      pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
  717.             pp++) {
  718.                         if (pp->p_offset + pp->p_size <= start ||
  719.                             pp->p_offset >= end)
  720.                                 continue;
  721.                         if (pp - du->dk_dd.d_partitions == RAWPART)
  722.                                 continue;
  723.                         if (du->dk_openpart & (1 << (pp -
  724.                     du->dk_dd.d_partitions)))
  725.                                 log(LOG_WARNING,
  726.                                     "wd%d%c: overlaps open partition (%c)\n",
  727.                                     unit, part + 'a',
  728.                                     pp - du->dk_dd.d_partitions + 'a');
  729.                 }
  730.         }
  731.         if (part >= du->dk_dd.d_npartitions)
  732.                 return (ENXIO);
  733.         du->dk_openpart |= mask;
  734.         switch (fmt) {
  735.         case S_IFCHR:
  736.                 du->dk_copenpart |= mask;
  737.                 break;
  738.         case S_IFBLK:
  739.                 du->dk_bopenpart |= mask;
  740.                 break;
  741.         }
  742.     return (error);
  743. }
  744.  
  745. /*
  746.  * Implement operations other than read/write.
  747.  * Called from wdstart or wdintr during opens and formats.
  748.  * Uses finite-state-machine to track progress of operation in progress.
  749.  * Returns 0 if operation still in progress, 1 if completed.
  750.  */
  751. wdcontrol(bp)
  752.     register struct buf *bp;
  753. {
  754.     register struct disk *du;
  755.     register unit;
  756.     unsigned char  stat;
  757.     int s, cnt;
  758.     extern int bootdev, cyloffset;
  759.  
  760.     du = &wddrives[wdunit(bp->b_dev)];
  761.     unit = du->dk_unit;
  762.     switch (DISKSTATE(du->dk_state)) {
  763.  
  764.     tryagainrecal:
  765.     case WANTOPEN:            /* set SDH, step rate, do restore */
  766. #ifdef    WDDEBUG
  767.         dprintf(DDSK,"wd%d: recal ", unit);
  768. #endif
  769.         s = splbio();        /* not called from intr level ... */
  770.         outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
  771.         wdtab.b_active = 1;
  772.         outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
  773.         du->dk_state++;
  774.         splx(s);
  775.         return(0);
  776.  
  777.     case RECAL:
  778.         if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
  779.             printf("wd%d: recal", du->dk_unit);
  780.             if (unit == 0) {
  781.                 printf(": status %b error %b\n",
  782.                     stat, WDCS_BITS,
  783.                     inb(wdc+wd_error), WDERR_BITS);
  784.                 if (++wdtab.b_errcnt < RETRIES)
  785.                     goto tryagainrecal;
  786.             }
  787.             goto badopen;
  788.         }
  789.  
  790.         /* some compaq controllers require this ... */
  791.         wdsetctlr(bp->b_dev, du);
  792.  
  793.         wdtab.b_errcnt = 0;
  794.         if (ISRAWSTATE(du->dk_state)) {
  795.             du->dk_state = OPENRAW;
  796.             return(1);
  797.         }
  798. retry:
  799. #ifdef    WDDEBUG
  800.         dprintf(DDSK,"rdlabel ");
  801. #endif
  802. if( cyloffset < 0 || cyloffset > 8192) cyloffset=0;
  803.         /*
  804.          * Read in sector LABELSECTOR to get the pack label
  805.          * and geometry.
  806.          */
  807.         outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
  808.         outb(wdc+wd_seccnt, 1);
  809.         outb(wdc+wd_sector, LABELSECTOR+1);
  810.         /*if (bp->b_dev == bootdev) {
  811.             (wdc+wd_cyl_lo = cyloffset & 0xff;
  812.             (wdc+wd_cyl_hi = cyloffset >> 8;
  813.         } else {
  814.             (wdc+wd_cyl_lo = 0;
  815.             (wdc+wd_cyl_hi = 0;
  816.         }*/
  817.         outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
  818.         outb(wdc+wd_cyl_hi, (cyloffset >> 8));
  819.         outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
  820.         outb(wdc+wd_command, WDCC_READ);
  821.         du->dk_state = RDLABEL;
  822.         return(0);
  823.  
  824.     case RDLABEL:
  825.         if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
  826.             if (++wdtab.b_errcnt < RETRIES)
  827.                 goto retry;
  828.             printf("wd%d: read label", unit);
  829.             goto badopen;
  830.         }
  831.  
  832.         insw(wdc+wd_data, bp->b_un.b_addr, 256);
  833.  
  834.         if (((struct disklabel *)
  835.             (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) {
  836.                du->dk_dd =
  837.              * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
  838.         } else {
  839.             printf("wd%d: bad disk label\n", du->dk_unit);
  840.             du->dk_state = OPENRAW;
  841.         }
  842.  
  843.         s = splbio();        /* not called from intr level ... */
  844.         while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
  845.  
  846.         wdsetctlr(bp->b_dev, du);
  847.  
  848.         outb(wdc+wd_seccnt, 0);
  849.         splx(s);
  850.  
  851.         if (du->dk_state == RDLABEL)
  852.             du->dk_state = RDBADTBL;
  853.         /*
  854.          * The rest of the initialization can be done
  855.          * by normal means.
  856.          */
  857.         return(1);
  858.  
  859.     default:
  860.         panic("wdcontrol");
  861.     }
  862.     /* NOTREACHED */
  863.  
  864. badopen:
  865.     printf(": status %b error %b\n",
  866.         stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
  867.     du->dk_state = OPENRAW;
  868.     return(1);
  869. }
  870.  
  871. wdsetctlr(dev, du) dev_t dev; struct disk *du; {
  872.     int stat;
  873.  
  874.     outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders);
  875.     outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8);
  876.     outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
  877.     outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
  878.     outb(wdc+wd_command, 0x91);
  879.  
  880.     while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
  881.     stat = inb(wdc+wd_error);
  882.     return(stat);
  883. }
  884.  
  885. /* ARGSUSED */
  886. wdclose(dev, flags, fmt)
  887.         dev_t dev;
  888.         int flags, fmt;
  889. {
  890.     register struct disk *du;
  891.  
  892.     du = &wddrives[wdunit(dev)];
  893.     du->dk_open-- ;
  894.     /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
  895. }
  896.  
  897. wdioctl(dev,cmd,addr,flag)
  898.     dev_t dev;
  899.     caddr_t addr;
  900. {
  901.     int unit = wdunit(dev);
  902.     register struct disk *du;
  903.     int error = 0;
  904.     struct uio auio;
  905.     struct iovec aiov;
  906.     /*int wdformat();*/
  907.  
  908.     du = &wddrives[unit];
  909.  
  910.     switch (cmd) {
  911.  
  912.     case DIOCGDINFO:
  913.         *(struct disklabel *)addr = du->dk_dd;
  914.         break;
  915.  
  916.         case DIOCGPART:
  917.                 ((struct partinfo *)addr)->disklab = &du->dk_dd;
  918.                 ((struct partinfo *)addr)->part =
  919.                     &du->dk_dd.d_partitions[wdpart(dev)];
  920.                 break;
  921.  
  922.         case DIOCSDINFO:
  923.                 if ((flag & FWRITE) == 0)
  924.                         error = EBADF;
  925.                 else
  926.                         error = setdisklabel(&du->dk_dd,
  927.                     (struct disklabel *)addr,
  928.                          0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
  929.                 /*if (error == 0 && dk->dk_state == OPENRAW &&
  930.                     vdreset_drive(vddinfo[unit]))
  931.                         dk->dk_state = OPEN;*/
  932.         wdsetctlr(dev, du);
  933.                 break;
  934.  
  935.         case DIOCWLABEL:
  936.                 if ((flag & FWRITE) == 0)
  937.                         error = EBADF;
  938.                 else
  939.                         du->dk_wlabel = *(int *)addr;
  940.                 break;
  941.  
  942.         case DIOCWDINFO:
  943.                 if ((flag & FWRITE) == 0)
  944.                         error = EBADF;
  945.                 else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
  946.                   0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
  947.                         int wlab;
  948.  
  949.                         /*if (error == 0 && dk->dk_state == OPENRAW &&
  950.                             vdreset_drive(vddinfo[unit]))
  951.                                 dk->dk_state = OPEN; */
  952.             wdsetctlr(dev, du);
  953.  
  954.                         /* simulate opening partition 0 so write succeeds */
  955.                         /* dk->dk_openpart |= (1 << 0);            /* XXX */
  956.                         wlab = du->dk_wlabel;
  957.                         du->dk_wlabel = 1;
  958.                         error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
  959.                         /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
  960.                         du->dk_wlabel = wlab;
  961.                 }
  962.                 break;
  963.  
  964. #ifdef notyet
  965.     case DIOCGDINFOP:
  966.         *(struct disklabel **)addr = &(du->dk_dd);
  967.         break;
  968.  
  969.     case DIOCWFORMAT:
  970.         if ((flag & FWRITE) == 0)
  971.             error = EBADF;
  972.         else {
  973.             register struct format_op *fop;
  974.  
  975.             fop = (struct format_op *)addr;
  976.             aiov.iov_base = fop->df_buf;
  977.             aiov.iov_len = fop->df_count;
  978.             auio.uio_iov = &aiov;
  979.             auio.uio_iovcnt = 1;
  980.             auio.uio_resid = fop->df_count;
  981.             auio.uio_segflg = 0;
  982.             auio.uio_offset =
  983.                 fop->df_startblk * du->dk_dd.d_secsize;
  984.             error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
  985.                 minphys, &auio);
  986.             fop->df_count -= auio.uio_resid;
  987.             fop->df_reg[0] = du->dk_status;
  988.             fop->df_reg[1] = du->dk_error;
  989.         }
  990.         break;
  991. #endif
  992.  
  993.     default:
  994.         error = ENOTTY;
  995.         break;
  996.     }
  997.     return (error);
  998. }
  999.  
  1000. /*wdformat(bp)
  1001.     struct buf *bp;
  1002. {
  1003.  
  1004.     bp->b_flags |= B_FORMAT;
  1005.     return (wdstrategy(bp));
  1006. }*/
  1007.  
  1008. /*
  1009.  * Routines to do raw IO for a unit.
  1010.  */
  1011. wdread(dev, uio)            /* character read routine */
  1012.     dev_t dev;
  1013.     struct uio *uio;
  1014. {
  1015.     int unit = wdunit(dev) ;
  1016.  
  1017.     if (unit >= NWD) return(ENXIO);
  1018.     return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio));
  1019. }
  1020.  
  1021.  
  1022. wdwrite(dev, uio)            /* character write routine */
  1023.     dev_t dev;
  1024.     struct uio *uio;
  1025. {
  1026.     int unit = wdunit(dev) ;
  1027.  
  1028.     if (unit >= NWD) return(ENXIO);
  1029.     return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio));
  1030. }
  1031.  
  1032. wdsize(dev)
  1033.     dev_t dev;
  1034. {
  1035.     register unit = wdunit(dev);
  1036.     register part = wdpart(dev);
  1037.     register struct disk *du;
  1038.     register val ;
  1039.  
  1040.     if (unit >= NWD) return(-1);
  1041.     if (wddrives[unit].dk_state == 0) {
  1042.         val = wdopen (dev, 0);
  1043.         if (val < 0)
  1044.             return (-1);
  1045.     }
  1046.     du = &wddrives[unit];
  1047.     return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
  1048.         du->dk_dd.d_secsize / 512));
  1049. }
  1050.  
  1051. extern        char *vmmap;            /* poor name! */
  1052.  
  1053. wddump(dev)            /* dump core after a system crash */
  1054.     dev_t dev;
  1055. {
  1056.     register struct disk *du;    /* disk unit to do the IO */
  1057.     register struct bt_bad *bt_ptr;
  1058.     long    num;            /* number of sectors to write */
  1059.     int    unit, part;
  1060.     long    cyloff, blknum, blkcnt;
  1061.     long    cylin, head, sector, stat;
  1062.     long    secpertrk, secpercyl, nblocks, i;
  1063.     char *addr;
  1064.     extern    int Maxmem;
  1065.     static  wddoingadump = 0 ;
  1066.     extern CMAP1;
  1067.     extern char CADDR1[];
  1068.  
  1069.     
  1070. #ifdef ARGO
  1071. outb(0x461,0);    /* disable failsafe timer */
  1072. #endif
  1073.     addr = (char *) 0;        /* starting address */
  1074.     /* size of memory to dump */
  1075.     num = Maxmem;
  1076.     unit = wdunit(dev);        /* eventually support floppies? */
  1077.     part = wdpart(dev);        /* file system */
  1078.     /* check for acceptable drive number */
  1079.     if (unit >= NWD) return(ENXIO);
  1080.  
  1081.     du = &wddrives[unit];
  1082.     /* was it ever initialized ? */
  1083.     if (du->dk_state < OPEN) return (ENXIO) ;
  1084.  
  1085.     /* Convert to disk sectors */
  1086.     num = (u_long) num * NBPG / du->dk_dd.d_secsize;
  1087.  
  1088.     /* check if controller active */
  1089.     /*if (wdtab.b_active) return(EFAULT); */
  1090.     if (wddoingadump) return(EFAULT);
  1091.  
  1092.     secpertrk = du->dk_dd.d_nsectors;
  1093.     secpercyl = du->dk_dd.d_secpercyl;
  1094.     nblocks = du->dk_dd.d_partitions[part].p_size;
  1095.     cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
  1096.  
  1097. /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
  1098.     /* check transfer bounds against partition size */
  1099.     if ((dumplo < 0) || ((dumplo + num) > nblocks))
  1100.         return(EINVAL);
  1101.  
  1102.     /*wdtab.b_active = 1;        /* mark controller active for if we
  1103.                        panic during the dump */
  1104.     wddoingadump = 1  ;  i = 100000 ;
  1105.     while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
  1106.     outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
  1107.     outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
  1108.     while (inb(wdc+wd_status) & WDCS_BUSY) ;
  1109.  
  1110.     /* some compaq controllers require this ... */
  1111.     wdsetctlr(dev, du);
  1112.     
  1113.     blknum = dumplo;
  1114.     while (num > 0) {
  1115. #ifdef notdef
  1116.         if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
  1117.         if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
  1118.             blkcnt = secpercyl - (blknum % secpercyl);
  1119.                 /* keep transfer within current cylinder */
  1120. #endif
  1121.         pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
  1122.  
  1123.         /* compute disk address */
  1124.         cylin = blknum / secpercyl;
  1125.         head = (blknum % secpercyl) / secpertrk;
  1126.         sector = blknum % secpertrk;
  1127.         cylin += cyloff;
  1128.  
  1129. #ifdef notyet
  1130.         /* 
  1131.          * See if the current block is in the bad block list.
  1132.          * (If we have one.)
  1133.          */
  1134.                 for (bt_ptr = dkbad[unit].bt_bad;
  1135.                 bt_ptr->bt_cyl != -1; bt_ptr++) {
  1136.             if (bt_ptr->bt_cyl > cylin)
  1137.                 /* Sorted list, and we passed our cylinder.
  1138.                     quit. */
  1139.                 break;
  1140.             if (bt_ptr->bt_cyl == cylin &&
  1141.                 bt_ptr->bt_trksec == (head << 8) + sector) {
  1142.             /*
  1143.              * Found bad block.  Calculate new block addr.
  1144.              * This starts at the end of the disk (skip the
  1145.              * last track which is used for the bad block list),
  1146.              * and works backwards to the front of the disk.
  1147.              */
  1148.                 blknum = (du->dk_dd.d_secperunit)
  1149.                     - du->dk_dd.d_nsectors
  1150.                     - (bt_ptr - dkbad[unit].bt_bad) - 1;
  1151.                 cylin = blknum / secpercyl;
  1152.                 head = (blknum % secpercyl) / secpertrk;
  1153.                 sector = blknum % secpertrk;
  1154.                 break;
  1155.             }
  1156.  
  1157. #endif
  1158.         sector++;        /* origin 1 */
  1159.  
  1160.         /* select drive.     */
  1161.         outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
  1162.         while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
  1163.  
  1164.         /* transfer some blocks */
  1165.         outb(wdc+wd_sector, sector);
  1166.         outb(wdc+wd_seccnt,1);
  1167.         outb(wdc+wd_cyl_lo, cylin);
  1168.         outb(wdc+wd_cyl_hi, cylin >> 8);
  1169. #ifdef notdef
  1170.         /* lets just talk about this first...*/
  1171.         pg ("sdh 0%o sector %d cyl %d addr 0x%x",
  1172.             inb(wdc+wd_sdh), inb(wdc+wd_sector),
  1173.             inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
  1174. #endif
  1175. #ifdef ODYSSEUS
  1176. if(cylin < 46 || cylin > 91)pg("oops");
  1177. #endif
  1178. #ifdef PRIAM
  1179. if(cylin < 40 || cylin > 79)pg("oops");
  1180. #endif
  1181.         outb(wdc+wd_command, WDCC_WRITE);
  1182.         
  1183.         /* Ready to send data?    */
  1184.         while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
  1185.         if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
  1186.  
  1187.         outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
  1188.         (int) addr += 512;
  1189.  
  1190.         if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
  1191.         /* Check data request (should be done).         */
  1192.         if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
  1193.  
  1194.         /* wait for completion */
  1195.         for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
  1196.                 if (i < 0) return (EIO) ;
  1197.         }
  1198.         /* error check the xfer */
  1199.         if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
  1200.         /* update block count */
  1201.         num--;
  1202.         blknum++ ;
  1203. if (num % 100 == 0) printf(".") ;
  1204.     }
  1205.     return(0);
  1206. }
  1207. #endif
  1208.