Index: arch/sun3/conf/files.sun3 =================================================================== RCS file: /cvsroot/src/sys/arch/sun3/conf/files.sun3,v retrieving revision 1.89 diff -u -p -r1.89 files.sun3 --- arch/sun3/conf/files.sun3 23 Apr 2026 02:54:40 -0000 1.89 +++ arch/sun3/conf/files.sun3 30 May 2026 13:16:29 -0000 @@ -198,13 +198,13 @@ file arch/sun3/dev/cg2.c cgtwo needs-fl device xyc {drive = -1} attach xyc at vme -device xy: disk +device xy: disk, bad144 attach xy at xyc file arch/sun3/dev/xy.c xy | xyc needs-flag device xdc {drive = -1} attach xdc at vme -device xd: disk +device xd: disk, bad144 attach xd at xdc file arch/sun3/dev/xd.c xd | xdc needs-flag Index: arch/sun3/dev/xd.c =================================================================== RCS file: /cvsroot/src/sys/arch/sun3/dev/xd.c,v retrieving revision 1.81 diff -u -p -r1.81 xd.c --- arch/sun3/dev/xd.c 6 Sep 2025 21:20:20 -0000 1.81 +++ arch/sun3/dev/xd.c 30 May 2026 13:16:29 -0000 @@ -598,10 +598,9 @@ static void xd_init(struct xd_softc *xd) { struct xdc_softc *xdc; - struct dkbad *dkb; struct xd_iopb_drive *driopb; void *dvmabuf; - int rqno, err, spt, mb, blk, lcv, fullmode, newstate; + int rqno, err, spt, mb, blk, fullmode, newstate; xdc = xd->parent; xd->state = XD_DRIVE_ATTACHING; @@ -660,9 +659,6 @@ xd_init(struct xd_softc *xd) xd->nhead = 1; xd->nsect = 1; xd->sectpercyl = 1; - for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */ - xd->dkb.bt_bad[lcv].bt_cyl = - xd->dkb.bt_bad[lcv].bt_trksec = 0xffff; rqno = xdc_cmd(xdc, XDCMD_WRP, XDFUN_DRV, xd->xd_drive, 0, 0, 0, fullmode); XDC_DONE(xdc, rqno, err); @@ -713,6 +709,10 @@ xd_init(struct xd_softc *xd) * read bad144 table. this table resides on the first sector of the * last track of the disk (i.e. second cyl of "acyl" area). */ + + xd->bad144 = bad144_init(XDFM_BPS, xd->ncyl, xd->nhead, xd->nsect); + KASSERT(xd->bad144 != NULL); + blk = (xd->ncyl + xd->acyl - 1) * (xd->nhead * xd->nsect) + /* last cyl */ (xd->nhead - 1) * xd->nsect; /* last head */ rqno = xdc_cmd(xdc, XDCMD_RD, 0, xd->xd_drive, @@ -724,25 +724,10 @@ xd_init(struct xd_softc *xd) goto done; } - /* check dkbad for sanity */ - dkb = (struct dkbad *)dvmabuf; - for (lcv = 0; lcv < 126; lcv++) { - if ((dkb->bt_bad[lcv].bt_cyl == 0xffff || - dkb->bt_bad[lcv].bt_cyl == 0) && - dkb->bt_bad[lcv].bt_trksec == 0xffff) - continue; /* blank */ - if (dkb->bt_bad[lcv].bt_cyl >= xd->ncyl) - break; - if ((dkb->bt_bad[lcv].bt_trksec >> 8) >= xd->nhead) - break; - if ((dkb->bt_bad[lcv].bt_trksec & 0xff) >= xd->nsect) - break; - } - if (lcv != 126) { + err = bad144_set(xd->bad144, (struct dkbad *)dvmabuf); + if (err) { printf("%s: warning: invalid bad144 sector!\n", device_xname(xd->sc_dev)); - } else { - memcpy(&xd->dkb, dvmabuf, XDFM_BPS); } done: @@ -876,9 +861,9 @@ xdioctl(dev_t dev, u_long cmd, void *add if ((flag & FWRITE) == 0) return EBADF; s = splbio(); - memcpy(&xd->dkb, addr, sizeof(xd->dkb)); + error = bad144_set(xd->bad144, (struct dkbad *)addr); splx(s); - return 0; + return error; case DIOCSDINFO: /* set disk label */ if ((flag & FWRITE) == 0) @@ -1993,10 +1978,10 @@ xdc_error(struct xdc_softc *xdcsc, struc (iorq->mode & XD_MODE_B144) == 0) { advance = iorq->sectcnt - iopb->sectcnt; XDC_ADVANCE(iorq, advance); - if ((i = isbad(&iorq->xd->dkb, - iorq->blockno / iorq->xd->sectpercyl, - (iorq->blockno / iorq->xd->nsect) % iorq->xd->nhead, - iorq->blockno % iorq->xd->nsect)) != -1) { + if ((i = bad144_isbad_chs(iorq->xd->bad144, + iorq->blockno / iorq->xd->sectpercyl, + (iorq->blockno / iorq->xd->nsect) % iorq->xd->nhead, + iorq->blockno % iorq->xd->nsect)) != -1) { iorq->mode |= XD_MODE_B144; /* enter bad144 mode & * redirect */ iopb->errno = iopb->done = iopb->errs = 0; Index: arch/sun3/dev/xdvar.h =================================================================== RCS file: /cvsroot/src/sys/arch/sun3/dev/xdvar.h,v retrieving revision 1.12 diff -u -p -r1.12 xdvar.h --- arch/sun3/dev/xdvar.h 1 Feb 2011 20:19:32 -0000 1.12 +++ arch/sun3/dev/xdvar.h 30 May 2026 13:16:29 -0000 @@ -108,7 +108,7 @@ struct xd_softc { u_char nhead; /* number of heads */ u_char nsect; /* number of sectors per track */ u_char hw_spt; /* as above, but includes spare sectors */ - struct dkbad dkb; /* bad144 sectors */ + struct bad144_context *bad144; /* bad144 sectors */ }; /* Index: arch/sun3/dev/xy.c =================================================================== RCS file: /cvsroot/src/sys/arch/sun3/dev/xy.c,v retrieving revision 1.84 diff -u -p -r1.84 xy.c --- arch/sun3/dev/xy.c 21 Dec 2024 17:40:11 -0000 1.84 +++ arch/sun3/dev/xy.c 30 May 2026 13:16:29 -0000 @@ -537,7 +537,6 @@ static void xy_init(struct xy_softc *xy) { struct xyc_softc *xyc; - struct dkbad *dkb; void *dvmabuf; int err, spt, mb, blk, lcv, fullmode, newstate; @@ -573,9 +572,6 @@ xy_init(struct xy_softc *xy) xy->nhead = 1; xy->nsect = 1; xy->sectpercyl = 1; - for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */ - xy->dkb.bt_bad[lcv].bt_cyl = - xy->dkb.bt_bad[lcv].bt_trksec = 0xffff; /* read disk label */ for (xy->drive_type = 0; xy->drive_type <= XYC_MAXDT; @@ -659,6 +655,10 @@ xy_init(struct xy_softc *xy) * read bad144 table. this table resides on the first sector of the * last track of the disk (i.e. second cyl of "acyl" area). */ + + xy->bad144 = bad144_init(XYFM_BPS, xy->ncyl, xy->nhead, xy->nsect); + KASSERT(xy->bad144 != NULL); + blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) + /* last cyl */ (xy->nhead - 1) * xy->nsect; /* last head */ @@ -671,25 +671,10 @@ xy_init(struct xy_softc *xy) goto done; } - /* check dkbad for sanity */ - dkb = (struct dkbad *)dvmabuf; - for (lcv = 0; lcv < 126; lcv++) { - if ((dkb->bt_bad[lcv].bt_cyl == 0xffff || - dkb->bt_bad[lcv].bt_cyl == 0) && - dkb->bt_bad[lcv].bt_trksec == 0xffff) - continue; /* blank */ - if (dkb->bt_bad[lcv].bt_cyl >= xy->ncyl) - break; - if ((dkb->bt_bad[lcv].bt_trksec >> 8) >= xy->nhead) - break; - if ((dkb->bt_bad[lcv].bt_trksec & 0xff) >= xy->nsect) - break; - } - if (lcv != 126) { + err = bad144_set(xy->bad144, (struct dkbad *)dvmabuf); + if (err) { printf("%s: warning: invalid bad144 sector!\n", device_xname(xy->sc_dev)); - } else { - memcpy(&xy->dkb, dvmabuf, XYFM_BPS); } done: @@ -829,9 +814,9 @@ xyioctl(dev_t dev, u_long cmd, void *add if ((flag & FWRITE) == 0) return EBADF; s = splbio(); - memcpy(&xy->dkb, addr, sizeof(xy->dkb)); + error = bad144_set(xy->bad144, (struct dkbad *)addr); splx(s); - return 0; + return error; case DIOCSDINFO: /* set disk label */ if ((flag & FWRITE) == 0) @@ -1888,10 +1873,10 @@ xyc_error(struct xyc_softc *xycsc, struc (iorq->mode & XY_MODE_B144) == 0) { advance = iorq->sectcnt - iopb->scnt; XYC_ADVANCE(iorq, advance); - if ((i = isbad(&iorq->xy->dkb, - iorq->blockno / iorq->xy->sectpercyl, - (iorq->blockno / iorq->xy->nsect) % iorq->xy->nhead, - iorq->blockno % iorq->xy->nsect)) != -1) { + if ((i = bad144_isbad_chs(iorq->xy->bad144, + iorq->blockno / iorq->xy->sectpercyl, + (iorq->blockno / iorq->xy->nsect) % iorq->xy->nhead, + iorq->blockno % iorq->xy->nsect)) != -1) { iorq->mode |= XY_MODE_B144; /* enter bad144 mode & * redirect */ iopb->errno = iopb->done = iopb->errs = 0; Index: arch/sun3/dev/xyvar.h =================================================================== RCS file: /cvsroot/src/sys/arch/sun3/dev/xyvar.h,v retrieving revision 1.11 diff -u -p -r1.11 xyvar.h --- arch/sun3/dev/xyvar.h 1 Feb 2011 20:19:32 -0000 1.11 +++ arch/sun3/dev/xyvar.h 30 May 2026 13:16:29 -0000 @@ -111,7 +111,7 @@ struct xy_softc { u_char hw_spt; /* as above, but includes spare sectors */ struct xy_iorq *xyrq; /* this disk's ioreq structure */ struct bufq_state *xyq; /* queue'd I/O requests */ - struct dkbad dkb; /* bad144 sectors */ + struct bad144_context *bad144; /* bad144 sectors */ }; /* Index: conf/files =================================================================== RCS file: /cvsroot/src/sys/conf/files,v retrieving revision 1.1318 diff -u -p -r1.1318 files --- conf/files 29 May 2026 08:31:34 -0000 1.1318 +++ conf/files 30 May 2026 13:16:29 -0000 @@ -533,6 +533,10 @@ include "altq/files.altq" device ld: disk file dev/ld.c ld needs-flag +# Disk-related attributes +define bad144 +file dev/bad144.c bad144 + # # MII/PHY support for network devices # Index: dev/bad144.c =================================================================== RCS file: dev/bad144.c diff -N dev/bad144.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/bad144.c 30 May 2026 13:16:29 -0000 @@ -0,0 +1,384 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2026 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dkbad.c 8.2 (Berkeley) 1/12/94 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include +#include + +/* + * General description of DEC standard 144, from bad144(8): + * + * The format of the information is specified by DEC standard 144, as + * follows. The bad sector information is located in the first 5 even + * numbered sectors of the last track of the disk pack. There are five + * identical copies of the information, described by the dkbad structure. + * + * Replacement sectors are allocated starting with the first sector before + * the bad sector information and working backwards towards the beginning of + * the disk. A maximum of 126 bad sectors are supported. The position of + * the bad sector in the bad sector table determines the replacement sector + * to which it corresponds. The bad sectors must be listed in ascending + * order. + * + * (Additional commentary: this is not always true; some disk drivers may + * use alternate cylinders for bad sector replacements. This is why we + * do not perform the actual remapping here.) + * + * The bad sector information and replacement sectors are conventionally + * only accessible through the ``c'' file system partition of the disk. If + * that partition is used for a file system, the user is responsible for + * making sure that it does not overlap the bad sector information or any + * replacement sectors. Thus, one track plus 126 sectors must be reserved + * to allow use of all of the possible bad sector replacements. + * + * NOTE ABOUT BYTE ORDER: You would think that because this on-disk format + * originated at DEC that the fields would be nominally stored in little- + * endian byte order, and in historical BSD usage (including 386BSD back + * in the day), that held true. HOWEVER, bad144 is also used by the Xylogics + * disk drivers, on Sun3 and SPARC systems which are big-endian and those + * drivers historically did NOT byte-swap the entries in the table. So, we + * have ended up with a mixed bag, and I have no interest in disturbing that + * particular sleeping dog. + */ + +struct bad144_context { + /* Provided by bad144 client at setup time. */ + uint32_t bc_secsize; /* drive sector size */ + uint32_t bc_ncyl; /* drive data cylinders */ + uint32_t bc_ntrkcyl; /* drive tracks (heads) per cylinder */ + uint32_t bc_nsectrk; /* drive sectors per track */ + + struct dkbad bc_bt; /* the actual bad sector table */ + daddr_t bc_bb[NBT_BAD+1];/* LBA-ized version */ +}; + +/* + * bad144_init -- + * Initialize bad144 sector forwarding context. Returns a context + * to be used for bad144 remapping, or NULL if bad144 can't be + * used on this drive due to geometry parameters being out of range. + */ +struct bad144_context * +bad144_init(uint32_t secsize, uint32_t ncyl, uint32_t ntrkcyl, uint32_t nsectrk) +{ + int i; + + KASSERT(secsize != 0); + KASSERT(ncyl != 0); + KASSERT(ntrkcyl != 0); + KASSERT(nsectrk != 0); + + if (ncyl > BAD144_MAXCYLNO || + ntrkcyl > BAD144_MAXTRKNO || + nsectrk > BAD144_MAXSECNO) { + /* Can't do bad144 on this drive. */ + return NULL; + } + + struct bad144_context *ctx = kmem_zalloc(sizeof(*ctx), KM_SLEEP); + + ctx->bc_secsize = secsize; + ctx->bc_ncyl = ncyl; + ctx->bc_ntrkcyl = ntrkcyl; + ctx->bc_nsectrk = nsectrk; + + for (i = 0; i < NBT_BAD; i++) { + ctx->bc_bt.bt_bad[i].bt_cyl = + ctx->bc_bt.bt_bad[i].bt_trksec = 0xffff; + ctx->bc_bb[i] = (daddr_t)-1; + } + /* There is an extra slot to terminate the list. */ + ctx->bc_bb[NBT_BAD] = (daddr_t)-1; + + return ctx; +} + +/* + * bad144_fini -- + * Dispose of a bad144 sector forwarding context. + */ +void +bad144_fini(struct bad144_context * const ctx) +{ + if (ctx != NULL) { + kmem_free(ctx, sizeof(*ctx)); + } +} + +/* + * This empty slot check comes from Chuck Cranor's Xylogics SMD + * drivers. It differs from the usual -1 check for cylinder, + * but presumably he did it this way because bad144 tables like + * this are found in the wild ?? + */ +#define EMPTY_SLOT(b) \ + ((bt->bt_bad[i].bt_cyl == 0xffff || \ + bt->bt_bad[i].bt_cyl == 0) && \ + bt->bt_bad[i].bt_trksec == 0xffff) + +/* + * bad144_set -- + * Set the bad144 sector fowarding table from the provided + * buffer. + */ +int +bad144_set(struct bad144_context * const ctx, const struct dkbad * const bt) +{ + int i; + daddr_t key, last_key; + + if (ctx == NULL) { + return ENOTSUP; + } + + KASSERT(bt != NULL); + + for (last_key = 0, i = 0; i < NBT_BAD; i++) { + /* + * All bad sector records are packed into the beginning + * of the table. Once we see an empty slot, there should + * be no more records. Verified below. + */ + if (EMPTY_SLOT(&bt->bt_bad[i])) { + break; + } + /* + * Verify the cylinder / head / sector values in the + * table do not exceed the drive's geometry. + */ + if (bt->bt_bad[i].bt_cyl >= ctx->bc_ncyl || + (bt->bt_bad[i].bt_trksec >> 8) >= ctx->bc_ntrkcyl || + (bt->bt_bad[i].bt_trksec & 0xff) >= ctx->bc_nsectrk) { + goto bad_table; + } + /* + * Verify the table lists bad sectors in ascending order + * and that are no duplicates. + */ + key = ((daddr_t)bt->bt_bad[i].bt_cyl << 16) + + bt->bt_bad[i].bt_trksec; + if (key <= last_key) { + goto bad_table; + } + last_key = key; + } + + /* + * Once we see an empty slot, we must only see empty + * slots. + */ + for (; i < NBT_BAD; i++) { + if (!EMPTY_SLOT(&bt->bt_bad[i])) { + goto bad_table; + } + } + + memcpy(&ctx->bc_bt, bt, sizeof(ctx->bc_bt)); + for (i = 0; i < NBT_BAD; i++) { + if (EMPTY_SLOT(&bt->bt_bad[i])) { + ctx->bc_bb[i] = (daddr_t)-1; + continue; + } + ctx->bc_bb[i] = + (bt->bt_bad[i].bt_cyl * (ctx->bc_ntrkcyl * ctx->bc_nsectrk)) + + ((bt->bt_bad[i].bt_trksec >> 8) * ctx->bc_nsectrk) + + (bt->bt_bad[i].bt_trksec & 0xff); + } + + return 0; + + bad_table: + return EINVAL; +} + +#define DKBAD_MAGIC 0x4321 + +/* + * bad144_load -- + * Find a bad sector table and load it into the context. + */ +int +bad144_load(struct bad144_context * const ctx, dev_t dev, + void (*strat)(struct buf *)) +{ + struct buf *bp; + int error, i = 0; + + if (ctx == NULL) { + return ESRCH; + } + + uint32_t nseccyl = ctx->bc_ntrkcyl * ctx->bc_nsectrk; + uint32_t nsecunit = ctx->bc_ncyl * nseccyl; + + bp = geteblk(ctx->bc_secsize); + bp->b_dev = dev; + + do { + bp->b_oflags &= ~BO_DONE; + bp->b_flags |= B_READ; + bp->b_blkno = nsecunit - ctx->bc_nsectrk + i; + if (ctx->bc_secsize > DEV_BSIZE) { + bp->b_blkno *= ctx->bc_secsize / DEV_BSIZE; + } else { + bp->b_blkno /= DEV_BSIZE / ctx->bc_secsize; + } + bp->b_bcount = ctx->bc_secsize; + bp->b_cylinder = ctx->bc_ncyl - 1; + (*strat)(bp); + + if ((error = biowait(bp)) == 0) { + struct dkbad *db = (struct dkbad *)bp->b_data; + if (db->bt_mbz == 0 && + db->bt_flag == DKBAD_MAGIC) { + error = bad144_set(ctx, db); + break; + } else { + error = ESRCH; + } + } + } while (error != 0 && (i += 2) < 10 && i < ctx->bc_nsectrk); + + brelse(bp, BC_INVAL); + return error; +} + +/* + * bad144_isbad_chs -- + * Search the bad sector table looking for the specified sector. + * Return the index if found, -1 if not found. + * + * This one does CHS addressing and is essentially the traditional + * isbad() routine. + */ +int +bad144_isbad_chs(const struct bad144_context * const ctx, + uint32_t cyl, uint32_t trk, uint32_t sec) +{ + const struct dkbad * const bt = &ctx->bc_bt; + int i; + daddr_t key, tkey; + + if (ctx == NULL) { + return -1; + } + + key = ((daddr_t)cyl << 16) + (trk << 8) + sec; + for (i = 0; i < NBT_BAD; i++) { + tkey = ((daddr_t)bt->bt_bad[i].bt_cyl << 16) + + bt->bt_bad[i].bt_trksec; + if (key == tkey) { + return i; + } + if (EMPTY_SLOT(i) || key < tkey) { + break; + } + } + return -1; +} + +/* + * bad144_isbad_lba -- + * Search the bad sector table looking for the specified sector. + * Return the index if found, -1 if not found. + * + * This one does LBA addressing, and checks a block range, + * also returning the distance to the bad sector. + */ +int +bad144_isbad_lba(const struct bad144_context * const ctx, daddr_t blk, + int nblks, int *distancep) +{ + daddr_t blkdiff; + int i; + + KASSERT(blk >= 0); + KASSERT(nblks > 0); + KASSERT(distancep != NULL); + + if (ctx == NULL) { + return -1; + } + + for (i = 0; (blkdiff = ctx->bc_bb[i]) != (daddr_t)-1; i++) { + blkdiff -= blk; + if (blkdiff < 0) { + continue; + } + if (blkdiff < nblks) { + /* + * There is a bad block within this transfer. + * If the distance is 0, then it's the first + * block in the transfer (i.e. "blk"). Otherwise, + * the distance indicates how many blocks can + * be transferred before the remap must be done. + */ + KASSERT(blkdiff < INT_MAX); + *distancep = (int)blkdiff; + return i; + } + } + return -1; +} Index: dev/ata/ata_wdc.c =================================================================== RCS file: /cvsroot/src/sys/dev/ata/ata_wdc.c,v retrieving revision 1.120 diff -u -p -r1.120 ata_wdc.c --- dev/ata/ata_wdc.c 5 Oct 2021 08:01:05 -0000 1.120 +++ dev/ata/ata_wdc.c 30 May 2026 13:16:29 -0000 @@ -68,6 +68,7 @@ __KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v #include #include #include +#include #include #include @@ -362,38 +363,33 @@ _wdc_ata_bio_start(struct ata_channel *c } #endif /* - * * When starting a multi-sector transfer, or doing single-sector * transfers... */ if (xfer->c_skip == 0 || (ata_bio->flags & ATA_SINGLE) != 0) { + int i, distance; + if (ata_bio->flags & ATA_SINGLE) nblks = 1; else nblks = xfer->c_bcount / drvp->lp->d_secsize; /* Check for bad sectors and adjust transfer, if necessary. */ - if ((drvp->lp->d_flags & D_BADSECT) != 0) { - long blkdiff; - int i; - for (i = 0; (blkdiff = drvp->badsect[i]) != -1; - i++) { - blkdiff -= ata_bio->blkno; - if (blkdiff < 0) - continue; - if (blkdiff == 0) { - /* Replace current block of transfer. */ - ata_bio->blkno = - drvp->lp->d_secperunit - - drvp->lp->d_nsectors - i - 1; - } - if (blkdiff < nblks) { - /* Bad block inside transfer. */ - ata_bio->flags |= ATA_SINGLE; - nblks = 1; - } - break; + if (drvp->bad144 != NULL && + (i = bad144_isbad_lba(drvp->bad144, + ata_bio->blkno, nblks, + &distance)) != -1) { + /* + * The bad block appears somewhere in this + * transfer, so degrade to single-sector mode. + */ + ata_bio->flags |= ATA_SINGLE; + nblks = 1; + if (distance == 0) { + /* Replace current block of transfer. */ + ata_bio->blkno = + drvp->lp->d_secperunit - + drvp->lp->d_nsectors - i - 1; } - /* Transfer is okay now. */ } if (ata_bio->flags & ATA_LBA48) { sect = 0; Index: dev/ata/atavar.h =================================================================== RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v retrieving revision 1.109 diff -u -p -r1.109 atavar.h --- dev/ata/atavar.h 5 Oct 2021 08:01:05 -0000 1.109 +++ dev/ata/atavar.h 30 May 2026 13:16:29 -0000 @@ -338,7 +338,7 @@ struct ata_drive_datas { /* Context used for I/O */ struct disklabel *lp; /* pointer to drive's label info */ uint8_t multi; /* # of blocks to transfer in multi-mode */ - daddr_t badsect[127]; /* 126 plus trailing -1 marker */ + struct bad144_context *bad144; /* bad144 data */ }; /* User config flags that force (or disable) the use of a mode */ Index: dev/ata/files.ata =================================================================== RCS file: /cvsroot/src/sys/dev/ata/files.ata,v retrieving revision 1.33 diff -u -p -r1.33 files.ata --- dev/ata/files.ata 17 Feb 2025 19:01:04 -0000 1.33 +++ dev/ata/files.ata 30 May 2026 13:16:29 -0000 @@ -6,7 +6,7 @@ # appropriate devices. # ATA disks -device wd: disk +device wd: disk, bad144 attach wd at ata_hl file dev/ata/wd.c wd needs-flag file dev/ata/ata_wdc.c wd & atabus & wdc_common Index: dev/ata/wd.c =================================================================== RCS file: /cvsroot/src/sys/dev/ata/wd.c,v retrieving revision 1.474 diff -u -p -r1.474 wd.c --- dev/ata/wd.c 13 Apr 2025 14:00:59 -0000 1.474 +++ dev/ata/wd.c 30 May 2026 13:16:29 -0000 @@ -72,6 +72,7 @@ __KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.474 #include #include #include +#include #include #include #include @@ -230,10 +231,6 @@ static const struct dkdriver wddkdriver .d_discard = wd_discard }; -#ifdef HAS_BAD144_HANDLING -static void bad144intern(struct wd_softc *); -#endif - #define WD_QUIRK_SPLIT_MOD15_WRITE 0x0001 /* must split certain writes */ #define WD_QUIRK_FMT "\20\1SPLIT_MOD15_WRITE" @@ -1138,6 +1135,87 @@ wdwrite(dev_t dev, struct uio *uio, int return (physio(wdstrategy, NULL, dev, B_WRITE, wdminphys, uio)); } +/* + * The bad144 table is consulted in _wdc_ata_bio_start(), which is + * called with the channel lock held. Thus, we must serialize using + * that lock when manipulating anything related to the bad144 table. + */ +#define WD_BAD144_LOCK(wd) mutex_enter(&(wd)->drvp->chnl_softc->ch_lock) +#define WD_BAD144_UNLOCK(wd) mutex_exit(&(wd)->drvp->chnl_softc->ch_lock) + +static void +wd_load_bad144(struct wd_softc *wd, dev_t dev) +{ + struct dk_softc * const dksc = &wd->sc_dksc; + const struct disklabel * const lp = dksc->sc_dkdev.dk_label; + struct bad144_context *bad144 = NULL; + int error; + + /* + * We are called from wdopen() if the disklabel indicates there + * is a bad144 table present on the disk. We only want to attempt + * to read the bad144 table once, on the very first open, because + * we are going to print diagnostic information in case there is + * some inconsistency that prevents bad144 from working. + */ + + WD_BAD144_LOCK(wd); + + if (wd->sc_tried_bad144 || wd->drvp->bad144 != NULL) { + /* + * This is not the first pass through, or someone raced + * with us and beat us to it. + */ + goto out_unlock; + } + + /* Don't hold this lock while we allocate memory and perform I/O. */ + WD_BAD144_UNLOCK(wd); + + bad144 = bad144_init(lp->d_secsize, lp->d_ncylinders, lp->d_ntracks, + lp->d_nsectors); + if (bad144 == NULL) { + printf("%s: disklabel indicates BAD144 but " + "BAD144 not supported on this drive", + device_xname(dksc->sc_dev)); + goto out; + } + + error = bad144_load(bad144, WDLABELDEV(dev), wdstrategy); + if (error == ESRCH) { + /* No bad144 table on this drive?? */ + printf("%s: disklabel indicates BAD144 but " + "BAD144 table not found", + device_xname(dksc->sc_dev)); + } else if (error == EINVAL) { + printf("%s: invalid BAD144 table", + device_xname(dksc->sc_dev)); + } else if (error) { + printf("%s: error %d reading BAD144 table", + device_xname(dksc->sc_dev), error); + } + + out: + WD_BAD144_LOCK(wd); + if (bad144 != NULL && error == 0) { + /* + * Don't replace the in-use table if we lost the + * race; the one we just read in is probably stale. + */ + if (wd->drvp->bad144 == NULL) { + wd->drvp->bad144 = bad144; + bad144 = NULL; + } + } + wd->sc_tried_bad144 = true; + + out_unlock: + WD_BAD144_UNLOCK(wd); + if (bad144 != NULL) { + bad144_fini(bad144); + } +} + static int wdopen(dev_t dev, int flag, int fmt, struct lwp *l) { @@ -1171,6 +1249,15 @@ wdopen(dev_t dev, int flag, int fmt, str error = dk_open(dksc, dev, flag, fmt, l); + /* + * If the disklabel indicates we have a bad144 table, + * read that in if we haven't already. + */ + if (error == 0 && + (dksc->sc_dkdev.dk_label->d_flags & D_BADSECT) != 0) { + wd_load_bad144(wd, dev); + } + return error; } @@ -1283,6 +1370,38 @@ wdperror(const struct wd_softc *wd, stru printf(")\n"); } +static int +wd_diocsbad(struct wd_softc *wd, const struct dkbad *dkb) +{ + struct dk_softc *dksc = &wd->sc_dksc; + const struct disklabel * const lp = dksc->sc_dkdev.dk_label; + struct bad144_context *bad144, *obad144; + int error; + + bad144 = bad144_init(lp->d_secsize, lp->d_ncylinders, lp->d_ntracks, + lp->d_nsectors); + if (bad144 == NULL) { + return ENOTSUP; + } + + error = bad144_set(bad144, dkb); + if (error) { + bad144_fini(bad144); + return error; + } + + WD_BAD144_LOCK(wd); + obad144 = wd->drvp->bad144; + wd->drvp->bad144 = bad144; + WD_BAD144_UNLOCK(wd); + + if (obad144 != NULL) { + bad144_fini(obad144); + } + + return 0; +} + int wdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { @@ -1296,15 +1415,11 @@ wdioctl(dev_t dev, u_long cmd, void *add return EIO; switch (cmd) { -#ifdef HAS_BAD144_HANDLING case DIOCSBAD: if ((flag & FWRITE) == 0) return EBADF; - dksc->sc_dkdev.dk_cpulabel->bad = *(struct dkbad *)addr; - dksc->sc_dkdev.dk_label->d_flags |= D_BADSECT; - bad144intern(wd); - return 0; -#endif + return wd_diocsbad(wd, (struct dkbad *)addr); + #ifdef WD_SOFTBADSECT case DIOCBSLIST: { uint32_t count, missing, skip; @@ -1687,33 +1802,6 @@ wd_dumpblocks(device_t dev, void *va, da return 0; } -#ifdef HAS_BAD144_HANDLING -/* - * Internalize the bad sector table. - */ -void -bad144intern(struct wd_softc *wd) -{ - struct dk_softc *dksc = &wd->sc_dksc; - struct dkbad *bt = &dksc->sc_dkdev.dk_cpulabel->bad; - struct disklabel *lp = dksc->sc_dkdev.dk_label; - int i = 0; - - ATADEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS); - - for (; i < NBT_BAD; i++) { - if (bt->bt_bad[i].bt_cyl == 0xffff) - break; - wd->drvp->badsect[i] = - bt->bt_bad[i].bt_cyl * lp->d_secpercyl + - (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + - (bt->bt_bad[i].bt_trksec & 0xff); - } - for (; i < NBT_BAD+1; i++) - wd->drvp->badsect[i] = -1; -} -#endif - static void wd_set_geometry(struct wd_softc *wd) { Index: dev/ata/wdvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/ata/wdvar.h,v retrieving revision 1.52 diff -u -p -r1.52 wdvar.h --- dev/ata/wdvar.h 13 Apr 2025 14:00:59 -0000 1.52 +++ dev/ata/wdvar.h 30 May 2026 13:16:29 -0000 @@ -72,6 +72,12 @@ struct wd_softc { uint32_t sc_capacity28; /* capacity accessible with LBA28 commands */ uint32_t sc_blksize; /* logical block size, in bytes */ + /* + * We only want to try loading the bad144 table from disk once, + * the very first time the disk is opened. + */ + bool sc_tried_bad144; + #ifdef WD_SOFTBADSECT SLIST_HEAD(, disk_badsectors) sc_bslist; u_int sc_bscount; Index: dev/vme/files.vme =================================================================== RCS file: /cvsroot/src/sys/dev/vme/files.vme,v retrieving revision 1.10 diff -u -p -r1.10 files.vme --- dev/vme/files.vme 9 Jan 2007 23:51:30 -0000 1.10 +++ dev/vme/files.vme 30 May 2026 13:16:29 -0000 @@ -23,14 +23,14 @@ file dev/vme/if_ie_vme.c ie_vme # Xylogics 753/7053 SMD controller device xdc {drive = -1} attach xdc at vme -device xd: disk +device xd: disk, bad144 attach xd at xdc file dev/vme/xd.c xd | xdc needs-flag # Xylogics 450/451 SMD controller device xyc {drive = -1} attach xyc at vme -device xy: disk +device xy: disk, bad144 attach xy at xyc file dev/vme/xy.c xy | xyc needs-flag Index: dev/vme/xd.c =================================================================== RCS file: /cvsroot/src/sys/dev/vme/xd.c,v retrieving revision 1.100 diff -u -p -r1.100 xd.c --- dev/vme/xd.c 6 Sep 2025 21:20:20 -0000 1.100 +++ dev/vme/xd.c 30 May 2026 13:16:29 -0000 @@ -711,9 +711,8 @@ xdattach(device_t parent, device_t self, struct xd_softc *xd = device_private(self); struct xdc_softc *xdc = device_private(parent); struct xdc_attach_args *xa = aux; - int rqno, spt = 0, mb, blk, lcv, fmode, s = 0, newstate; + int rqno, spt = 0, mb, blk, fmode, s = 0, newstate; struct xd_iopb_drive *driopb; - struct dkbad *dkb; int rseg, error; bus_dma_segment_t seg; bus_addr_t busaddr; @@ -815,8 +814,6 @@ xdattach(device_t parent, device_t self, xd->nhead = 1; xd->nsect = 1; xd->sectpercyl = 1; - for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */ - xd->dkb.bt_bad[lcv].bt_cyl = xd->dkb.bt_bad[lcv].bt_trksec = 0xffff; rqno = xdc_cmd(xdc, XDCMD_WRP, XDFUN_DRV, xd->xd_drive, 0, 0, 0, fmode); XDC_DONE(xdc, rqno, error); if (error) { @@ -867,6 +864,9 @@ xdattach(device_t parent, device_t self, * last track of the disk (i.e. second cyl of "acyl" area). */ + xd->bad144 = bad144_init(XDFM_BPS, xd->ncyl, xd->nhead, xd->nsect); + KASSERT(xd->bad144 != NULL); + blk = (xd->ncyl + xd->acyl - 1) * (xd->nhead * xd->nsect) + /* last cyl */ (xd->nhead - 1) * xd->nsect; /* last head */ rqno = xdc_cmd(xdc, XDCMD_RD, 0, xd->xd_drive, blk, 1, dmaddr, fmode); @@ -877,24 +877,9 @@ xdattach(device_t parent, device_t self, goto done; } - /* check dkbad for sanity */ - dkb = (struct dkbad *) buf; - for (lcv = 0; lcv < 126; lcv++) { - if ((dkb->bt_bad[lcv].bt_cyl == 0xffff || - dkb->bt_bad[lcv].bt_cyl == 0) && - dkb->bt_bad[lcv].bt_trksec == 0xffff) - continue; /* blank */ - if (dkb->bt_bad[lcv].bt_cyl >= xd->ncyl) - break; - if ((dkb->bt_bad[lcv].bt_trksec >> 8) >= xd->nhead) - break; - if ((dkb->bt_bad[lcv].bt_trksec & 0xff) >= xd->nsect) - break; - } - if (lcv != 126) { + error = bad144_set(xd->bad144, (struct dkbad *)buf); + if (error) { aprint_error_dev(xd->sc_dev, "warning: invalid bad144 sector!\n"); - } else { - memcpy(&xd->dkb, buf, XDFM_BPS); } done: @@ -1044,9 +1029,9 @@ xdioctl(dev_t dev, u_long command, void if ((flag & FWRITE) == 0) return EBADF; s = splbio(); - memcpy(&xd->dkb, addr, sizeof(xd->dkb)); + error = bad144_set(xd->bad144, (struct dkbad *)addr); splx(s); - return 0; + return error; case DIOCSDINFO: /* set disk label */ #ifdef __HAVE_OLD_DISKLABEL @@ -2177,8 +2162,8 @@ xdc_error(struct xdc_softc *xdcsc, struc (iorq->mode & XD_MODE_B144) == 0) { advance = iorq->sectcnt - iopb->sectcnt; XDC_ADVANCE(iorq, advance); -#ifdef __sparc__ - if ((i = isbad(&iorq->xd->dkb, iorq->blockno / iorq->xd->sectpercyl, + if ((i = bad144_isbad_chs(iorq->xd->bad144, + iorq->blockno / iorq->xd->sectpercyl, (iorq->blockno / iorq->xd->nsect) % iorq->xd->nhead, iorq->blockno % iorq->xd->nsect)) != -1) { iorq->mode |= XD_MODE_B144; /* enter bad144 mode & @@ -2195,7 +2180,6 @@ xdc_error(struct xdc_softc *xdcsc, struc xdc_start(xdcsc, 1); /* resubmit */ return (XD_ERR_AOK); /* recovered! */ } -#endif } /* Index: dev/vme/xdvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/vme/xdvar.h,v retrieving revision 1.13 diff -u -p -r1.13 xdvar.h --- dev/vme/xdvar.h 27 Oct 2012 17:18:38 -0000 1.13 +++ dev/vme/xdvar.h 30 May 2026 13:16:29 -0000 @@ -109,7 +109,7 @@ struct xd_softc { u_char nhead; /* number of heads */ u_char nsect; /* number of sectors per track */ u_char hw_spt; /* as above, but includes spare sectors */ - struct dkbad dkb; /* bad144 sectors */ + struct bad144_context *bad144; /* bad144 sectors */ }; /* Index: dev/vme/xy.c =================================================================== RCS file: /cvsroot/src/sys/dev/vme/xy.c,v retrieving revision 1.102 diff -u -p -r1.102 xy.c --- dev/vme/xy.c 7 Aug 2021 16:19:17 -0000 1.102 +++ dev/vme/xy.c 30 May 2026 13:16:29 -0000 @@ -611,7 +611,6 @@ xyattach(device_t parent, device_t self, struct xyc_softc *xyc = device_private(parent); struct xyc_attach_args *xa = aux; int spt, mb, blk, lcv, fmode, s = 0, newstate; - struct dkbad *dkb; int rseg, error; bus_dma_segment_t seg; bus_addr_t busaddr; @@ -696,9 +695,6 @@ xyattach(device_t parent, device_t self, xy->nhead = 1; xy->nsect = 1; xy->sectpercyl = 1; - for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */ - xy->dkb.bt_bad[lcv].bt_cyl = - xy->dkb.bt_bad[lcv].bt_trksec = 0xffff; /* read disk label */ for (xy->drive_type = 0 ; xy->drive_type <= XYC_MAXDT ; @@ -779,6 +775,9 @@ xyattach(device_t parent, device_t self, * last track of the disk (i.e. second cyl of "acyl" area). */ + xy->bad144 = bad144_init(XYFM_BPS, xy->ncyl, xy->nhead, xy->nsect); + KASSERT(xy->bad144 != NULL); + blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) + /* last cyl */ (xy->nhead - 1) * xy->nsect; /* last head */ @@ -791,24 +790,9 @@ xyattach(device_t parent, device_t self, goto done; } - /* check dkbad for sanity */ - dkb = (struct dkbad *) buf; - for (lcv = 0; lcv < 126; lcv++) { - if ((dkb->bt_bad[lcv].bt_cyl == 0xffff || - dkb->bt_bad[lcv].bt_cyl == 0) && - dkb->bt_bad[lcv].bt_trksec == 0xffff) - continue; /* blank */ - if (dkb->bt_bad[lcv].bt_cyl >= xy->ncyl) - break; - if ((dkb->bt_bad[lcv].bt_trksec >> 8) >= xy->nhead) - break; - if ((dkb->bt_bad[lcv].bt_trksec & 0xff) >= xy->nsect) - break; - } - if (lcv != 126) { + error = bad144_set(xy->bad144, (struct dkbad *)buf); + if (error) { aprint_error_dev(xy->sc_dev, "warning: invalid bad144 sector!\n"); - } else { - memcpy(&xy->dkb, buf, XYFM_BPS); } done: @@ -963,7 +947,7 @@ xyioctl(dev_t dev, u_long command, void if ((flag & FWRITE) == 0) return EBADF; s = splbio(); - memcpy(&xy->dkb, addr, sizeof(xy->dkb)); + error = bad144_set(xy->bad144, (struct dkbad *)addr); splx(s); return 0; @@ -2049,8 +2033,8 @@ xyc_error(struct xyc_softc *xycsc, struc (iorq->mode & XY_MODE_B144) == 0) { advance = iorq->sectcnt - iopb->scnt; XYC_ADVANCE(iorq, advance); -#ifdef __sparc__ - if ((i = isbad(&iorq->xy->dkb, iorq->blockno / iorq->xy->sectpercyl, + if ((i = bad144_isbad_chs(iorq->xy->bad144, + iorq->blockno / iorq->xy->sectpercyl, (iorq->blockno / iorq->xy->nsect) % iorq->xy->nhead, iorq->blockno % iorq->xy->nsect)) != -1) { iorq->mode |= XY_MODE_B144; /* enter bad144 mode & @@ -2066,7 +2050,6 @@ xyc_error(struct xyc_softc *xycsc, struc /* will resubmit when we come out of remove_iorq */ return (XY_ERR_AOK); /* recovered! */ } -#endif } /* Index: dev/vme/xyvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/vme/xyvar.h,v retrieving revision 1.14 diff -u -p -r1.14 xyvar.h --- dev/vme/xyvar.h 27 Oct 2012 17:18:39 -0000 1.14 +++ dev/vme/xyvar.h 30 May 2026 13:16:29 -0000 @@ -108,7 +108,7 @@ struct xy_softc { u_char hw_spt; /* as above, but includes spare sectors */ struct xy_iorq *xyrq; /* this disk's ioreq structure */ struct bufq_state *xyq; /* queued I/O requests */ - struct dkbad dkb; /* bad144 sectors */ + struct bad144_context *bad144; /* bad144 sectors */ }; /*