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