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