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