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