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