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