1 /* 2 * Copyright (c) 1982 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)up.c 7.6 (Berkeley) 05/27/88 7 */ 8 9 /* 10 * UNIBUS peripheral standalone driver with ECC correction and bad 11 * block forwarding. Also supports header operation and write check 12 * for data and/or header. 13 */ 14 #include "param.h" 15 #include "inode.h" 16 #include "fs.h" 17 #include "dkbad.h" 18 #include "disklabel.h" 19 20 #include "../vax/pte.h" 21 22 #include "../vaxuba/upreg.h" 23 #include "../vaxuba/ubareg.h" 24 25 #include "saio.h" 26 #include "savax.h" 27 28 #define RETRIES 27 29 30 #define MAXBADDESC 126 /* max number of bad sectors recorded */ 31 #define SECTSIZ 512 /* sector size in bytes */ 32 #define HDRSIZ 4 /* number of bytes in sector header */ 33 34 #define MAXUNIT 8 35 #define MAXCTLR 1 /* all addresses must be specified */ 36 u_short ubastd[MAXCTLR] = { 0776700 }; 37 struct disklabel uplabel[MAXNUBA][MAXCTLR][MAXUNIT]; 38 char lbuf[SECTSIZ]; 39 40 extern struct st upst[]; 41 42 #ifndef SMALL 43 struct dkbad upbad[MAXNUBA][MAXCTLR][MAXUNIT]; /* bad sector table */ 44 #endif 45 int sectsiz; /* real sector size */ 46 47 struct up_softc { 48 char gottype; 49 char type; 50 char debug; 51 # define UPF_BSEDEBUG 01 /* debugging bad sector forwarding */ 52 # define UPF_ECCDEBUG 02 /* debugging ecc correction */ 53 int retries; 54 int ecclim; 55 } up_softc[MAXNUBA][MAXCTLR][MAXUNIT]; 56 57 u_char up_offset[16] = { 58 UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 59 UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 60 UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 61 0, 0, 0, 0 62 }; 63 64 upopen(io) 65 register struct iob *io; 66 { 67 register struct updevice *upaddr; 68 register struct up_softc *sc; 69 register struct st *st; 70 register int unit; 71 struct disklabel *dlp, *lp; 72 int error = 0; 73 74 if ((u_int)io->i_ctlr >= MAXCTLR) 75 return (ECTLR); 76 if ((u_int)io->i_part >= MAXUNIT) 77 return (EPART); 78 upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]); 79 unit = io->i_unit; 80 upaddr->upcs2 = unit % 8; 81 while ((upaddr->upcs1 & UP_DVA) == 0); 82 sc = &up_softc[io->i_adapt][io->i_ctlr][unit]; 83 lp = &uplabel[io->i_adapt][io->i_ctlr][unit]; 84 if (sc->gottype == 0) { 85 register int i; 86 struct iob tio; 87 88 #ifndef SMALL 89 sc->retries = RETRIES; 90 sc->ecclim = 11; 91 sc->debug = 0; 92 #endif 93 /* Read in the pack label. */ 94 lp->d_nsectors = 32; 95 lp->d_secpercyl = 19*32; 96 tio = *io; 97 tio.i_bn = LABELSECTOR; 98 tio.i_ma = lbuf; 99 tio.i_cc = SECTSIZ; 100 tio.i_flgs |= F_RDDATA; 101 if (upstrategy(&tio, READ) != SECTSIZ) 102 error = ERDLAB; 103 dlp = (struct disklabel *)(lbuf + LABELOFFSET); 104 if (error == 0 && (dlp->d_magic != DISKMAGIC || 105 dlp->d_magic2 != DISKMAGIC)) 106 error = EUNLAB; 107 if (error == 0) 108 *lp = *dlp; 109 else 110 #ifdef COMPAT_42 111 if (upmaptype(unit, upaddr, lp) == 0) 112 #endif 113 return (error); 114 115 #ifndef SMALL 116 /* Read in the bad sector table. */ 117 tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors; 118 tio.i_ma = (char *)&upbad[io->i_adapt][io->i_ctlr][io->i_unit]; 119 tio.i_cc = sizeof(struct dkbad); 120 tio.i_flgs |= F_RDDATA; 121 for (i = 0; i < 5; i++) { 122 if (upstrategy(&tio, READ) == sizeof(struct dkbad)) 123 break; 124 tio.i_bn += 2; 125 } 126 if (i == 5) { 127 printf("up: can't read bad sector table\n"); 128 for (i = 0; i < MAXBADDESC; i++) { 129 upbad[tio.i_adapt][tio.i_ctlr][unit].bt_bad[i].bt_cyl = -1; 130 upbad[tio.i_adapt][tio.i_ctlr][unit].bt_bad[i].bt_trksec = -1; 131 } 132 } 133 #endif 134 sc->gottype = 1; 135 } 136 if (io->i_part >= lp->d_npartitions || 137 lp->d_partitions[io->i_part].p_size == 0) 138 return (EPART); 139 io->i_boff = lp->d_partitions[io->i_part].p_offset; 140 io->i_flgs &= ~F_TYPEMASK; 141 return (0); 142 } 143 144 upstrategy(io, func) 145 register struct iob *io; 146 int func; 147 { 148 int cn, tn, sn, o; 149 register unit = io->i_unit; 150 register daddr_t bn; 151 int recal, info, waitdry; 152 register struct updevice *upaddr; 153 register struct disklabel *lp; 154 struct up_softc *sc; 155 int error, rv = io->i_cc; 156 #ifndef SMALL 157 int doprintf = 0; 158 #endif 159 160 upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]); 161 sc = &up_softc[io->i_adapt][io->i_ctlr][unit]; 162 lp = &uplabel[io->i_adapt][io->i_ctlr][unit]; 163 sectsiz = SECTSIZ; 164 if (io->i_flgs & (F_HDR|F_HCHECK)) 165 sectsiz += HDRSIZ; 166 upaddr->upcs2 = unit % 8; 167 if ((upaddr->upds & UPDS_VV) == 0) { 168 upaddr->upcs1 = UP_DCLR|UP_GO; 169 upaddr->upcs1 = UP_PRESET|UP_GO; 170 upaddr->upof = UPOF_FMT22; 171 } 172 if ((upaddr->upds & UPDS_DREADY) == 0) { 173 printf("up%d not ready", unit); 174 return (-1); 175 } 176 info = ubasetup(io, 1); 177 upaddr->upwc = -io->i_cc / sizeof (short); 178 recal = 0; 179 io->i_errcnt = 0; 180 181 restart: 182 error = 0; 183 o = io->i_cc + (upaddr->upwc * sizeof (short)); 184 upaddr->upba = info + o; 185 bn = io->i_bn + o / sectsiz; 186 #ifndef SMALL 187 if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) 188 printf("wc=%d o=%d i_bn=%d bn=%d\n", 189 upaddr->upwc, o, io->i_bn, bn); 190 #endif 191 while((upaddr->upds & UPDS_DRY) == 0) 192 ; 193 if (upstart(io, bn, lp) != 0) { 194 rv = -1; 195 goto done; 196 } 197 do { 198 DELAY(25); 199 } while ((upaddr->upcs1 & UP_RDY) == 0); 200 /* 201 * If transfer has completed, free UNIBUS 202 * resources and return transfer size. 203 */ 204 if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0) 205 goto done; 206 bn = io->i_bn + 207 (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz; 208 if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH)) 209 bn--; 210 cn = bn / lp->d_secpercyl; 211 sn = bn % lp->d_secpercyl; 212 tn = sn / lp->d_nsectors; 213 sn = sn % lp->d_nsectors; 214 #ifndef SMALL 215 if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) { 216 printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ", 217 bn, cn, tn, sn); 218 printf("cs2=%b er1=%b er2=%b wc=%d\n", 219 upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 220 UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc); 221 } 222 #endif 223 waitdry = 0; 224 while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz) 225 DELAY(5); 226 #ifndef SMALL 227 if (upaddr->uper1&UPER1_WLE) { 228 /* 229 * Give up on write locked devices immediately. 230 */ 231 printf("up%d: write locked\n", unit); 232 rv = -1; 233 goto done; 234 } 235 if (upaddr->uper2 & UPER2_BSE) { 236 if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0) 237 goto success; 238 error = EBSE; 239 goto hard; 240 } 241 /* 242 * ECC error. If a soft error, correct it; 243 * if correction is too large, no more retries. 244 */ 245 if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) { 246 if (upecc(io, ECC) == 0) 247 goto success; 248 error = EECC; 249 goto hard; 250 } 251 /* 252 * If the error is a header CRC, check if a replacement sector 253 * exists in the bad sector table. 254 */ 255 if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 && 256 upecc(io, BSE) == 0) 257 goto success; 258 #endif 259 if (++io->i_errcnt > sc->retries) { 260 /* 261 * After 28 retries (16 without offset, and 262 * 12 with offset positioning) give up. 263 */ 264 hard: 265 if (error == 0) { 266 error = EHER; 267 if (upaddr->upcs2 & UPCS2_WCE) 268 error = EWCK; 269 } 270 printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ", 271 bn, cn, tn, sn); 272 printf("cs2=%b er1=%b er2=%b\n", 273 upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 274 UPER1_BITS, upaddr->uper2, UPER2_BITS); 275 upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 276 io->i_errblk = bn; 277 if (io->i_errcnt >= 16) { 278 upaddr->upof = UPOF_FMT22; 279 upaddr->upcs1 = UP_RTC|UP_GO; 280 while ((upaddr->upds&UPDS_DRY) == 0) 281 DELAY(25); 282 } 283 rv = -1; 284 goto done; 285 } 286 /* 287 * Clear drive error and, every eight attempts, (starting with the 288 * fourth) recalibrate to clear the slate. 289 */ 290 upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 291 if ((io->i_errcnt&07) == 4 ) { 292 upaddr->upcs1 = UP_RECAL|UP_GO; 293 while ((upaddr->upds&UPDS_DRY) == 0) 294 DELAY(25); 295 upaddr->updc = cn; 296 upaddr->upcs1 = UP_SEEK|UP_GO; 297 while ((upaddr->upds&UPDS_DRY) == 0) 298 DELAY(25); 299 } 300 if (io->i_errcnt >= 16 && (func & READ)) { 301 upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22; 302 upaddr->upcs1 = UP_OFFSET|UP_GO; 303 while ((upaddr->upds&UPDS_DRY) == 0) 304 DELAY(25); 305 } 306 goto restart; 307 308 success: 309 #define rounddown(x, y) (((x) / (y)) * (y)) 310 upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short)); 311 if (upaddr->upwc) { 312 #ifndef SMALL 313 doprintf++; 314 #endif 315 goto restart; 316 } 317 done: 318 ubafree(io, info); 319 /* 320 * If we were offset positioning, 321 * return to centerline. 322 */ 323 if (io->i_errcnt >= 16) { 324 upaddr->upof = UPOF_FMT22; 325 upaddr->upcs1 = UP_RTC|UP_GO; 326 while ((upaddr->upds&UPDS_DRY) == 0) 327 DELAY(25); 328 } 329 return (rv); 330 } 331 332 #ifndef SMALL 333 /* 334 * Correct an ECC error, and restart the i/o to complete the transfer (if 335 * necessary). This is quite complicated because the transfer may be going 336 * to an odd memory address base and/or across a page boundary. 337 */ 338 upecc(io, flag) 339 register struct iob *io; 340 int flag; 341 { 342 register i, unit; 343 register struct up_softc *sc; 344 register struct updevice *up; 345 register struct disklabel *lp; 346 caddr_t addr; 347 int bn, twc, npf, mask, cn, tn, sn; 348 daddr_t bbn; 349 350 /* 351 * Npf is the number of sectors transferred 352 * before the sector containing the ECC error; 353 * bn is the current block number. 354 */ 355 unit = io->i_unit; 356 sc = &up_softc[io->i_adapt][io->i_ctlr][unit]; 357 lp = &uplabel[io->i_adapt][io->i_ctlr][unit]; 358 up = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]); 359 twc = up->upwc; 360 npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz; 361 if (flag == ECC) 362 npf--; 363 if (sc->debug & UPF_ECCDEBUG) 364 printf("npf=%d mask=0x%x ec1=%d wc=%d\n", 365 npf, up->upec2, up->upec1, twc); 366 bn = io->i_bn + npf; 367 cn = bn / lp->d_secpercyl; 368 sn = bn % lp->d_secpercyl; 369 tn = sn / lp->d_nsectors; 370 sn = sn % lp->d_nsectors; 371 372 /* 373 * ECC correction. 374 */ 375 if (flag == ECC) { 376 int bit, o; 377 378 mask = up->upec2; 379 printf("up%d: soft ecc sn%d\n", unit, bn); 380 for (i = mask, bit = 0; i; i >>= 1) 381 if (i & 1) 382 bit++; 383 if (bit > sc->ecclim) { 384 printf("%d-bit error\n", bit); 385 return (1); 386 } 387 /* 388 * Compute the byte and bit position of 389 * the error. o is the byte offset in 390 * the transfer at which the correction 391 * applied. 392 */ 393 i = up->upec1 - 1; /* -1 makes 0 origin */ 394 bit = i & 07; 395 o = (i & ~07) >> 3; 396 up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 397 /* 398 * Correct while possible bits remain of mask. 399 * Since mask contains 11 bits, we continue while 400 * the bit offset is > -11. Also watch out for 401 * end of this block and the end of the transfer. 402 */ 403 while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) { 404 /* 405 * addr = 406 * (base address of transfer) + 407 * (# sectors transferred before the error) * 408 * (sector size) + 409 * (byte offset to incorrect data) 410 */ 411 addr = io->i_ma + (npf * sectsiz) + o; 412 /* 413 * No data transfer occurs with a write check, 414 * so don't correct the resident copy of data. 415 */ 416 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { 417 if (sc->debug & UPF_ECCDEBUG) 418 printf("addr=0x%x old=0x%x ", addr, 419 (*addr&0xff)); 420 *addr ^= (mask << bit); 421 if (sc->debug & UPF_ECCDEBUG) 422 printf("new=0x%x\n", (*addr&0xff)); 423 } 424 o++, bit -= 8; 425 } 426 return (0); 427 } 428 429 /* 430 * Bad sector forwarding. 431 */ 432 if (flag == BSE) { 433 /* 434 * If not in bad sector table, 435 * indicate a hard error to caller. 436 */ 437 up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 438 if ((bbn = isbad(&upbad[io->i_adapt][io->i_ctlr][unit], cn, tn, sn)) < 0) 439 return (1); 440 bbn = (lp->d_ncylinders * lp->d_secpercyl) - 441 lp->d_nsectors - 1 - bbn; 442 twc = up->upwc + sectsiz; 443 up->upwc = - (sectsiz / sizeof (short)); 444 if (sc->debug & UPF_BSEDEBUG) 445 printf("revector sn %d to %d\n", sn, bbn); 446 /* 447 * Clear the drive & read the replacement 448 * sector. If this is in the middle of a 449 * transfer, then set up the controller 450 * registers in a normal fashion. 451 * The UNIBUS address need not be changed. 452 */ 453 while ((up->upcs1 & UP_RDY) == 0) 454 ; 455 if (upstart(io, bbn, lp)) 456 return (1); /* error */ 457 io->i_errcnt = 0; /* success */ 458 do { 459 DELAY(25); 460 } while ((up->upcs1 & UP_RDY) == 0) ; 461 if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) { 462 up->upwc = twc - sectsiz; 463 return (1); 464 } 465 } 466 if (twc) 467 up->upwc = twc; 468 return (0); 469 } 470 #endif /* !SMALL */ 471 472 upstart(io, bn, lp) 473 register struct iob *io; 474 daddr_t bn; 475 register struct disklabel *lp; 476 { 477 register struct updevice *upaddr; 478 register struct up_softc *sc; 479 int sn, tn; 480 481 upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]); 482 sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit]; 483 sn = bn % lp->d_secpercyl; 484 tn = sn / lp->d_nsectors; 485 sn = sn % lp->d_nsectors; 486 upaddr->updc = bn / lp->d_secpercyl; 487 upaddr->upda = (tn << 8) + sn; 488 switch (io->i_flgs & F_TYPEMASK) { 489 490 case F_RDDATA: 491 upaddr->upcs1 = UP_RCOM|UP_GO; 492 break; 493 494 case F_WRDATA: 495 upaddr->upcs1 = UP_WCOM|UP_GO; 496 break; 497 498 #ifndef SMALL 499 case F_HDR|F_RDDATA: 500 upaddr->upcs1 = UP_RHDR|UP_GO; 501 break; 502 503 case F_HDR|F_WRDATA: 504 upaddr->upcs1 = UP_WHDR|UP_GO; 505 break; 506 507 case F_CHECK|F_WRDATA: 508 case F_CHECK|F_RDDATA: 509 upaddr->upcs1 = UP_WCDATA|UP_GO; 510 break; 511 512 case F_HCHECK|F_WRDATA: 513 case F_HCHECK|F_RDDATA: 514 upaddr->upcs1 = UP_WCHDR|UP_GO; 515 break; 516 #endif 517 518 default: 519 io->i_error = ECMD; 520 io->i_flgs &= ~F_TYPEMASK; 521 return (1); 522 } 523 return (0); 524 } 525 526 #ifndef SMALL 527 /*ARGSUSED*/ 528 upioctl(io, cmd, arg) 529 struct iob *io; 530 int cmd; 531 caddr_t arg; 532 { 533 register struct up_softc *sc; 534 535 sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit]; 536 switch(cmd) { 537 case SAIODEBUG: 538 sc->debug = (int)arg; 539 break; 540 case SAIODEVDATA: 541 *(struct disklabel *)arg = 542 uplabel[io->i_adapt][io->i_ctlr][io->i_unit]; 543 break; 544 case SAIOGBADINFO: 545 *(struct dkbad *)arg = 546 upbad[io->i_adapt][io->i_ctlr][io->i_unit]; 547 break; 548 case SAIOECCLIM: 549 sc->ecclim = (int)arg; 550 break; 551 case SAIORETRIES: 552 sc->retries = (int)arg; 553 break; 554 default: 555 return (ECMD); 556 } 557 return (0); 558 } 559 #endif /* !SMALL */ 560