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