1 /* hp.c 4.15 83/02/18 */ 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 hard0: 210 io->i_error = EHER; 211 if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) 212 io->i_error = EWCK; 213 hard: 214 io->i_errblk = bn + ssect; 215 printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 216 cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 217 printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 218 if (hpaddr->hpmr) 219 printf(" mr1=%o", MASKREG(hpaddr->hpmr)); 220 if (hpaddr->hpmr2) 221 printf(" mr2=%o", MASKREG(hpaddr->hpmr2)); 222 #ifdef HPDEBUG 223 printf("dc: %d, da: 0x%x",MASKREG(hpaddr->hpdc), 224 MASKREG(hpaddr->hpda)); 225 #endif 226 hpaddr->hpcs1 = HP_DCLR|HP_GO; 227 printf("\n"); 228 return (-1); 229 230 } 231 /* 232 * Attempt to forward bad sectors on 233 * anything but an ML11. If drive 234 * supports skip sector handling, try to 235 * use it first; otherwise try the 236 * bad sector table. 237 */ 238 if ((er2 & HPER2_BSE) && !ML11) { 239 badsect: 240 if (!ssect && (er2&HPER2_SSE)) 241 goto skipsect; 242 if (io->i_flgs & F_NBSF) { 243 io->i_error = EBSE; 244 goto hard; 245 } 246 if (hpecc(io, BSE) == 0) 247 goto success; 248 io->i_error = EBSE; 249 goto hard; 250 } 251 252 /* 253 * Skip sector handling. 254 */ 255 if (RM80 && er2&HPER2_SSE) { 256 skipsect: 257 (void) hpecc(io, SSE); 258 ssect = 1; 259 goto success; 260 } 261 /* 262 * ECC correction. 263 */ 264 if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { 265 if (hpecc(io, ECC) == 0) 266 goto success; 267 io->i_error = EECC; 268 return (-1); 269 } 270 if (ML11 && (io->i_errcnt >= 16)) 271 goto hard0; 272 /* fall thru to retry */ 273 hpaddr->hpcs1 = HP_DCLR|HP_GO; 274 HPWAIT(hpaddr); 275 276 /* 277 * Every fourth retry recalibrate. 278 */ 279 if (((io->i_errcnt&07) == 4) ) { 280 hpaddr->hpcs1 = HP_RECAL|HP_GO; 281 hprecal = 1; 282 goto again; 283 } 284 285 /* 286 * Recalibration state machine. 287 */ 288 switch (hprecal) { 289 290 case 1: 291 hpaddr->hpdc = cn; 292 hpaddr->hpcs1 = HP_SEEK|HP_GO; 293 hprecal = 2; 294 goto again; 295 296 case 2: 297 if (io->i_errcnt < 16 || (io->i_flgs & F_READ) == 0) 298 goto donerecal; 299 hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; 300 hpaddr->hpcs1 = HP_OFFSET|HP_GO; 301 hprecal = 3; 302 goto again; 303 304 case 3: 305 donerecal: 306 hprecal = 0; 307 goto again; 308 } 309 if (io->i_errcnt >= 16) { 310 hpaddr->hpcs1 = HP_RTC|HP_GO; 311 while (hpaddr->hpds & HPDS_PIP) 312 ; 313 } 314 goto again; 315 316 success: 317 /* 318 * On successful error recovery, bump 319 * block number to advance to next portion 320 * of i/o transfer. 321 */ 322 bn++; 323 if ((bn-startblock) * sectsiz < bytecnt) { 324 again: 325 io->i_bn = bn; 326 io->i_ma = membase + (io->i_bn - startblock)*sectsiz; 327 io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; 328 #ifdef HPDEBUG 329 printf("restart: bl %d, byte %d, mem 0x%x hprecal %d\n", 330 io->i_bn, io->i_cc, io->i_ma, hprecal); 331 #endif 332 goto restart; 333 } 334 return (bytecnt); 335 } 336 337 hpecc(io, flag) 338 register struct iob *io; 339 int flag; 340 { 341 register unit = io->i_unit; 342 register struct mba_regs *mbp = mbamba(unit); 343 register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit); 344 register struct st *st = &hpst[hp_type[unit]]; 345 int npf, bn, cn, tn, sn, bcr; 346 347 if (bcr = MASKREG(mbp->mba_bcr>>16)) 348 bcr |= 0xffff0000; /* sxt */ 349 npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ 350 bn = io->i_bn + npf + ssect; /* physical block #*/ 351 352 /* 353 * ECC correction logic. 354 */ 355 if (flag == ECC) { 356 register int i; 357 caddr_t addr; 358 int bit, byte, mask, ecccnt = 0; 359 360 printf("hp%d: soft ecc sn%d\n", unit, bn); 361 mask = MASKREG(rp->hpec2); 362 i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ 363 bit = i&07; 364 i = (i&~07)>>3; 365 byte = i; 366 rp->hpcs1 = HP_DCLR | HP_GO; 367 while (i <sectsiz && npf*sectsiz + i < io->i_cc && bit > -11) { 368 addr = io->i_ma + (npf*sectsiz) + byte; 369 #ifdef HPECCDEBUG 370 printf("addr %x old:%x ",addr, (*addr&0xff)); 371 #endif 372 /* don't correct in-core copy during wcheck */ 373 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) 374 *addr ^= (mask << bit); 375 #ifdef HPECCDEBUG 376 printf("new:%x\n",(*addr&0xff)); 377 #endif 378 byte++, i++; 379 bit -= 8; 380 if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC) 381 return (1); 382 } 383 return(0); 384 } 385 386 /* 387 * Skip sector error. 388 * Set skip-sector-inhibit and 389 * read next sector 390 */ 391 if (flag == SSE) { 392 rp->hpcs1 = HP_DCLR | HP_GO; 393 HPWAIT(rp); 394 rp->hpof |= HPOF_SSEI; 395 return (0); 396 } 397 398 /* 399 * Bad block forwarding. 400 */ 401 if (flag == BSE) { 402 int bbn; 403 404 rp->hpcs1 = HP_DCLR | HP_GO; 405 #ifdef HPDEBUG 406 printf("hpecc: BSE @ bn %d\n", bn); 407 #endif 408 cn = bn/st->nspc; 409 sn = bn%st->nspc; 410 tn = sn/st->nsect; 411 sn = sn%st->nsect; 412 bcr += sectsiz; 413 if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0) 414 return (1); 415 bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn; 416 cn = bbn/st->nspc; 417 sn = bbn%st->nspc; 418 tn = sn/st->nsect; 419 sn = sn%st->nsect; 420 io->i_cc = sectsiz; 421 io->i_ma += npf*sectsiz; 422 #ifdef HPDEBUG 423 printf("revector to cn %d tn %d sn %d mem: 0x%x\n", 424 cn, tn, sn, io->i_ma); 425 #endif 426 rp->hpof &= ~HPOF_SSEI; /* clear skip sector inhibit if set */ 427 mbp->mba_sr = -1; 428 rp->hpdc = cn; 429 rp->hpda = (tn<<8) + sn; 430 mbastart(io,io->i_flgs); 431 io->i_errcnt = 0; /* error has been corrected */ 432 HPWAIT(rp); 433 return (rp->hpds&HPDS_ERR); 434 } 435 printf("hpecc: flag=%d\n", flag); 436 return (1); 437 } 438 439 /*ARGSUSED*/ 440 hpioctl(io, cmd, arg) 441 struct iob *io; 442 int cmd; 443 caddr_t arg; 444 { 445 register unit = io->i_unit; 446 struct st *st = &hpst[hp_type[unit]], *tmp; 447 struct mba_drv *drv = mbadrv(unit); 448 449 switch(cmd) { 450 451 case SAIODEVDATA: 452 if ((drv->mbd_dt&MBDT_TAP) == 0) { 453 tmp = (struct st *)arg; 454 *tmp = *st; 455 return (0); 456 } 457 return (ECMD); 458 459 case SAIOSSI: /* skip-sector-inhibit */ 460 if (drv->mbd_dt&MBDT_TAP) 461 return (ECMD); 462 if ((io->i_flgs&F_SSI) == 0) { 463 /* make sure this is done once only */ 464 io->i_flgs |= F_SSI; 465 st->nsect++; 466 st->nspc += st->ntrak; 467 } 468 return (0); 469 470 case SAIONOSSI: /* remove skip-sector-inhibit */ 471 if (io->i_flgs & F_SSI) { 472 io->i_flgs &= ~F_SSI; 473 drv->mbd_of &= ~HPOF_SSEI; 474 st->nsect--; 475 st->nspc -= st->ntrak; 476 } 477 return(0); 478 479 case SAIOSSDEV: /* drive have skip sector? */ 480 return (RM80 ? 0 : ECMD); 481 } 482 return (ECMD); 483 } 484