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