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