1 1.31 christos /* $NetBSD: bad144.c,v 1.31 2015/01/02 19:46:02 christos Exp $ */ 2 1.10 mikel 3 1.1 cgd /* 4 1.6 mycroft * Copyright (c) 1980, 1986, 1988, 1993 5 1.6 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.21 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.13 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.26 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1988, 1993\ 35 1.26 lukem The Regents of the University of California. All rights reserved."); 36 1.11 mikel #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.11 mikel #if 0 40 1.11 mikel static char sccsid[] = "@(#)bad144.c 8.2 (Berkeley) 4/27/95"; 41 1.11 mikel #else 42 1.31 christos __RCSID("$NetBSD: bad144.c,v 1.31 2015/01/02 19:46:02 christos Exp $"); 43 1.11 mikel #endif 44 1.11 mikel #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd /* 47 1.1 cgd * bad144 48 1.1 cgd * 49 1.1 cgd * This program prints and/or initializes a bad block record for a pack, 50 1.1 cgd * in the format used by the DEC standard 144. 51 1.1 cgd * It can also add bad sector(s) to the record, moving the sector 52 1.1 cgd * replacements as necessary. 53 1.1 cgd * 54 1.1 cgd * It is preferable to write the bad information with a standard formatter, 55 1.1 cgd * but this program will do. 56 1.1 cgd * 57 1.1 cgd * RP06 sectors are marked as bad by inverting the format bit in the 58 1.1 cgd * header; on other drives the valid-sector bit is cleared. 59 1.1 cgd */ 60 1.1 cgd #include <sys/param.h> 61 1.1 cgd #include <sys/dkbad.h> 62 1.1 cgd #include <sys/ioctl.h> 63 1.1 cgd #include <sys/file.h> 64 1.1 cgd #include <sys/disklabel.h> 65 1.14 fvdl #include <ufs/ufs/dinode.h> 66 1.6 mycroft #include <ufs/ffs/fs.h> 67 1.1 cgd 68 1.13 lukem #include <err.h> 69 1.13 lukem #include <paths.h> 70 1.1 cgd #include <stdio.h> 71 1.11 mikel #include <stdlib.h> 72 1.9 cgd #include <string.h> 73 1.11 mikel #include <unistd.h> 74 1.13 lukem #include <util.h> 75 1.1 cgd 76 1.1 cgd #define RETRIES 10 /* number of retries on reading old sectors */ 77 1.1 cgd 78 1.19 wiz #ifdef __vax__ 79 1.29 joerg static int fflag; 80 1.19 wiz #endif 81 1.29 joerg static int add, copy, verbose, nflag; 82 1.29 joerg static int dups; 83 1.29 joerg static int badfile = -1; /* copy of badsector table to use, -1 if any */ 84 1.1 cgd #define MAXSECSIZE 1024 85 1.29 joerg static struct dkbad curbad, oldbad; 86 1.1 cgd #define DKBAD_MAGIC 0x4321 87 1.1 cgd 88 1.29 joerg static daddr_t size; 89 1.29 joerg static struct disklabel *dp; 90 1.29 joerg static struct disklabel label; 91 1.29 joerg static char diskname[MAXPATHLEN]; 92 1.29 joerg 93 1.29 joerg static daddr_t badsn(const struct bt_bad *); 94 1.29 joerg static int blkcopy(int, daddr_t, daddr_t); 95 1.29 joerg static void blkzero(int, daddr_t); 96 1.29 joerg static int checkold(void); 97 1.29 joerg static int compare(const void *, const void *); 98 1.29 joerg static daddr_t getold(int, struct dkbad *); 99 1.29 joerg static void shift(int, int, int); 100 1.29 joerg __dead static void usage(void); 101 1.19 wiz 102 1.19 wiz #ifdef __vax__ 103 1.19 wiz #define OPTSTRING "01234acfvn" 104 1.19 wiz #else 105 1.19 wiz #define OPTSTRING "01234acvn" 106 1.19 wiz #endif 107 1.11 mikel 108 1.11 mikel int 109 1.16 wiz main(int argc, char *argv[]) 110 1.1 cgd { 111 1.11 mikel struct bt_bad *bt; 112 1.30 christos daddr_t sn; 113 1.30 christos #ifdef __vax__ 114 1.30 christos daddr_t bn[NBT_BAD]; 115 1.30 christos #endif 116 1.19 wiz int i, f, nbad, new, bad, errs, ch; 117 1.1 cgd 118 1.19 wiz while ((ch = getopt(argc, argv, OPTSTRING)) != -1) { 119 1.19 wiz switch (ch) { 120 1.19 wiz case '0': 121 1.19 wiz case '1': 122 1.19 wiz case '2': 123 1.19 wiz case '3': 124 1.19 wiz case '4': 125 1.19 wiz badfile = ch - '0'; 126 1.19 wiz break; 127 1.19 wiz case 'a': 128 1.19 wiz add = 1; 129 1.19 wiz break; 130 1.19 wiz case 'c': 131 1.19 wiz copy = 1; 132 1.19 wiz break; 133 1.19 wiz #ifdef __vax__ 134 1.19 wiz case 'f': 135 1.19 wiz fflag = 1; 136 1.19 wiz break; 137 1.1 cgd #endif 138 1.19 wiz case 'n': 139 1.19 wiz nflag = 1; 140 1.19 wiz /* FALLTHROUGH */ 141 1.19 wiz case 'v': 142 1.19 wiz verbose = 1; 143 1.19 wiz break; 144 1.19 wiz case '?': 145 1.19 wiz default: 146 1.19 wiz usage(); 147 1.1 cgd } 148 1.1 cgd } 149 1.19 wiz 150 1.19 wiz argc -= optind; 151 1.19 wiz argv += optind; 152 1.19 wiz 153 1.1 cgd if (argc < 1) { 154 1.19 wiz usage(); 155 1.1 cgd } 156 1.13 lukem f = opendisk(argv[0], argc == 1 ? O_RDONLY : O_RDWR, diskname, 157 1.13 lukem sizeof(diskname), 0); 158 1.1 cgd if (f < 0) 159 1.13 lukem err(4, "opendisk `%s'", diskname); 160 1.1 cgd /* obtain label and adjust to fit */ 161 1.19 wiz dp = &label; 162 1.1 cgd if (ioctl(f, DIOCGDINFO, dp) < 0) 163 1.13 lukem err(4, "ioctl DIOCGDINFO `%s'", diskname); 164 1.1 cgd if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC 165 1.13 lukem /* dkcksum(lp) != 0 */ ) 166 1.13 lukem errx(1, "Bad pack magic number (pack is unlabeled)"); 167 1.19 wiz if (dp->d_secsize > MAXSECSIZE || dp->d_secsize == 0) 168 1.13 lukem errx(7, "Disk sector size too large/small (%d)", 169 1.13 lukem dp->d_secsize); 170 1.17 wiz #ifdef __i386__ 171 1.31 christos if (dp->d_type == DKTYPE_SCSI) 172 1.13 lukem errx(1, "SCSI disks don't use bad144!"); 173 1.1 cgd /* are we inside a DOS partition? */ 174 1.1 cgd if (dp->d_partitions[0].p_offset) { 175 1.1 cgd /* yes, rules change. assume bad tables at end of partition C, 176 1.1 cgd which maps all of DOS partition we are within -wfj */ 177 1.1 cgd size = dp->d_partitions[2].p_offset + dp->d_partitions[2].p_size; 178 1.17 wiz } 179 1.1 cgd #endif 180 1.1 cgd size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; 181 1.1 cgd argc--; 182 1.1 cgd argv++; 183 1.1 cgd if (argc == 0) { 184 1.1 cgd sn = getold(f, &oldbad); 185 1.20 fvdl printf("bad block information at sector %lld in %s:\n", 186 1.25 apb (long long)sn, diskname); 187 1.1 cgd printf("cartridge serial number: %d(10)\n", oldbad.bt_csn); 188 1.1 cgd switch (oldbad.bt_flag) { 189 1.1 cgd 190 1.1 cgd case (u_short)-1: 191 1.1 cgd printf("alignment cartridge\n"); 192 1.1 cgd break; 193 1.1 cgd 194 1.1 cgd case DKBAD_MAGIC: 195 1.1 cgd break; 196 1.1 cgd 197 1.1 cgd default: 198 1.1 cgd printf("bt_flag=%x(16)?\n", oldbad.bt_flag); 199 1.1 cgd break; 200 1.1 cgd } 201 1.1 cgd bt = oldbad.bt_bad; 202 1.18 wiz for (i = 0; i < NBT_BAD; i++) { 203 1.1 cgd bad = (bt->bt_cyl<<16) + bt->bt_trksec; 204 1.1 cgd if (bad < 0) 205 1.1 cgd break; 206 1.20 fvdl printf("sn=%lld, cn=%d, tn=%d, sn=%d\n", 207 1.20 fvdl (long long)badsn(bt), 208 1.1 cgd bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); 209 1.1 cgd bt++; 210 1.1 cgd } 211 1.11 mikel (void) checkold(); 212 1.1 cgd exit(0); 213 1.1 cgd } 214 1.1 cgd if (add) { 215 1.1 cgd /* 216 1.1 cgd * Read in the old badsector table. 217 1.1 cgd * Verify that it makes sense, and the bad sectors 218 1.1 cgd * are in order. Copy the old table to the new one. 219 1.1 cgd */ 220 1.1 cgd (void) getold(f, &oldbad); 221 1.11 mikel i = checkold(); 222 1.1 cgd if (verbose) 223 1.1 cgd printf("Had %d bad sectors, adding %d\n", i, argc); 224 1.18 wiz if (i + argc > NBT_BAD) { 225 1.1 cgd printf("bad144: not enough room for %d more sectors\n", 226 1.1 cgd argc); 227 1.18 wiz printf("limited to %d by information format\n", 228 1.18 wiz NBT_BAD); 229 1.1 cgd exit(1); 230 1.1 cgd } 231 1.1 cgd curbad = oldbad; 232 1.1 cgd } else { 233 1.1 cgd curbad.bt_csn = atoi(*argv++); 234 1.1 cgd argc--; 235 1.1 cgd curbad.bt_mbz = 0; 236 1.1 cgd curbad.bt_flag = DKBAD_MAGIC; 237 1.18 wiz if (argc > NBT_BAD) { 238 1.1 cgd printf("bad144: too many bad sectors specified\n"); 239 1.18 wiz printf("limited to %d by information format\n", 240 1.18 wiz NBT_BAD); 241 1.1 cgd exit(1); 242 1.1 cgd } 243 1.1 cgd i = 0; 244 1.1 cgd } 245 1.1 cgd errs = 0; 246 1.1 cgd new = argc; 247 1.1 cgd while (argc > 0) { 248 1.17 wiz sn = atoi(*argv++); 249 1.1 cgd argc--; 250 1.1 cgd if (sn < 0 || sn >= size) { 251 1.20 fvdl printf("%lld: out of range [0,%lld) for disk %s\n", 252 1.20 fvdl (long long)sn, (long long)size, dp->d_typename); 253 1.1 cgd errs++; 254 1.1 cgd continue; 255 1.1 cgd } 256 1.30 christos #ifdef __vax__ 257 1.1 cgd bn[i] = sn; 258 1.30 christos #endif 259 1.1 cgd curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks); 260 1.1 cgd sn %= (dp->d_nsectors*dp->d_ntracks); 261 1.1 cgd curbad.bt_bad[i].bt_trksec = 262 1.1 cgd ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors); 263 1.1 cgd i++; 264 1.1 cgd } 265 1.1 cgd if (errs) 266 1.1 cgd exit(1); 267 1.1 cgd nbad = i; 268 1.18 wiz while (i < NBT_BAD) { 269 1.1 cgd curbad.bt_bad[i].bt_trksec = -1; 270 1.1 cgd curbad.bt_bad[i].bt_cyl = -1; 271 1.1 cgd i++; 272 1.1 cgd } 273 1.1 cgd if (add) { 274 1.1 cgd /* 275 1.1 cgd * Sort the new bad sectors into the list. 276 1.1 cgd * Then shuffle the replacement sectors so that 277 1.1 cgd * the previous bad sectors get the same replacement data. 278 1.1 cgd */ 279 1.1 cgd qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad), 280 1.1 cgd compare); 281 1.13 lukem if (dups) 282 1.19 wiz errx(3, "bad sectors have been duplicated; " 283 1.19 wiz "can't add existing sectors"); 284 1.1 cgd shift(f, nbad, nbad-new); 285 1.1 cgd } 286 1.1 cgd if (badfile == -1) 287 1.1 cgd i = 0; 288 1.1 cgd else 289 1.1 cgd i = badfile * 2; 290 1.27 lukem for (; i < 10 && i < (int)dp->d_nsectors; i += 2) { 291 1.11 mikel if (lseek(f, 292 1.12 kleink (off_t)(dp->d_secsize * (size - dp->d_nsectors + i)), 293 1.12 kleink SEEK_SET) < 0) 294 1.13 lukem err(4, "lseek"); 295 1.1 cgd if (verbose) 296 1.20 fvdl printf("write badsect file at %lld\n", 297 1.20 fvdl (long long)size - dp->d_nsectors + i); 298 1.1 cgd if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) != 299 1.13 lukem sizeof(curbad)) 300 1.13 lukem err(4, "write bad sector file %d", i/2); 301 1.1 cgd if (badfile != -1) 302 1.1 cgd break; 303 1.1 cgd } 304 1.15 matt #ifdef __vax__ 305 1.1 cgd if (nflag == 0 && fflag) 306 1.1 cgd for (i = nbad - new; i < nbad; i++) 307 1.1 cgd format(f, bn[i]); 308 1.1 cgd #endif 309 1.1 cgd #ifdef DIOCSBAD 310 1.1 cgd if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0) 311 1.19 wiz warnx("Can't sync bad-sector file; reboot for changes " 312 1.19 wiz "to take effect"); 313 1.1 cgd #endif 314 1.1 cgd if ((dp->d_flags & D_BADSECT) == 0 && nflag == 0) { 315 1.1 cgd dp->d_flags |= D_BADSECT; 316 1.1 cgd if (ioctl(f, DIOCWDINFO, dp) < 0) { 317 1.13 lukem warn("label"); 318 1.13 lukem errx(1, 319 1.13 lukem "Can't write label to enable bad sector handling"); 320 1.1 cgd } 321 1.1 cgd } 322 1.19 wiz return (0); 323 1.1 cgd } 324 1.1 cgd 325 1.29 joerg static daddr_t 326 1.16 wiz getold(int f, struct dkbad *bad) 327 1.1 cgd { 328 1.11 mikel int i; 329 1.1 cgd daddr_t sn; 330 1.1 cgd 331 1.1 cgd if (badfile == -1) 332 1.1 cgd i = 0; 333 1.1 cgd else 334 1.1 cgd i = badfile * 2; 335 1.27 lukem for (; i < 10 && i < (int)dp->d_nsectors; i += 2) { 336 1.1 cgd sn = size - dp->d_nsectors + i; 337 1.12 kleink if (lseek(f, (off_t)(sn * dp->d_secsize), SEEK_SET) < 0) 338 1.13 lukem err(4, "lseek"); 339 1.27 lukem if ((size_t)read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) { 340 1.1 cgd if (i > 0) 341 1.1 cgd printf("Using bad-sector file %d\n", i/2); 342 1.1 cgd return(sn); 343 1.1 cgd } 344 1.20 fvdl warn("read bad sector file at sn %lld", (long long)sn); 345 1.1 cgd if (badfile != -1) 346 1.1 cgd break; 347 1.1 cgd } 348 1.24 elad errx(1, "%s: can't read bad block info", diskname); 349 1.1 cgd /*NOTREACHED*/ 350 1.1 cgd } 351 1.1 cgd 352 1.29 joerg static int 353 1.16 wiz checkold(void) 354 1.1 cgd { 355 1.13 lukem int i; 356 1.13 lukem struct bt_bad *bt; 357 1.1 cgd daddr_t sn, lsn; 358 1.1 cgd int errors = 0, warned = 0; 359 1.1 cgd 360 1.13 lukem lsn = 0; 361 1.1 cgd if (oldbad.bt_flag != DKBAD_MAGIC) { 362 1.24 elad warnx("%s: bad flag in bad-sector table", diskname); 363 1.1 cgd errors++; 364 1.1 cgd } 365 1.1 cgd if (oldbad.bt_mbz != 0) { 366 1.24 elad warnx("%s: bad magic number", diskname); 367 1.1 cgd errors++; 368 1.1 cgd } 369 1.1 cgd bt = oldbad.bt_bad; 370 1.18 wiz for (i = 0; i < NBT_BAD; i++, bt++) { 371 1.1 cgd if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff) 372 1.1 cgd break; 373 1.1 cgd if ((bt->bt_cyl >= dp->d_ncylinders) || 374 1.1 cgd ((bt->bt_trksec >> 8) >= dp->d_ntracks) || 375 1.1 cgd ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) { 376 1.19 wiz warnx("cyl/trk/sect out of range in existing entry: " 377 1.20 fvdl "sn=%lld, cn=%d, tn=%d, sn=%d", 378 1.20 fvdl (long long)badsn(bt), bt->bt_cyl, bt->bt_trksec>>8, 379 1.13 lukem bt->bt_trksec & 0xff); 380 1.1 cgd errors++; 381 1.1 cgd } 382 1.1 cgd sn = (bt->bt_cyl * dp->d_ntracks + 383 1.1 cgd (bt->bt_trksec >> 8)) * 384 1.1 cgd dp->d_nsectors + (bt->bt_trksec & 0xff); 385 1.1 cgd if (i > 0 && sn < lsn && !warned) { 386 1.13 lukem warnx("bad sector file is out of order"); 387 1.1 cgd errors++; 388 1.1 cgd warned++; 389 1.1 cgd } 390 1.1 cgd if (i > 0 && sn == lsn) { 391 1.20 fvdl warnx("bad sector file contains duplicates (sn %lld)", 392 1.20 fvdl (long long)sn); 393 1.1 cgd errors++; 394 1.1 cgd } 395 1.1 cgd lsn = sn; 396 1.1 cgd } 397 1.1 cgd if (errors) 398 1.1 cgd exit(1); 399 1.1 cgd return (i); 400 1.1 cgd } 401 1.1 cgd 402 1.1 cgd /* 403 1.1 cgd * Move the bad sector replacements 404 1.1 cgd * to make room for the new bad sectors. 405 1.1 cgd * new is the new number of bad sectors, old is the previous count. 406 1.1 cgd */ 407 1.29 joerg static void 408 1.16 wiz shift(int f, int new, int old) 409 1.1 cgd { 410 1.1 cgd daddr_t repl; 411 1.1 cgd 412 1.1 cgd /* 413 1.1 cgd * First replacement is last sector of second-to-last track. 414 1.1 cgd */ 415 1.1 cgd repl = size - dp->d_nsectors - 1; 416 1.1 cgd new--; old--; 417 1.1 cgd while (new >= 0 && new != old) { 418 1.1 cgd if (old < 0 || 419 1.1 cgd compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) { 420 1.1 cgd /* 421 1.1 cgd * Insert new replacement here-- copy original 422 1.1 cgd * sector if requested and possible, 423 1.1 cgd * otherwise write a zero block. 424 1.1 cgd */ 425 1.1 cgd if (!copy || 426 1.1 cgd !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new)) 427 1.1 cgd blkzero(f, repl - new); 428 1.1 cgd } else { 429 1.1 cgd if (blkcopy(f, repl - old, repl - new) == 0) 430 1.20 fvdl warnx("Can't copy replacement sector %lld to %lld", 431 1.20 fvdl (long long)repl-old, (long long)repl-new); 432 1.1 cgd old--; 433 1.1 cgd } 434 1.1 cgd new--; 435 1.1 cgd } 436 1.1 cgd } 437 1.1 cgd 438 1.29 joerg static char *buf; 439 1.1 cgd 440 1.1 cgd /* 441 1.1 cgd * Copy disk sector s1 to s2. 442 1.1 cgd */ 443 1.29 joerg static int 444 1.16 wiz blkcopy(int f, daddr_t s1, daddr_t s2) 445 1.1 cgd { 446 1.13 lukem int tries, n; 447 1.1 cgd 448 1.28 plunky if (buf == NULL) { 449 1.1 cgd buf = malloc((unsigned)dp->d_secsize); 450 1.28 plunky if (buf == NULL) 451 1.13 lukem errx(20, "Out of memory"); 452 1.1 cgd } 453 1.1 cgd for (tries = 0; tries < RETRIES; tries++) { 454 1.12 kleink if (lseek(f, (off_t)(dp->d_secsize * s1), SEEK_SET) < 0) 455 1.13 lukem err(4, "lseek"); 456 1.27 lukem if ((size_t)(n = read(f, buf, dp->d_secsize)) == dp->d_secsize) 457 1.1 cgd break; 458 1.1 cgd } 459 1.27 lukem if ((size_t)n != dp->d_secsize) { 460 1.1 cgd if (n < 0) 461 1.20 fvdl err(4, "can't read sector, %lld", (long long)s1); 462 1.13 lukem else 463 1.20 fvdl errx(4, "can't read sector, %lld", (long long)s1); 464 1.1 cgd return(0); 465 1.1 cgd } 466 1.12 kleink if (lseek(f, (off_t)(dp->d_secsize * s2), SEEK_SET) < 0) 467 1.13 lukem err(4, "lseek"); 468 1.1 cgd if (verbose) 469 1.20 fvdl printf("copying %lld to %lld\n", (long long)s1, (long long)s2); 470 1.27 lukem if (nflag == 0 && (size_t)write(f, buf, dp->d_secsize) != dp->d_secsize) { 471 1.20 fvdl warn("can't write replacement sector, %lld", (long long)s2); 472 1.1 cgd return(0); 473 1.1 cgd } 474 1.1 cgd return(1); 475 1.1 cgd } 476 1.1 cgd 477 1.29 joerg static void 478 1.16 wiz blkzero(int f, daddr_t sn) 479 1.1 cgd { 480 1.18 wiz char *zbuf; 481 1.1 cgd 482 1.19 wiz zbuf = calloc(1, (unsigned int)dp->d_secsize); 483 1.19 wiz if (zbuf == NULL) 484 1.19 wiz errx(20, "Out of memory"); 485 1.23 christos if (lseek(f, (off_t)(dp->d_secsize * sn), SEEK_SET) < 0) { 486 1.23 christos free(zbuf); 487 1.13 lukem err(4, "lseek"); 488 1.23 christos } 489 1.1 cgd if (verbose) 490 1.20 fvdl printf("zeroing %lld\n", (long long)sn); 491 1.27 lukem if (nflag == 0 && (size_t)write(f, zbuf, dp->d_secsize) != dp->d_secsize) 492 1.20 fvdl warn("can't write replacement sector, %lld", 493 1.20 fvdl (long long)sn); 494 1.22 christos free(zbuf); 495 1.1 cgd } 496 1.1 cgd 497 1.29 joerg static int 498 1.16 wiz compare(const void *v1, const void *v2) 499 1.1 cgd { 500 1.11 mikel const struct bt_bad *b1 = v1; 501 1.11 mikel const struct bt_bad *b2 = v2; 502 1.11 mikel 503 1.1 cgd if (b1->bt_cyl > b2->bt_cyl) 504 1.1 cgd return(1); 505 1.1 cgd if (b1->bt_cyl < b2->bt_cyl) 506 1.1 cgd return(-1); 507 1.1 cgd if (b1->bt_trksec == b2->bt_trksec) 508 1.1 cgd dups++; 509 1.1 cgd return (b1->bt_trksec - b2->bt_trksec); 510 1.1 cgd } 511 1.1 cgd 512 1.29 joerg static daddr_t 513 1.16 wiz badsn(const struct bt_bad *bt) 514 1.1 cgd { 515 1.11 mikel 516 1.11 mikel return ((bt->bt_cyl * dp->d_ntracks 517 1.11 mikel + (bt->bt_trksec >> 8)) * dp->d_nsectors 518 1.11 mikel + (bt->bt_trksec & 0xff)); 519 1.1 cgd } 520 1.1 cgd 521 1.15 matt #ifdef __vax__ 522 1.1 cgd 523 1.1 cgd struct rp06hdr { 524 1.1 cgd short h_cyl; 525 1.1 cgd short h_trksec; 526 1.1 cgd short h_key1; 527 1.1 cgd short h_key2; 528 1.1 cgd char h_data[512]; 529 1.1 cgd #define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */ 530 1.1 cgd }; 531 1.1 cgd 532 1.1 cgd /* 533 1.1 cgd * Most massbus and unibus drives 534 1.1 cgd * have headers of this form 535 1.1 cgd */ 536 1.1 cgd struct hpuphdr { 537 1.1 cgd u_short hpup_cyl; 538 1.1 cgd u_char hpup_sect; 539 1.1 cgd u_char hpup_track; 540 1.1 cgd char hpup_data[512]; 541 1.1 cgd #define HPUP_OKSECT 0xc000 /* this normally means sector is good */ 542 1.1 cgd #define HPUP_16BIT 0x1000 /* 1 == 16 bit format */ 543 1.1 cgd }; 544 1.1 cgd 545 1.29 joerg static int rp06format(struct formats *, struct disklabel *, daddr_t, char *, int); 546 1.29 joerg static int hpupformat(struct formats *, struct disklabel *, daddr_t, char *, int); 547 1.29 joerg 548 1.29 joerg static struct formats { 549 1.1 cgd char *f_name; /* disk name */ 550 1.1 cgd int f_bufsize; /* size of sector + header */ 551 1.1 cgd int f_bic; /* value to bic in hpup_cyl */ 552 1.1 cgd int (*f_routine)(); /* routine for special handling */ 553 1.1 cgd } formats[] = { 554 1.1 cgd { "rp06", sizeof (struct rp06hdr), RP06_FMT, rp06format }, 555 1.1 cgd { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 556 1.1 cgd { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 557 1.1 cgd { "rm03", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 558 1.1 cgd { "rm05", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 559 1.1 cgd { "9300", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 560 1.1 cgd { "9766", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 561 1.1 cgd { 0, 0, 0, 0 } 562 1.1 cgd }; 563 1.1 cgd 564 1.1 cgd /*ARGSUSED*/ 565 1.29 joerg static int 566 1.18 wiz hpupformat(struct formats *fp, struct disklabel *dp, daddr_t blk, char *buf, 567 1.18 wiz int count) 568 1.1 cgd { 569 1.1 cgd struct hpuphdr *hdr = (struct hpuphdr *)buf; 570 1.1 cgd int sect; 571 1.1 cgd 572 1.1 cgd if (count < sizeof(struct hpuphdr)) { 573 1.1 cgd hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) | 574 1.1 cgd (blk / (dp->d_nsectors * dp->d_ntracks)); 575 1.1 cgd sect = blk % (dp->d_nsectors * dp->d_ntracks); 576 1.1 cgd hdr->hpup_track = (u_char)(sect / dp->d_nsectors); 577 1.1 cgd hdr->hpup_sect = (u_char)(sect % dp->d_nsectors); 578 1.1 cgd } 579 1.1 cgd return (0); 580 1.1 cgd } 581 1.1 cgd 582 1.1 cgd /*ARGSUSED*/ 583 1.29 joerg static int 584 1.18 wiz rp06format(struct formats *fp, struct disklabel *dp, daddr_t blk, char *buf, 585 1.18 wiz int count) 586 1.1 cgd { 587 1.1 cgd 588 1.1 cgd if (count < sizeof(struct rp06hdr)) { 589 1.13 lukem warnx("Can't read header on blk %d, can't reformat", blk); 590 1.1 cgd return (-1); 591 1.1 cgd } 592 1.1 cgd return (0); 593 1.1 cgd } 594 1.1 cgd 595 1.29 joerg static void 596 1.18 wiz format(int fd, daddr_t blk) 597 1.1 cgd { 598 1.13 lukem struct formats *fp; 599 1.1 cgd static char *buf; 600 1.1 cgd static char bufsize; 601 1.1 cgd struct format_op fop; 602 1.1 cgd int n; 603 1.1 cgd 604 1.1 cgd for (fp = formats; fp->f_name; fp++) 605 1.1 cgd if (strcmp(dp->d_typename, fp->f_name) == 0) 606 1.1 cgd break; 607 1.13 lukem if (fp->f_name == 0) 608 1.13 lukem errx(2, "don't know how to format %s disks", dp->d_typename); 609 1.1 cgd if (buf && bufsize < fp->f_bufsize) { 610 1.1 cgd free(buf); 611 1.1 cgd buf = NULL; 612 1.1 cgd } 613 1.1 cgd if (buf == NULL) 614 1.1 cgd buf = malloc((unsigned)fp->f_bufsize); 615 1.13 lukem if (buf == NULL) 616 1.13 lukem errx(3, "can't allocate sector buffer"); 617 1.1 cgd bufsize = fp->f_bufsize; 618 1.1 cgd /* 619 1.1 cgd * Here we do the actual formatting. All we really 620 1.1 cgd * do is rewrite the sector header and flag the bad sector 621 1.1 cgd * according to the format table description. If a special 622 1.1 cgd * purpose format routine is specified, we allow it to 623 1.1 cgd * process the sector as well. 624 1.1 cgd */ 625 1.1 cgd if (verbose) 626 1.1 cgd printf("format blk %d\n", blk); 627 1.13 lukem memset((char *)&fop, 0, sizeof(fop)); 628 1.1 cgd fop.df_buf = buf; 629 1.1 cgd fop.df_count = fp->f_bufsize; 630 1.1 cgd fop.df_startblk = blk; 631 1.13 lukem memset(buf, 0, fp->f_bufsize); 632 1.1 cgd if (ioctl(fd, DIOCRFORMAT, &fop) < 0) 633 1.13 lukem warn("read format"); 634 1.1 cgd if (fp->f_routine && 635 1.1 cgd (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0) 636 1.1 cgd return; 637 1.1 cgd if (fp->f_bic) { 638 1.1 cgd struct hpuphdr *xp = (struct hpuphdr *)buf; 639 1.1 cgd 640 1.1 cgd xp->hpup_cyl &= ~fp->f_bic; 641 1.1 cgd } 642 1.1 cgd if (nflag) 643 1.1 cgd return; 644 1.13 lukem memset((char *)&fop, 0, sizeof(fop)); 645 1.1 cgd fop.df_buf = buf; 646 1.1 cgd fop.df_count = fp->f_bufsize; 647 1.1 cgd fop.df_startblk = blk; 648 1.1 cgd if (ioctl(fd, DIOCWFORMAT, &fop) < 0) 649 1.13 lukem err(4, "write format"); 650 1.13 lukem if (fop.df_count != fp->f_bufsize) 651 1.13 lukem warn("write format %d", blk); 652 1.1 cgd } 653 1.1 cgd #endif 654 1.19 wiz 655 1.29 joerg static void 656 1.19 wiz usage(void) 657 1.19 wiz { 658 1.19 wiz 659 1.19 wiz fprintf(stderr, "usage: bad144 [-%sv] disk [sno [bad ...]]\n" 660 1.19 wiz "to read or overwrite the bad-sector table, e.g.: bad144 hp0\n" 661 1.19 wiz "or bad144 -a [-c%sv] disk [bad ...]\n" 662 1.19 wiz "where options are:\n" 663 1.19 wiz "\t-a add new bad sectors to the table\n" 664 1.19 wiz "\t-c copy original sector to replacement\n" 665 1.19 wiz "%s" 666 1.19 wiz "\t-v verbose mode\n", 667 1.19 wiz #ifdef __vax__ 668 1.19 wiz "f", "f", "\t-f reformat listed sectors as bad\n" 669 1.19 wiz #else 670 1.19 wiz "", "", "" 671 1.19 wiz #endif 672 1.19 wiz ); 673 1.19 wiz exit(1); 674 1.19 wiz } 675