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