1 /* hp.c 4.14 83/02/17 */ 2 3 /* 4 * RP??/RM?? disk driver 5 * with ECC handling and bad block forwarding. 6 * Also supports header io operations and 7 * commands to write check header and data. 8 */ 9 10 #include "../h/param.h" 11 #include "../h/inode.h" 12 #include "../h/fs.h" 13 #include "../h/dkbad.h" 14 15 #include "../vax/pte.h" 16 #include "../vaxmba/hpreg.h" 17 #include "../vaxmba/mbareg.h" 18 19 #include "saio.h" 20 #include "savax.h" 21 22 #define MASKREG(reg) ((reg)&0xffff) 23 24 #define MAXBADDESC 126 25 #define SECTSIZ 512 /* sector size in bytes */ 26 #define HDRSIZ 4 /* number of bytes in sector header */ 27 #define MAXECC 5 /* the maximum number of bad bits accepted in 28 * an ecc error when F_ECCLM is set */ 29 30 char hp_type[MAXNMBA*8] = { 0 }; 31 32 /* THIS SHOULD BE READ IN OFF THE PACK, PER DRIVE */ 33 short hp6_off[8] = { 0, 38, 0, -1, -1, -1, 118, -1 }; 34 short rm3_off[8] = { 0, 100, 0, -1, -1, -1, 310, -1 }; 35 short rm5_off[8] = { 0, 27, 0, 562, 589, 681, 562, 82 }; 36 short rm80_off[8] = { 0, 37, 0, -1, -1, -1, 115, 305 }; 37 short hp7_off[8] = { 0, 10, 0, 330, 340, 500, 330, 50 }; 38 short ml_off[8] = { 0, -1, -1, -1, -1, -1, -1, -1 }; 39 short si9775_off[8] = { 0, 13, 0, -1, -1, -1, 40, 441 }; 40 short si9730_off[8] = { 0, 50, 0, -1, -1, -1, -1, 155 }; 41 short hpam_off[8] = { 0, 32, 0, 668, 723, 778, 668, 98 }; 42 short hpfj_off[8] = { 0, 19, 0, -1, -1, -1, 398, 59 }; 43 /* END SHOULD BE READ IN */ 44 45 short hptypes[] = { 46 MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, 47 MBDT_RP05, MBDT_RP07, MBDT_ML11A, MBDT_ML11B, 48 -1 /*9755*/, -1 /*9730*/, -1 /*Cap*/, -1 /* Eagle */, 49 -1 /* Eagle */, MBDT_RM02, 0 50 }; 51 52 #define RP06 (hptypes[hp_type[unit]] <= MBDT_RP06) 53 #define ML11 (hptypes[hp_type[unit]] == MBDT_ML11A) 54 #define RM80 (hptypes[hp_type[unit]] == MBDT_RM80) 55 56 u_char hp_offset[16] = { 57 HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 58 HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 59 HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 60 0, 0, 0, 0, 61 }; 62 63 struct st hpst[] = { 64 32, 5, 32*5, 823, rm3_off, /* RM03 */ 65 32, 19, 32*19, 823, rm5_off, /* RM05 */ 66 22, 19, 22*19, 815, hp6_off, /* RP06 */ 67 31, 14, 31*14, 559, rm80_off, /* RM80 */ 68 22, 19, 22*19, 411, hp6_off, /* RP06 */ 69 50, 32, 50*32, 630, hp7_off, /* RP07 */ 70 1, 1, 1, 1, ml_off, /* ML11A */ 71 1, 1, 1, 1, ml_off, /* ML11B */ 72 32, 40, 32*40, 843, si9775_off, /* 9775 */ 73 32, 10, 32*10, 823, si9730_off, /* 9730 */ 74 32, 16, 32*16, 1024, hpam_off, /* capricorn */ 75 43, 20, 43*20, 842, hpfj_off, /* Eagle */ 76 48, 20, 48*20, 842, hpfj_off, /* modif. eagle */ 77 1, 1, 1, 1, 0, /* rm02 - not used */ 78 }; 79 80 struct dkbad hpbad[MAXNMBA*8]; 81 int sectsiz; 82 83 /* 84 * When awaiting command completion, don't 85 * hang on to the status register since 86 * this ties up the controller. 87 */ 88 #define HPWAIT(addr) while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500); 89 90 hpopen(io) 91 register struct iob *io; 92 { 93 register unit = io->i_unit; 94 struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); 95 register struct st *st; 96 97 mbainit(UNITTOMBA(unit)); 98 if (hp_type[unit] == 0) { 99 register type = hpaddr->hpdt & MBDT_TYPE; 100 register int i; 101 struct iob tio; 102 103 for (i = 0; hptypes[i]; i++) 104 if (hptypes[i] == type) 105 goto found; 106 _stop("unknown drive type"); 107 found: 108 hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */ 109 hpaddr->hpcs1 = HP_PRESET|HP_GO; 110 if (!ML11) 111 hpaddr->hpof = HPOF_FMT22; 112 hp_type[unit] = hpmaptype(hpaddr, i, unit); 113 /* 114 * Read in the bad sector table: 115 * copy the contents of the io structure 116 * to tio for use during the bb pointer 117 * read operation. 118 */ 119 st = &hpst[i]; 120 tio = *io; 121 tio.i_bn = st->nspc * st->ncyl - st->nsect; 122 tio.i_ma = (char *)&hpbad[unit]; 123 tio.i_cc = sizeof (struct dkbad); 124 tio.i_flgs |= F_RDDATA; 125 for (i = 0; i < 5; i++) { 126 if (hpstrategy(&tio, READ) == sizeof (struct dkbad)) 127 break; 128 tio.i_bn += 2; 129 } 130 if (i == 5) { 131 printf("Unable to read bad sector table\n"); 132 for (i = 0; i < MAXBADDESC; i++) { 133 hpbad[unit].bt_bad[i].bt_cyl = -1; 134 hpbad[unit].bt_bad[i].bt_trksec = -1; 135 } 136 } 137 } 138 if (io->i_boff < 0 || io->i_boff > 7 || 139 st->off[io->i_boff]== -1) 140 _stop("hp bad minor"); 141 io->i_boff = st->off[io->i_boff] * st->nspc; 142 } 143 144 hpmaptype(hpaddr, type, unit) 145 register struct hpdevice *hpaddr; 146 unsigned type; 147 int unit; 148 { 149 int ntracks, hpsn; 150 151 /* 152 * Handle SI model byte stuff when 153 * we think it's an RM03 or RM05. 154 */ 155 if (type == 0 || type == 1) { 156 hpsn = hpaddr->hpsn; 157 if ((hpsn & SIMB_LU) != unit) 158 return (type); 159 switch ((hpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05)) { 160 case SI9775D: 161 return (8); 162 case SI9730D: 163 return (9); 164 case SI9766: 165 hpaddr->hpcs1 = HP_RECAL|HP_GO; 166 DELAY(100000); 167 return (1); 168 169 case SI9762: 170 return (0); 171 } 172 return (type); 173 } 174 /* 175 * RM03: EMULEX controller. Map to correct 176 * drive type by checking the holding 177 * register for the disk geometry. 178 */ 179 if (type == 13) { 180 hpaddr->hpcs1 = HP_NOP; 181 hpaddr->hphr = HPHR_MAXTRAK; 182 ntracks = MASKREG(hpaddr->hphr) + 1; 183 if (ntracks == 16) 184 return (10); /* AMPEX capricorn */ 185 hpaddr->hphr = HPHR_MAXSECT; 186 ntracks = MASKREG(hpaddr->hphr) + 1; 187 if (ntracks == 48) 188 return (12); /* 48 sector Eagle */ 189 if (ntracks == 43) 190 return (11); /* 43 sector Eagle */ 191 printf("RM02 with %d sectors/track?\n", ntracks); 192 return (type); 193 } 194 /* 195 * ML11's all map to the same type. 196 */ 197 if (type == 6 || type == 7) 198 return (6); 199 return (type); 200 } 201 202 int ssect; /* set to 1 if we are on a track with skip sectors */ 203 204 hpstrategy(io, func) 205 register struct iob *io; 206 { 207 register unit = io->i_unit; 208 struct mba_regs *mba = mbamba(unit); 209 daddr_t bn; 210 struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); 211 struct st *st = &hpst[hp_type[unit]]; 212 int cn, tn, sn, bytecnt, bytesleft; 213 daddr_t startblock; 214 char *membase; 215 int er1, er2, hprecal; 216 217 sectsiz = SECTSIZ; 218 if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) 219 sectsiz += HDRSIZ; 220 if ((hpaddr->hpds & HPDS_VV) == 0) { 221 hpaddr->hpcs1 = HP_DCLR|HP_GO; 222 hpaddr->hpcs1 = HP_PRESET|HP_GO; 223 if (!ML11) 224 hpaddr->hpof = HPOF_FMT22; 225 } 226 io->i_errcnt = 0; 227 ssect = 0; 228 bytecnt = io->i_cc; 229 membase = io->i_ma; 230 startblock = io->i_bn; 231 hprecal = 0; 232 restart: 233 bn = io->i_bn; 234 cn = bn/st->nspc; 235 sn = bn%st->nspc; 236 tn = sn/st->nsect; 237 sn = sn%st->nsect + ssect; 238 239 HPWAIT(hpaddr); 240 mba->mba_sr = -1; 241 if (ML11) 242 hpaddr->hpda = bn; 243 else { 244 hpaddr->hpdc = cn; 245 hpaddr->hpda = (tn << 8) + sn; 246 } 247 if (mbastart(io, func) != 0) /* start transfer */ 248 return (-1); 249 HPWAIT(hpaddr); 250 if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0) 251 return (bytecnt); 252 253 /* ------- error handling ------- */ 254 255 if (bytesleft = MASKREG(mba->mba_bcr>>16)) 256 bytesleft |= 0xffff0000; /* sign ext */ 257 bn = io->i_bn + (io->i_cc + bytesleft)/sectsiz; 258 cn = bn/st->nspc; 259 sn = bn%st->nspc; 260 tn = sn/st->nsect; 261 sn = sn%st->nsect; 262 er1 = MASKREG(hpaddr->hper1); 263 er2 = MASKREG(hpaddr->hper2); 264 #ifdef HPDEBUG 265 printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 266 cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 267 printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 268 printf("\nbytes left: %d, of 0x%x, da 0x%x",-bytesleft, 269 hpaddr->hpof, hpaddr->hpda); 270 printf("\n"); 271 #endif 272 if (er1 & HPER1_HCRC) { 273 er1 &= ~(HPER1_HCE|HPER1_FER); 274 er2 &= ~HPER2_BSE; 275 } 276 if (er1&HPER1_WLE) { 277 printf("hp%d: write locked\n", unit); 278 return (-1); 279 } 280 if (MASKREG(er1) == HPER1_FER && RP06) 281 goto badsect; 282 if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) || 283 (!ML11 && (er2 & HPER2_HARD))) { 284 hard0: 285 io->i_error = EHER; 286 if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) 287 io->i_error = EWCK; 288 hard: 289 io->i_errblk = bn + ssect; 290 printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 291 cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 292 printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 293 if (hpaddr->hpmr) 294 printf(" mr1=%o", MASKREG(hpaddr->hpmr)); 295 if (hpaddr->hpmr2) 296 printf(" mr2=%o", MASKREG(hpaddr->hpmr2)); 297 #ifdef HPDEBUG 298 printf("dc: %d, da: 0x%x",MASKREG(hpaddr->hpdc), 299 MASKREG(hpaddr->hpda)); 300 #endif 301 hpaddr->hpcs1 = HP_DCLR|HP_GO; 302 printf("\n"); 303 return (-1); 304 305 } 306 if ((er2 & HPER2_BSE) && !ML11) { 307 badsect: 308 if (!ssect && (er2&HPER2_SSE)) 309 goto skipsect; 310 if (io->i_flgs & F_NBSF) { 311 io->i_error = EBSE; 312 goto hard; 313 } 314 if (hpecc(io, BSE) == 0) 315 goto success; 316 io->i_error = EBSE; 317 goto hard; 318 } 319 if (RM80 && er2&HPER2_SSE) { 320 skipsect: 321 (void) hpecc(io, SSE); 322 ssect = 1; 323 goto success; 324 } 325 if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { 326 if (hpecc(io, ECC) == 0) 327 goto success; 328 io->i_error = EECC; 329 return (-1); 330 } 331 if (ML11 && (io->i_errcnt >= 16)) 332 goto hard0; 333 /* fall thru to retry */ 334 hpaddr->hpcs1 = HP_DCLR|HP_GO; 335 HPWAIT(hpaddr); 336 if (((io->i_errcnt&07) == 4) ) { 337 hpaddr->hpcs1 = HP_RECAL|HP_GO; 338 hprecal = 1; 339 goto again; 340 } 341 switch (hprecal) { 342 343 case 1: 344 hpaddr->hpdc = cn; 345 hpaddr->hpcs1 = HP_SEEK|HP_GO; 346 hprecal = 2; 347 goto again; 348 349 case 2: 350 if (io->i_errcnt < 16 || (io->i_flgs & F_READ) == 0) 351 goto donerecal; 352 hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; 353 hpaddr->hpcs1 = HP_OFFSET|HP_GO; 354 hprecal = 3; 355 goto again; 356 357 case 3: 358 donerecal: 359 hprecal = 0; 360 goto again; 361 } 362 if (io->i_errcnt >= 16) { 363 hpaddr->hpcs1 = HP_RTC|HP_GO; 364 while (hpaddr->hpds & HPDS_PIP) 365 ; 366 } 367 goto again; 368 369 success: /* continue with the next block */ 370 bn++; 371 if ((bn-startblock) * sectsiz < bytecnt) { 372 again: /* re-read same block */ 373 io->i_bn = bn; 374 io->i_ma = membase + (io->i_bn - startblock)*sectsiz; 375 io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; 376 #ifdef HPDEBUG 377 printf("restart: bl %d, byte %d, mem 0x%x hprecal %d\n", 378 io->i_bn, io->i_cc, io->i_ma, hprecal); 379 #endif 380 goto restart; 381 } 382 return (bytecnt); 383 } 384 385 hpecc(io, flag) 386 register struct iob *io; 387 int flag; 388 { 389 register unit = io->i_unit; 390 register struct mba_regs *mbp = mbamba(unit); 391 register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit); 392 register struct st *st = &hpst[hp_type[unit]]; 393 int npf, bn, cn, tn, sn, bcr; 394 395 if (bcr = MASKREG(mbp->mba_bcr>>16)) 396 bcr |= 0xffff0000; /* sxt */ 397 npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ 398 bn = io->i_bn + npf + ssect; /* physical block #*/ 399 switch (flag) { 400 401 case ECC: { 402 register int i; 403 caddr_t addr; 404 int bit, byte, mask, ecccnt = 0; 405 406 printf("hp%d: soft ecc sn%d\n", unit, bn); 407 mask = MASKREG(rp->hpec2); 408 i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ 409 bit = i&07; 410 i = (i&~07)>>3; 411 byte = i; 412 rp->hpcs1 = HP_DCLR | HP_GO; 413 while (i <sectsiz && npf*sectsiz + i < io->i_cc && bit > -11) { 414 addr = io->i_ma + (npf*sectsiz) + byte; 415 #ifdef HPECCDEBUG 416 printf("addr %x old:%x ",addr, (*addr&0xff)); 417 #endif 418 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) 419 *addr ^= (mask << bit); /* don't 'correct' mem- 420 * ory during Wcheck */ 421 #ifdef HPECCDEBUG 422 printf("new:%x\n",(*addr&0xff)); 423 #endif 424 byte++; 425 i++; 426 bit -= 8; 427 if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC) 428 return (1); 429 } 430 return(0); 431 } 432 433 /* 434 * Skip sector error. 435 * Set skip-sector-inhibit and 436 * read next sector 437 */ 438 case SSE: 439 rp->hpcs1 = HP_DCLR | HP_GO; 440 HPWAIT(rp); 441 rp->hpof |= HPOF_SSEI; 442 return (0); 443 444 case BSE: { 445 int bbn; 446 447 rp->hpcs1 = HP_DCLR | HP_GO; 448 #ifdef HPDEBUG 449 printf("hpecc: BSE @ bn %d\n", bn); 450 #endif 451 cn = bn/st->nspc; 452 sn = bn%st->nspc; 453 tn = sn/st->nsect; 454 sn = sn%st->nsect; 455 bcr += sectsiz; 456 if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0) 457 return (1); 458 bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn; 459 cn = bbn/st->nspc; 460 sn = bbn%st->nspc; 461 tn = sn/st->nsect; 462 sn = sn%st->nsect; 463 io->i_cc = sectsiz; 464 io->i_ma += npf*sectsiz; 465 #ifdef HPDEBUG 466 printf("revector to cn %d tn %d sn %d mem: 0x%x\n", 467 cn, tn, sn, io->i_ma); 468 #endif 469 rp->hpof &= ~HPOF_SSEI; /* clear skip sector inhibit if set */ 470 mbp->mba_sr = -1; 471 rp->hpdc = cn; 472 rp->hpda = (tn<<8) + sn; 473 mbastart(io,io->i_flgs); 474 io->i_errcnt = 0; /* error has been corrected */ 475 HPWAIT(rp); 476 return (rp->hpds&HPDS_ERR); 477 } 478 } 479 printf("hpecc: flag=%d\n", flag); 480 return (1); 481 } 482 /*ARGSUSED*/ 483 hpioctl(io, cmd, arg) 484 struct iob *io; 485 int cmd; 486 caddr_t arg; 487 { 488 register unit = io->i_unit; 489 struct st *st = &hpst[hp_type[unit]], *tmp; 490 struct mba_drv *drv = mbadrv(unit); 491 492 switch(cmd) { 493 494 case SAIODEVDATA: 495 if ((drv->mbd_dt&MBDT_TAP) == 0) { 496 tmp = (struct st *)arg; 497 *tmp = *st; 498 return (0); 499 } 500 return (ECMD); 501 502 case SAIOSSI: /* skip-sector-inhibit */ 503 if (drv->mbd_dt&MBDT_TAP) 504 return (ECMD); 505 if ((io->i_flgs&F_SSI) == 0) { 506 /* make sure this is done once only */ 507 io->i_flgs |= F_SSI; 508 st->nsect++; 509 st->nspc += st->ntrak; 510 } 511 return (0); 512 513 case SAIONOSSI: /* remove skip-sector-inhibit */ 514 if (io->i_flgs & F_SSI) { 515 io->i_flgs &= ~F_SSI; 516 drv->mbd_of &= ~HPOF_SSEI; 517 st->nsect--; 518 st->nspc -= st->ntrak; 519 } 520 return(0); 521 522 case SAIOSSDEV: /* drive have skip sector? */ 523 return (RM80 ? 0 : ECMD); 524 } 525 return (ECMD); 526 } 527