added my responsibility for the `cpm' port
[unix-history] / sys / i386 / isa / wd.c
index 04cd82c..5d9bf91 100644 (file)
@@ -37,11 +37,10 @@ static int wdtest = 0;
  * SUCH DAMAGE.
  *
  *     from: @(#)wd.c  7.2 (Berkeley) 5/9/91
  * SUCH DAMAGE.
  *
  *     from: @(#)wd.c  7.2 (Berkeley) 5/9/91
- *     $Id: wd.c,v 1.31 1994/02/22 18:51:27 rgrimes Exp $
+ *     $Id: wd.c,v 1.39 1994/06/07 01:36:39 phk Exp $
  */
 
 /* TODO:
  */
 
 /* TODO:
- *     o Fix timeout from 2 to about 4 seconds.
  *     o Bump error count after timeout.
  *     o Satisfy ATA timing in all cases.
  *     o Finish merging berry/sos timeout code (bump error count...).
  *     o Bump error count after timeout.
  *     o Satisfy ATA timing in all cases.
  *     o Finish merging berry/sos timeout code (bump error count...).
@@ -84,11 +83,11 @@ static int wdtest = 0;
 #include "syslog.h"
 #include "vm/vm.h"
 
 #include "syslog.h"
 #include "vm/vm.h"
 
-#define        TIMEOUT         10000   /* XXX? WDCC_DIAGNOSE can take > 1.1 sec */
-
+#define TIMEOUT                10000
 #define        RETRIES         5       /* number of retries before giving up */
 #define RECOVERYTIME   500000  /* usec for controller to recover after err */
 #define        MAXTRANSFER     256     /* max size of transfer in sectors */
 #define        RETRIES         5       /* number of retries before giving up */
 #define RECOVERYTIME   500000  /* usec for controller to recover after err */
 #define        MAXTRANSFER     256     /* max size of transfer in sectors */
+#define BAD144_NO_CYL  0xffff  /* XXX should be in dkbad.h; bad144.c uses -1 */
 
 #ifdef notyet
 #define wdnoreloc(dev) (minor(dev) & 0x80)     /* ignore partition table */
 
 #ifdef notyet
 #define wdnoreloc(dev) (minor(dev) & 0x80)     /* ignore partition table */
@@ -150,6 +149,7 @@ struct disk {
        struct dos_partition
                dk_dospartitions[NDOSPART];     /* DOS view of disk */
        struct dkbad dk_bad;    /* bad sector table */
        struct dos_partition
                dk_dospartitions[NDOSPART];     /* DOS view of disk */
        struct dkbad dk_bad;    /* bad sector table */
+       long    dk_badsect[127];        /* 126 plus trailing -1 marker */
 };
 
 static struct disk *wddrives[NWD];     /* table of units */
 };
 
 static struct disk *wddrives[NWD];     /* table of units */
@@ -160,6 +160,8 @@ static struct buf rwdbuf[NWD];      /* buffers for raw IO */
 #endif
 static long wdxfer[NWD];       /* count of transfers */
 
 #endif
 static long wdxfer[NWD];       /* count of transfers */
 
+
+static void bad144intern(struct disk *);
 static int wdprobe(struct isa_device *dvp);
 static int wdattach(struct isa_device *dvp);
 static void wdustart(struct disk *du);
 static int wdprobe(struct isa_device *dvp);
 static int wdattach(struct isa_device *dvp);
 static void wdustart(struct disk *du);
@@ -210,9 +212,46 @@ wdprobe(struct isa_device *dvp)
 
        /* execute a controller only command */
        if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
 
        /* execute a controller only command */
        if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
-           || wdwait(du, 0, TIMEOUT) != 0)
+           || wdwait(du, 0, TIMEOUT) < 0)
                goto nodevice;
 
                goto nodevice;
 
+       /*
+        * drive(s) did not time out during diagnostic :
+        * Get error status and check that both drives are OK.
+        * Table 9-2 of ATA specs suggests that we must check for 
+        * a value of 0x01 
+        *
+        * Strangely, some controllers will return a status of
+        * 0x81 (drive 0 OK, drive 1 failure), and then when
+        * the DRV bit is set, return status of 0x01 (OK) for
+        * drive 2.  (This seems to contradict the ATA spec.)
+        */
+       du->dk_error = inb(du->dk_port + wd_error);
+       /* printf("Error : %x\n", du->dk_error); */
+       if(du->dk_error != 0x01) {
+               if(du->dk_error & 0x80) { /* drive 1 failure */ 
+
+                       /* first set the DRV bit */
+                       u_int sdh;
+                       sdh = inb(du->dk_port+ wd_sdh);
+                       sdh = sdh | 0x10;
+                       outb(du->dk_port+ wd_sdh, sdh);
+
+                       /* Wait, to make sure drv 1 has completed diags */
+                       if ( wdwait(du, 0, TIMEOUT) < 0)
+                               goto nodevice;
+
+                       /* Get status for drive 1 */
+                       du->dk_error = inb(du->dk_port + wd_error); 
+                       /* printf("Error (drv 1) : %x\n", du->dk_error); */
+
+                       if(du->dk_error != 0x01)
+                               goto nodevice;
+               } else  /* drive 0 fail */
+                       goto nodevice;
+       }
+       
+
        free(du, M_TEMP);
        return (IO_WDCSIZE);
 
        free(du, M_TEMP);
        return (IO_WDCSIZE);
 
@@ -257,11 +296,14 @@ wdattach(struct isa_device *dvp)
                /*
                 * Print out description of drive.
                 * wdp_model can be [0..40] bytes, thus \0 can be missing so
                /*
                 * Print out description of drive.
                 * wdp_model can be [0..40] bytes, thus \0 can be missing so
-                * use %40s to print it.
+                * so copy it and add a null before printing.
                 */
                if (wdgetctlr(du) == 0) {
                 */
                if (wdgetctlr(du) == 0) {
-                   printf("wdc%d: unit %d (wd%d): <%40s>\n",
-                       dvp->id_unit, unit, lunit, du->dk_params.wdp_model);
+                   char buf[sizeof(du->dk_params.wdp_model) + 1];
+                   bcopy(du->dk_params.wdp_model, buf, sizeof(buf)-1);
+                   buf[sizeof(buf)-1] = '\0';
+                   printf("wdc%d: unit %d (wd%d): <%s>\n",
+                       dvp->id_unit, unit, lunit, buf);
                    if (du->dk_params.wdp_heads == 0)
                        printf("wd%d: size unknown\n", lunit);
                    else
                    if (du->dk_params.wdp_heads == 0)
                        printf("wd%d: size unknown\n", lunit);
                    else
@@ -316,13 +358,14 @@ wdstrategy(register struct buf *bp)
                goto done;
        }
 
                goto done;
        }
 
+#if !defined(DISKLABEL_UNPROTECTED)
        /* "soft" write protect check */
        if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
                bp->b_error = EROFS;
                bp->b_flags |= B_ERROR;
                goto done;
        }
        /* "soft" write protect check */
        if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
                bp->b_error = EROFS;
                bp->b_flags |= B_ERROR;
                goto done;
        }
-
+#endif /* !defined(DISKLABEL_UNPROTECTED) */
        /*
         * Do bounds checking, adjust transfer, and set b_cylin.
         */
        /*
         * Do bounds checking, adjust transfer, and set b_cylin.
         */
@@ -331,10 +374,32 @@ wdstrategy(register struct buf *bp)
                                    du->dk_wlabel) <= 0)
                goto done;
 
                                    du->dk_wlabel) <= 0)
                goto done;
 
+       /*
+        * Check for *any* block on this transfer being on the bad block list
+        * if it is, then flag the block as a transfer that requires
+        * bad block handling.  Also, used as a hint for low level disksort
+        * clustering code to keep from coalescing a bad transfer into
+        * a normal transfer.  Single block transfers for a large number of
+        * blocks associated with a cluster I/O are undersirable.
+        */
+       if( du->dk_flags & DKFL_BADSECT) {
+               int i;
+               int nsecs = howmany(bp->b_bcount, DEV_BSIZE);
+               int blkend = bp->b_pblkno + nsecs;
+               for(i=0;du->dk_badsect[i] != -1 && du->dk_badsect[i] < blkend;i++) {
+                       if( du->dk_badsect[i] >= bp->b_pblkno) {
+                               bp->b_flags |= B_BAD;
+                               break;
+                       }
+               }
+       }
+
        /* queue transfer on drive, activate drive and controller if idle */
        dp = &wdutab[lunit];
        s = splbio();
        /* queue transfer on drive, activate drive and controller if idle */
        dp = &wdutab[lunit];
        s = splbio();
-       disksort(dp, bp);
+
+       cldisksort(dp, bp, 254*DEV_BSIZE);
+
        if (dp->b_active == 0)
                wdustart(du);   /* start drive */
 
        if (dp->b_active == 0)
                wdustart(du);   /* start drive */
 
@@ -350,8 +415,10 @@ wdstrategy(register struct buf *bp)
        return;
 
 done:
        return;
 
 done:
+       s = splbio();
        /* toss transfer, we're done early */
        biodone(bp);
        /* toss transfer, we're done early */
        biodone(bp);
+       splx(s);
 }
 
 /*
 }
 
 /*
@@ -438,7 +505,7 @@ loop:
        }
 
        /* calculate transfer details */
        }
 
        /* calculate transfer details */
-       blknum = bp->b_blkno + du->dk_skip;
+       blknum = bp->b_pblkno + du->dk_skip;
 #ifdef WDDEBUG
        if (du->dk_skip == 0)
                printf("wd%d: wdstart: %s %d@%d; map ", lunit,
 #ifdef WDDEBUG
        if (du->dk_skip == 0)
                printf("wd%d: wdstart: %s %d@%d; map ", lunit,
@@ -447,67 +514,49 @@ loop:
        else
                printf(" %d)%x", du->dk_skip, inb(du->dk_port + wd_altsts));
 #endif
        else
                printf(" %d)%x", du->dk_skip, inb(du->dk_port + wd_altsts));
 #endif
-       if (du->dk_skip == 0)
-               du->dk_bc = bp->b_bcount;
 
        lp = &du->dk_dd;
        secpertrk = lp->d_nsectors;
        secpercyl = lp->d_secpercyl;
 
        lp = &du->dk_dd;
        secpertrk = lp->d_nsectors;
        secpercyl = lp->d_secpercyl;
-       if (wddospart(bp->b_dev))
-               blknum += du->dk_dd2.d_partitions[wdpart(bp->b_dev)].p_offset;
-       else
-               blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
-       cylin = blknum / secpercyl;
-       head = (blknum % secpercyl) / secpertrk;
-       sector = blknum % secpertrk;
 
 
-       /* 
-        * See if the current block is in the bad block list.
-        * (If we have one, and not formatting.)
-        */
-       if ((du->dk_flags & (DKFL_SINGLE | DKFL_BADSECT))
-           == (DKFL_SINGLE | DKFL_BADSECT))
-#define BAD144_NO_CYL  0xffff  /* XXX should be in dkbad.h; bad144.c uses -1 */
-           for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != BAD144_NO_CYL;
-                bt_ptr++) {
-               if (bt_ptr->bt_cyl > cylin)
-                       /* Sorted list, and we passed our cylinder. quit. */
-                       break;
-               if (bt_ptr->bt_cyl == cylin &&
-                   bt_ptr->bt_trksec == (head << 8) + sector) {
-                       /*
-                        * Found bad block.  Calculate new block number.
-                        * This starts at the end of the disk (skip the
-                        * last track which is used for the bad block list),
-                        * and works backwards to the front of the disk.
-                        */
-#ifdef WDDEBUG
-                       printf("--- badblock code -> Old = %ld; ", blknum);
-#endif
+       if (du->dk_skip == 0) {
+               du->dk_bc = bp->b_bcount;
+               if (bp->b_flags & B_BAD) {
+                       du->dk_flags |= DKFL_SINGLE;
+               }
+       }
+
+       if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT))         /* 19 Aug 92*/
+               == (DKFL_SINGLE|DKFL_BADSECT)) {
+               int i;
 
 
+               for(i=0;
+                       du->dk_badsect[i] != -1 && du->dk_badsect[i] <= blknum;
+                       i++) {
+
+                       if( du->dk_badsect[i] == blknum) {
                        /*
                         * XXX the offset of the bad sector table ought
                         * to be stored in the in-core copy of the table.
                         */
 #define BAD144_PART    2       /* XXX scattered magic numbers */
 #define BSD_PART       0       /* XXX should be 2 but bad144.c uses 0 */
                        /*
                         * XXX the offset of the bad sector table ought
                         * to be stored in the in-core copy of the table.
                         */
 #define BAD144_PART    2       /* XXX scattered magic numbers */
 #define BSD_PART       0       /* XXX should be 2 but bad144.c uses 0 */
-                       if (lp->d_partitions[BSD_PART].p_offset != 0)
-                               blknum = lp->d_partitions[BAD144_PART].p_offset
-                                        + lp->d_partitions[BAD144_PART].p_size;
-                       else
-                               blknum = lp->d_secperunit;
-                       blknum -= lp->d_nsectors + (bt_ptr - du->dk_bad.bt_bad)
-                                 + 1;
-
-                       cylin = blknum / secpercyl;
-                       head = (blknum % secpercyl) / secpertrk;
-                       sector = blknum % secpertrk;
-#ifdef WDDEBUG
-                       printf("new = %ld\n", blknum);
-#endif
-                       break;
+                               if (lp->d_partitions[BSD_PART].p_offset != 0)
+                                       blknum = lp->d_partitions[BAD144_PART].p_offset
+                                                + lp->d_partitions[BAD144_PART].p_size;
+                               else
+                                       blknum = lp->d_secperunit;
+                               blknum -= lp->d_nsectors + i + 1;
+                               
+                               break;
+                       }
                }
        }
                }
        }
+                               
+       
+       cylin = blknum / secpercyl;
+       head = (blknum % secpercyl) / secpertrk;
+       sector = blknum % secpertrk;
 
        wdtab[ctrlr].b_active = 1;      /* mark controller active */
 
 
        wdtab[ctrlr].b_active = 1;      /* mark controller active */
 
@@ -575,7 +624,7 @@ loop:
         * think).  Discarding them would be OK if the (special) file offset
         * was not advanced.
         */
         * think).  Discarding them would be OK if the (special) file offset
         * was not advanced.
         */
-       du->dk_timeout = 1 + 1;
+       du->dk_timeout = 1 + 3;
 
        /* If this is a read operation, just go away until it's done. */
        if (bp->b_flags & B_READ)
 
        /* If this is a read operation, just go away until it's done. */
        if (bp->b_flags & B_READ)
@@ -617,7 +666,9 @@ wdintr(int unit)
        if (wdtab[unit].b_active == 2)
                return;         /* intr in wdflushirq() */
        if (!wdtab[unit].b_active) {
        if (wdtab[unit].b_active == 2)
                return;         /* intr in wdflushirq() */
        if (!wdtab[unit].b_active) {
+#ifndef LAPTOP
                printf("wdc%d: extra interrupt\n", unit);
                printf("wdc%d: extra interrupt\n", unit);
+#endif
                return;
        }
 
                return;
        }
 
@@ -634,9 +685,15 @@ wdintr(int unit)
        /* is it not a transfer, but a control operation? */
        if (du->dk_state < OPEN) {
                wdtab[unit].b_active = 0;
        /* is it not a transfer, but a control operation? */
        if (du->dk_state < OPEN) {
                wdtab[unit].b_active = 0;
-               if (wdcontrol(bp))
+               switch (wdcontrol(bp)) {
+               case 0:
+                       return;
+               case 1:
                        wdstart(unit);
                        wdstart(unit);
-               return;
+                       return;
+               case 2:
+                       goto done;
+               }
        }
 
        /* have we an error? */
        }
 
        /* have we an error? */
@@ -680,6 +737,9 @@ oops:
                chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
 
                /* ready to receive data? */
                chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
 
                /* ready to receive data? */
+               if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
+                   != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
+                       wderror(bp, du, "wdintr: read intr arrived early");
                if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
                        wderror(bp, du, "wdintr: read error detected late");
                        goto oops;
                if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
                        wderror(bp, du, "wdintr: read error detected late");
                        goto oops;
@@ -720,9 +780,8 @@ outt:
                                return; /* redo xfer sector by sector */
                        }
                }
                                return; /* redo xfer sector by sector */
                        }
                }
-#ifdef B_FORMAT
+
 done: ;
 done: ;
-#endif
                /* done with this transfer, with or without error */
                du->dk_flags &= ~DKFL_SINGLE;
                wdtab[unit].b_actf = dp->b_forw;
                /* done with this transfer, with or without error */
                du->dk_flags &= ~DKFL_SINGLE;
                wdtab[unit].b_actf = dp->b_forw;
@@ -831,8 +890,10 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
 
                        du->dk_flags |= DKFL_BSDLABEL;
                        du->dk_flags &= ~DKFL_WRITEPROT;
 
                        du->dk_flags |= DKFL_BSDLABEL;
                        du->dk_flags &= ~DKFL_WRITEPROT;
-                       if (du->dk_dd.d_flags & D_BADSECT)
+                       if (du->dk_dd.d_flags & D_BADSECT) {
                                du->dk_flags |= DKFL_BADSECT;
                                du->dk_flags |= DKFL_BADSECT;
+                               bad144intern(du);
+                       }
 
                        /*
                         * Force WDRAW partition to be the whole disk.
 
                        /*
                         * Force WDRAW partition to be the whole disk.
@@ -920,7 +981,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
  * Implement operations other than read/write.
  * Called from wdstart or wdintr during opens and formats.
  * Uses finite-state-machine to track progress of operation in progress.
  * Implement operations other than read/write.
  * Called from wdstart or wdintr during opens and formats.
  * Uses finite-state-machine to track progress of operation in progress.
- * Returns 0 if operation still in progress, 1 if completed.
+ * Returns 0 if operation still in progress, 1 if completed, 2 if error.
  */
 static int
 wdcontrol(register struct buf *bp)
  */
 static int
 wdcontrol(register struct buf *bp)
@@ -952,7 +1013,7 @@ maybe_retry:
                                goto tryagainrecal;
                        bp->b_error = ENXIO;    /* XXX needs translation */
                        bp->b_flags |= B_ERROR;
                                goto tryagainrecal;
                        bp->b_error = ENXIO;    /* XXX needs translation */
                        bp->b_flags |= B_ERROR;
-                       return (1);
+                       return (2);
                }
                wdtab[ctrlr].b_errcnt = 0;
                du->dk_state = OPEN;
                }
                wdtab[ctrlr].b_errcnt = 0;
                du->dk_state = OPEN;
@@ -963,7 +1024,7 @@ maybe_retry:
                return (1);
        }
        panic("wdcontrol");
                return (1);
        }
        panic("wdcontrol");
-       return (1);
+       return (2);
 }
 
 /*
 }
 
 /*
@@ -999,20 +1060,43 @@ wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
 static int
 wdsetctlr(struct disk *du)
 {
 static int
 wdsetctlr(struct disk *du)
 {
+       int error = 0;
 #ifdef WDDEBUG
        printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
               du->dk_ctrlr, du->dk_unit,
               du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
               du->dk_dd.d_nsectors);
 #endif
 #ifdef WDDEBUG
        printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
               du->dk_ctrlr, du->dk_unit,
               du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
               du->dk_dd.d_nsectors);
 #endif
-       if (du->dk_dd.d_ntracks > 16) {
-               printf("wd%d: cannot handle %lu heads (truncating to 16)\n",
+       if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
+               struct wdparams *wp;
+
+               printf("wd%d: can't handle %lu heads from partition table ",
                       du->dk_lunit, du->dk_dd.d_ntracks);
                       du->dk_lunit, du->dk_dd.d_ntracks);
-               du->dk_dd.d_ntracks = 16;
+               /* obtain parameters */
+               wp = &du->dk_params;
+               if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
+                       printf("(controller value %lu restored)\n",
+                               wp->wdp_heads);
+                       du->dk_dd.d_ntracks = wp->wdp_heads;
+               }
+               else {
+                       printf("(truncating to 16)\n");
+                       du->dk_dd.d_ntracks = 16;
+               }
+       }
+
+       if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
+               printf("wd%d: cannot handle %lu sectors (max 255)\n",
+                      du->dk_lunit, du->dk_dd.d_nsectors);
+               error = 1;
+       }
+       if (error) {
+               wdtab[du->dk_ctrlr].b_errcnt += RETRIES;
+               return (1);
        }
        if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
                      du->dk_dd.d_nsectors, WDCC_IDC) != 0
        }
        if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
                      du->dk_dd.d_nsectors, WDCC_IDC) != 0
-           || wdwait(du, WDCS_READY, TIMEOUT) != 0) {
+           || wdwait(du, WDCS_READY, TIMEOUT) < 0) {
                wderror((struct buf *)NULL, du, "wdsetctlr failed");
                return (1);
        }
                wderror((struct buf *)NULL, du, "wdsetctlr failed");
                return (1);
        }
@@ -1047,7 +1131,7 @@ wdgetctlr(struct disk *du)
        struct wdparams *wp;
 
        if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
        struct wdparams *wp;
 
        if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
-           || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) < 0) {
+           || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
                /* XXX need to check error status after final transfer. */
                /*
                 * Old drives don't support WDCC_READP.  Try a seek to 0.
                /* XXX need to check error status after final transfer. */
                /*
                 * Old drives don't support WDCC_READP.  Try a seek to 0.
@@ -1194,8 +1278,10 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
        case DIOCSBAD:
                if ((flag & FWRITE) == 0)
                        error = EBADF;
        case DIOCSBAD:
                if ((flag & FWRITE) == 0)
                        error = EBADF;
-               else
+               else {
                        du->dk_bad = *(struct dkbad *)addr;
                        du->dk_bad = *(struct dkbad *)addr;
+                       bad144intern(du);
+               }
                break;
 
        case DIOCGDINFO:
                break;
 
        case DIOCGDINFO:
@@ -1714,4 +1800,27 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout)
        return (-1);
 }
 
        return (-1);
 }
 
+/*
+ * Internalize the bad sector table.
+ */
+void bad144intern(struct disk *du) {
+       int i;
+       if (du->dk_flags & DKFL_BADSECT) {
+               for (i = 0; i < 127; i++) {
+                       du->dk_badsect[i] = -1;
+               }
+               for (i = 0; i < 126; i++) {
+                       if (du->dk_bad.bt_bad[i].bt_cyl == 0xffff) {  
+                               break;
+                       } else {
+                               du->dk_badsect[i] =
+                                       du->dk_bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
+                                       (du->dk_bad.bt_bad[i].bt_trksec >> 8) * du->dk_dd.d_nsectors
++
+                                       (du->dk_bad.bt_bad[i].bt_trksec & 0x00ff);
+                       }
+               }
+       }
+}
+
 #endif /* NWDC > 0 */
 #endif /* NWDC > 0 */