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