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