1 /* 2 * Copyright (c) 1982, 1986 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 * @(#)hp.c 7.10 (Berkeley) 07/08/88 7 */ 8 9 /* 10 * RP??/RM?? disk driver with ECC handling and bad block forwarding. 11 * Also supports header io operations and commands to write check 12 * header and data. 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 "../vaxmba/hpreg.h" 23 #include "../vaxmba/mbareg.h" 24 25 #include "saio.h" 26 #include "savax.h" 27 28 #define RETRIES 27 29 30 #define MASKREG(reg) ((reg)&0xffff) 31 32 #define MAXBADDESC 126 33 #define SECTSIZ 512 /* sector size in bytes */ 34 #define HDRSIZ 4 /* number of bytes in sector header */ 35 36 char lbuf[SECTSIZ]; 37 38 #define RP06(type) ((type) == MBDT_RP06 || (type) == MBDT_RP05 \ 39 || (type) == MBDT_RP04) 40 #define ML11(type) ((type) == MBDT_ML11A) 41 #define RM80(type) ((type) == MBDT_RM80) 42 43 u_char hp_offset[16] = { 44 HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 45 HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 46 HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 47 0, 0, 0, 0, 48 }; 49 50 #define MAXUNIT 8 51 struct disklabel hplabel[MAXNMBA][MAXUNIT]; 52 #ifndef SMALL 53 struct dkbad hpbad[MAXNMBA][MAXUNIT]; 54 int sectsiz; 55 #endif 56 57 struct hp_softc { 58 char type; 59 char gottype; 60 char ssect; /* 1 when on track w/skip sector */ 61 char debug; 62 # define HPF_BSEDEBUG 01 /* debugging bad sector forwarding */ 63 # define HPF_ECCDEBUG 02 /* debugging ecc correction */ 64 int ecclim; 65 int retries; 66 } hp_softc[MAXNMBA][MAXUNIT]; 67 68 /* 69 * When awaiting command completion, don't hang on to the status register 70 * since this ties up some controllers. 71 */ 72 #define HPWAIT(addr) \ 73 while ((((addr)->hpds)&HPDS_DRY) == 0) \ 74 DELAY(500); 75 76 hpopen(io) 77 register struct iob *io; 78 { 79 register unit = io->i_unit; 80 register struct hp_softc *sc; 81 register struct disklabel *lp; 82 struct hpdevice *hpaddr; 83 struct disklabel *dlp; 84 int error = 0; 85 86 /* 87 * Accept adaptor number as either controller or adaptor, 88 * but not both. 89 */ 90 if (io->i_ctlr) { 91 if (io->i_adapt == 0) 92 io->i_adapt = io->i_ctlr; 93 else 94 return (ECTLR); 95 } 96 if ((u_int)io->i_adapt >= MAXNMBA || !mbainit(io->i_adapt)) 97 return (EADAPT); 98 if ((u_int)unit >= MAXUNIT) 99 return (EUNIT); 100 hpaddr = (struct hpdevice *)mbadrv(io->i_adapt, unit); 101 sc = &hp_softc[io->i_adapt][unit]; 102 lp = &hplabel[io->i_adapt][unit]; 103 if (sc->gottype == 0) { 104 register int i; 105 struct iob tio; 106 107 #ifndef SMALL 108 sc->retries = RETRIES; 109 sc->ecclim = 11; 110 sc->debug = 0; 111 #endif 112 hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */ 113 hpaddr->hpcs1 = HP_PRESET|HP_GO; 114 #ifndef SMALL 115 if ((hpaddr->hpds & HPDS_DPR) == 0) 116 return (ENXIO); 117 sc->type = hpaddr->hpdt & MBDT_TYPE; 118 if (sc->type == MBDT_ML11B) 119 sc->type = MBDT_ML11A; 120 if (!ML11(sc->type)) 121 #endif 122 hpaddr->hpof = HPOF_FMT22; 123 /* 124 * Read in the pack label. 125 */ 126 lp->d_nsectors = 32; 127 lp->d_secpercyl = 20*32; 128 tio = *io; 129 tio.i_bn = LABELSECTOR; 130 tio.i_ma = lbuf; 131 tio.i_cc = SECTSIZ; 132 tio.i_flgs |= F_RDDATA; 133 if (hpstrategy(&tio, READ) != SECTSIZ) 134 error = ERDLAB; 135 dlp = (struct disklabel *)(lbuf + LABELOFFSET); 136 if (error == 0 && (dlp->d_magic != DISKMAGIC || 137 dlp->d_magic2 != DISKMAGIC)) 138 error = EUNLAB; 139 if (error == 0) 140 *lp = *dlp; 141 else 142 #ifdef COMPAT_42 143 if (hpmaptype(hpaddr, hpaddr->hpdt & MBDT_TYPE, unit, lp) == 0) 144 #endif 145 return (error); 146 147 #ifndef SMALL 148 /* 149 * Read in the bad sector table. 150 */ 151 tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors; 152 tio.i_ma = (char *)&hpbad[io->i_adapt][unit]; 153 tio.i_cc = sizeof(struct dkbad); 154 for (i = 0; i < 5; i++) { 155 if (hpstrategy(&tio, READ) == sizeof(struct dkbad)) 156 break; 157 tio.i_bn += 2; 158 } 159 if (i == 5) { 160 printf("hp: can't read bad sector table\n"); 161 for (i = 0; i < MAXBADDESC; i++) { 162 hpbad[io->i_adapt][unit].bt_bad[i].bt_cyl = -1; 163 hpbad[io->i_adapt][unit].bt_bad[i].bt_trksec = -1; 164 } 165 } 166 #endif 167 sc->gottype = 1; 168 } 169 if (io->i_part >= lp->d_npartitions || 170 lp->d_partitions[io->i_part].p_size == 0) 171 return (EPART); 172 io->i_boff = lp->d_partitions[io->i_part].p_offset; 173 return (0); 174 } 175 176 hpstrategy(io, func) 177 register struct iob *io; 178 { 179 register int unit = io->i_unit; 180 register struct hp_softc *sc; 181 register struct disklabel *lp; 182 struct mba_regs *mba; 183 struct hpdevice *hpaddr; 184 daddr_t bn, startblock; 185 int cn, tn, sn, bytecnt, bytesleft, rv; 186 int er1, er2, hprecal; 187 char *membase; 188 189 mba = mbamba(io->i_adapt); 190 hpaddr = (struct hpdevice *)mbadrv(io->i_adapt, unit); 191 sc = &hp_softc[io->i_adapt][unit]; 192 lp = &hplabel[io->i_adapt][unit]; 193 #ifndef SMALL 194 sectsiz = SECTSIZ; 195 if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) 196 sectsiz += HDRSIZ; 197 if ((hpaddr->hpds & HPDS_VV) == 0) { 198 hpaddr->hpcs1 = HP_DCLR|HP_GO; 199 hpaddr->hpcs1 = HP_PRESET|HP_GO; 200 if (!ML11(sc->type)) 201 hpaddr->hpof = HPOF_FMT22; 202 } 203 io->i_errcnt = 0; 204 sc->ssect = 0; 205 rv = bytecnt = io->i_cc; 206 membase = io->i_ma; 207 startblock = io->i_bn; 208 hprecal = 0; 209 #endif 210 211 restart: 212 bn = io->i_bn; 213 cn = bn / lp->d_secpercyl; 214 sn = bn % lp->d_secpercyl; 215 tn = sn / lp->d_nsectors; 216 sn = sn % lp->d_nsectors + sc->ssect; 217 218 HPWAIT(hpaddr); 219 mba->mba_sr = -1; 220 if (ML11(sc->type)) 221 hpaddr->hpda = bn; 222 else { 223 hpaddr->hpdc = cn; 224 hpaddr->hpda = (tn << 8) + sn; 225 } 226 #ifdef SMALL 227 mbastart(io, io->i_unit, func); /* start transfer */ 228 HPWAIT(hpaddr); 229 if (hpaddr->hpds & HPDS_ERR) { 230 printf("hp error: sn [%d-%d) ds=%b er1=%b\n", 231 bn, bn + io->i_cc/SECTSIZ, MASKREG(hpaddr->hpds), HPDS_BITS, 232 MASKREG(hpaddr->hper1), HPER1_BITS); 233 return (-1); 234 } 235 return (io->i_cc); 236 #else 237 if (mbastart(io, io->i_unit, func) != 0) { /* start transfer */ 238 rv = -1; 239 goto done; 240 } 241 HPWAIT(hpaddr); 242 /* 243 * Successful data transfer, return. 244 */ 245 if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0) 246 goto done; 247 248 /* 249 * Error handling. Calculate location of error. 250 */ 251 bytesleft = MASKREG(mba->mba_bcr); 252 if (bytesleft) 253 bytesleft |= 0xffff0000; /* sxt */ 254 bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz; 255 er1 = MASKREG(hpaddr->hper1); 256 er2 = MASKREG(hpaddr->hper2); 257 if (er1 & (HPER1_DCK|HPER1_ECH)) 258 bn--; /* Error is in Prev block */ 259 cn = bn/lp->d_secpercyl; 260 sn = bn%lp->d_secpercyl; 261 tn = sn/lp->d_nsectors; 262 sn = sn%lp->d_nsectors; 263 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) { 264 printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b\n", 265 bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 266 printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS); 267 printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft, 268 hpaddr->hpof, hpaddr->hpda); 269 } 270 if (er1 & HPER1_HCRC) { 271 er1 &= ~(HPER1_HCE|HPER1_FER); 272 er2 &= ~HPER2_BSE; 273 if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0) 274 goto success; 275 } 276 /* 277 * Give up early if drive write locked. 278 */ 279 if (er1&HPER1_WLE) { 280 printf("hp%d: write locked\n", unit); 281 rv = -1; 282 goto done; 283 } 284 /* 285 * Skip sector handling. 286 */ 287 if (RM80(sc->type) && (er2 & HPER2_SSE)) { 288 (void) hpecc(io, SSE); 289 sc->ssect = 1; 290 goto restart; 291 } 292 /* 293 * Attempt to forward bad sectors on anything but an ML11. 294 * Interpret format error bit as a bad block on RP06's. 295 */ 296 if (((er2 & HPER2_BSE) && !ML11(sc->type)) || 297 (MASKREG(er1) == HPER1_FER && RP06(sc->type))) { 298 if (io->i_flgs & F_NBSF) { 299 io->i_error = EBSE; 300 goto hard; 301 } 302 if (hpecc(io, BSE) == 0) 303 goto success; 304 io->i_error = EBSE; 305 goto hard; 306 } 307 /* 308 * ECC correction? 309 */ 310 if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { 311 if (hpecc(io, ECC) == 0) 312 goto success; 313 io->i_error = EECC; 314 goto hard; 315 } 316 317 /* 318 * If a hard error, or maximum retry count 319 * exceeded, clear controller state and 320 * pass back error to caller. 321 */ 322 if (++io->i_errcnt > sc->retries || (er1 & HPER1_HARD) || 323 (!ML11(sc->type) && (er2 & HPER2_HARD)) || 324 (ML11(sc->type) && (io->i_errcnt >= 16))) { 325 io->i_error = EHER; 326 if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) 327 io->i_error = EWCK; 328 hard: 329 io->i_errblk = bn + sc->ssect; 330 if (sc->debug & (HPF_BSEDEBUG|HPF_ECCDEBUG)) 331 printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc), 332 MASKREG(hpaddr->hpda)); 333 else { 334 printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 335 bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 336 printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 337 } 338 hpaddr->hpcs1 = HP_DCLR|HP_GO; 339 printf("\n"); 340 rv = -1; 341 goto done; 342 343 } 344 /* fall thru to retry */ 345 hpaddr->hpcs1 = HP_DCLR|HP_GO; 346 HPWAIT(hpaddr); 347 348 /* 349 * Every fourth retry recalibrate. 350 */ 351 if (((io->i_errcnt & 07) == 4) ) { 352 hpaddr->hpcs1 = HP_RECAL|HP_GO; 353 HPWAIT(hpaddr); 354 hpaddr->hpdc = cn; 355 hpaddr->hpcs1 = HP_SEEK|HP_GO; 356 HPWAIT(hpaddr); 357 } 358 359 if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) { 360 hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; 361 hpaddr->hpcs1 = HP_OFFSET|HP_GO; 362 HPWAIT(hpaddr); 363 } 364 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) 365 printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", 366 io->i_bn, io->i_cc, io->i_ma, hprecal); 367 goto restart; 368 369 success: 370 /* 371 * On successful error recovery, bump 372 * block number to advance to next portion 373 * of i/o transfer. 374 */ 375 bn++; 376 if ((bn-startblock) * sectsiz < bytecnt) { 377 io->i_bn = bn; 378 io->i_ma = membase + (io->i_bn - startblock)*sectsiz; 379 io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; 380 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) 381 printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", 382 io->i_bn, io->i_cc, io->i_ma, hprecal); 383 goto restart; 384 } 385 done: 386 if (io->i_errcnt >= 16) { 387 hpaddr->hpcs1 = HP_RTC|HP_GO; 388 while (hpaddr->hpds & HPDS_PIP) 389 ; 390 } 391 io->i_bn = startblock; /*reset i_bn to original */ 392 io->i_cc = bytecnt; /*reset i_cc to total count xfered*/ 393 io->i_ma = membase; /*reset i_ma to original */ 394 return (rv); 395 #endif 396 } 397 398 #ifndef SMALL 399 hpecc(io, flag) 400 register struct iob *io; 401 int flag; 402 { 403 register int unit = io->i_unit; 404 register struct mba_regs *mbp; 405 register struct hpdevice *rp; 406 register struct hp_softc *sc; 407 register struct disklabel *lp; 408 int npf, bn, cn, tn, sn, bcr; 409 410 mbp = mbamba(io->i_adapt); 411 rp = (struct hpdevice *)mbadrv(io->i_adapt, unit); 412 sc = &hp_softc[io->i_adapt][unit]; 413 lp = &hplabel[io->i_adapt][unit]; 414 bcr = MASKREG(mbp->mba_bcr); 415 if (bcr) 416 bcr |= 0xffff0000; /* sxt */ 417 npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ 418 if (flag == ECC) 419 npf--; /* Error is in prev block --ghg */ 420 bn = io->i_bn + npf + sc->ssect; /* physical block #*/ 421 if (sc->debug & HPF_ECCDEBUG) 422 printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n", 423 bcr, npf, sc->ssect, sectsiz, io->i_cc); 424 /* 425 * ECC correction logic. 426 */ 427 if (flag == ECC) { 428 register int i; 429 caddr_t addr; 430 int bit, o, mask; 431 432 printf("hp%d: soft ecc sn%d\n", unit, bn); 433 mask = MASKREG(rp->hpec2); 434 for (i = mask, bit = 0; i; i >>= 1) 435 if (i & 1) 436 bit++; 437 if (bit > sc->ecclim) { 438 printf("%d-bit error\n", bit); 439 return (1); 440 } 441 i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ 442 bit = i&07; 443 o = (i & ~07) >> 3; 444 rp->hpcs1 = HP_DCLR | HP_GO; 445 while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) { 446 addr = io->i_ma + (npf*sectsiz) + o; 447 /* 448 * No data transfer occurs with a write check, 449 * so don't correct the resident copy of data. 450 */ 451 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { 452 if (sc->debug & HPF_ECCDEBUG) 453 printf("addr=%x old=%x ", addr, 454 (*addr & 0xff)); 455 *addr ^= (mask << bit); 456 if (sc->debug & HPF_ECCDEBUG) 457 printf("new=%x\n",(*addr & 0xff)); 458 } 459 o++, bit -= 8; 460 } 461 return (0); 462 } 463 464 /* 465 * Skip sector error. 466 * Set skip-sector-inhibit and 467 * read next sector 468 */ 469 if (flag == SSE) { 470 rp->hpcs1 = HP_DCLR | HP_GO; 471 HPWAIT(rp); 472 rp->hpof |= HPOF_SSEI; 473 return (0); 474 } 475 476 /* 477 * Bad block forwarding. 478 */ 479 if (flag == BSE) { 480 int bbn; 481 482 rp->hpcs1 = HP_DCLR | HP_GO; 483 if (sc->debug & HPF_BSEDEBUG) 484 printf("hpecc: BSE @ bn %d\n", bn); 485 cn = bn / lp->d_secpercyl; 486 sn = bn % lp->d_secpercyl; 487 tn = sn / lp->d_nsectors; 488 sn = sn % lp->d_nsectors; 489 bcr += sectsiz; 490 if ((bbn = isbad(&hpbad[io->i_adapt][unit], cn, tn, sn)) < 0) 491 return (1); 492 bbn = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors - 1 493 - bbn; 494 cn = bbn / lp->d_secpercyl; 495 sn = bbn % lp->d_secpercyl; 496 tn = sn / lp->d_nsectors; 497 sn = sn % lp->d_nsectors; 498 io->i_cc = sectsiz; 499 io->i_ma += npf * sectsiz; 500 if (sc->debug & HPF_BSEDEBUG) 501 printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 502 rp->hpof &= ~HPOF_SSEI; 503 mbp->mba_sr = -1; 504 rp->hpdc = cn; 505 rp->hpda = (tn<<8) + sn; 506 mbastart(io, io->i_unit, io->i_flgs); 507 io->i_errcnt = 0; 508 HPWAIT(rp); 509 return (rp->hpds&HPDS_ERR); 510 } 511 printf("hpecc: flag=%d\n", flag); 512 return (1); 513 } 514 515 /*ARGSUSED*/ 516 hpioctl(io, cmd, arg) 517 struct iob *io; 518 int cmd; 519 caddr_t arg; 520 { 521 register unit = io->i_unit; 522 register struct hp_softc *sc = &hp_softc[io->i_adapt][unit]; 523 register struct disklabel *lp = &hplabel[io->i_adapt][unit]; 524 struct mba_drv *drv = mbadrv(io->i_adapt, unit); 525 526 switch(cmd) { 527 528 case SAIODEBUG: 529 sc->debug = (int)arg; 530 break; 531 532 case SAIODEVDATA: 533 if (drv->mbd_dt&MBDT_TAP) 534 return (ECMD); 535 *(struct disklabel *)arg = *lp; 536 break; 537 538 case SAIOGBADINFO: 539 if (drv->mbd_dt&MBDT_TAP) 540 return (ECMD); 541 *(struct dkbad *)arg = hpbad[io->i_adapt][unit]; 542 break; 543 544 case SAIOECCLIM: 545 sc->ecclim = (int)arg; 546 break; 547 548 case SAIORETRIES: 549 sc->retries = (int)arg; 550 break; 551 552 case SAIOSSI: /* skip-sector-inhibit */ 553 if (drv->mbd_dt&MBDT_TAP) 554 return (ECMD); 555 if ((io->i_flgs&F_SSI) == 0) { 556 /* make sure this is done once only */ 557 io->i_flgs |= F_SSI; 558 lp->d_nsectors++; 559 lp->d_secpercyl += lp->d_ntracks; 560 } 561 break; 562 563 case SAIONOSSI: /* remove skip-sector-inhibit */ 564 if (io->i_flgs & F_SSI) { 565 io->i_flgs &= ~F_SSI; 566 drv->mbd_of &= ~HPOF_SSEI; 567 lp->d_nsectors--; 568 lp->d_secpercyl -= lp->d_ntracks; 569 } 570 break; 571 572 case SAIOSSDEV: /* drive have skip sector? */ 573 return (RM80(sc->type) ? 0 : ECMD); 574 575 default: 576 return (ECMD); 577 } 578 return (0); 579 } 580 #endif /* !SMALL */ 581