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