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