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.8 (Berkeley) 11/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 RETRIES 27 28 29 #define MASKREG(reg) ((reg)&0xffff) 30 31 #define MAXBADDESC 126 32 #define SECTSIZ 512 /* sector size in bytes */ 33 #define HDRSIZ 4 /* number of bytes in sector header */ 34 35 extern struct st hpst[]; 36 extern short hptypes[]; 37 38 #define RP06 (hptypes[sc->type] == MBDT_RP06 || hptypes[sc->type] == MBDT_RP05 \ 39 || hptypes[sc->type] == MBDT_RP04) 40 #define ML11 (hptypes[sc->type] == MBDT_ML11A) 41 #define RM80 (hptypes[sc->type] == 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 52 struct hp_softc { 53 char type; 54 char gottype; 55 char ssect; /* 1 when on track w/skip sector */ 56 char debug; 57 # define HPF_BSEDEBUG 01 /* debugging bad sector forwarding */ 58 # define HPF_ECCDEBUG 02 /* debugging ecc correction */ 59 int ecclim; 60 int retries; 61 } hp_softc[MAXNMBA * 8]; 62 63 int sectsiz; 64 65 /* 66 * When awaiting command completion, don't 67 * hang on to the status register since 68 * this ties up some controllers. 69 */ 70 #define HPWAIT(addr) \ 71 while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500); 72 73 hpopen(io) 74 register struct iob *io; 75 { 76 register unit = io->i_unit; 77 struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); 78 register struct st *st; 79 register struct hp_softc *sc = &hp_softc[unit]; 80 81 mbainit(UNITTOMBA(unit)); 82 if (sc->gottype == 0) { 83 register i, type = hpaddr->hpdt & MBDT_TYPE; 84 struct iob tio; 85 86 for (i = 0; hptypes[i]; i++) 87 if (hptypes[i] == type) 88 goto found; 89 _stop("unknown drive type"); 90 found: 91 sc->retries = RETRIES; 92 sc->ecclim = 11; 93 sc->debug = 0; 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 sc->type = hpmaptype(hpaddr, i, UNITTODRIVE(unit)); 99 /* 100 * Read in the bad sector table. 101 */ 102 st = &hpst[sc->type]; 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 sc->gottype = 1; 121 } 122 st = &hpst[sc->type]; 123 if (io->i_boff < 0 || io->i_boff > 7 || 124 st->off[io->i_boff]== -1) 125 _stop("hp bad minor"); 126 io->i_boff = st->off[io->i_boff] * st->nspc; 127 } 128 129 hpstrategy(io, func) 130 register struct iob *io; 131 { 132 register unit = io->i_unit; 133 struct mba_regs *mba = mbamba(unit); 134 daddr_t bn, startblock; 135 struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); 136 register struct hp_softc *sc = &hp_softc[unit]; 137 struct st *st = &hpst[sc->type]; 138 int cn, tn, sn, bytecnt, bytesleft, rv; 139 char *membase; 140 int er1, er2, hprecal; 141 142 sectsiz = SECTSIZ; 143 if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) 144 sectsiz += HDRSIZ; 145 if ((hpaddr->hpds & HPDS_VV) == 0) { 146 hpaddr->hpcs1 = HP_DCLR|HP_GO; 147 hpaddr->hpcs1 = HP_PRESET|HP_GO; 148 if (!ML11) 149 hpaddr->hpof = HPOF_FMT22; 150 } 151 io->i_errcnt = 0; 152 sc->ssect = 0; 153 rv = bytecnt = io->i_cc; 154 membase = io->i_ma; 155 startblock = io->i_bn; 156 hprecal = 0; 157 158 restart: 159 bn = io->i_bn; 160 cn = bn/st->nspc; 161 sn = bn%st->nspc; 162 tn = sn/st->nsect; 163 sn = sn%st->nsect + sc->ssect; 164 165 HPWAIT(hpaddr); 166 mba->mba_sr = -1; 167 if (ML11) 168 hpaddr->hpda = bn; 169 else { 170 hpaddr->hpdc = cn; 171 hpaddr->hpda = (tn << 8) + sn; 172 } 173 if (mbastart(io, func) != 0) { /* start transfer */ 174 rv = -1; 175 goto done; 176 } 177 HPWAIT(hpaddr); 178 /* 179 * Successful data transfer, return. 180 */ 181 if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0) 182 goto done; 183 184 /* 185 * Error handling. Calculate location of error. 186 */ 187 bytesleft = MASKREG(mba->mba_bcr); 188 if (bytesleft) 189 bytesleft |= 0xffff0000; /* sxt */ 190 bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz; 191 er1 = MASKREG(hpaddr->hper1); 192 er2 = MASKREG(hpaddr->hper2); 193 if (er1 & (HPER1_DCK|HPER1_ECH)) 194 bn--; /* Error is in Prev block */ 195 cn = bn/st->nspc; 196 sn = bn%st->nspc; 197 tn = sn/st->nsect; 198 sn = sn%st->nsect; 199 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) { 200 printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b\n", 201 bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 202 printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS); 203 printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft, 204 hpaddr->hpof, hpaddr->hpda); 205 } 206 if (er1 & HPER1_HCRC) { 207 er1 &= ~(HPER1_HCE|HPER1_FER); 208 er2 &= ~HPER2_BSE; 209 if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0) 210 goto success; 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 rv = -1; 218 goto done; 219 } 220 /* 221 * Skip sector handling. 222 */ 223 if (RM80 && (er2 & HPER2_SSE)) { 224 (void) hpecc(io, SSE); 225 sc->ssect = 1; 226 goto restart; 227 } 228 /* 229 * Attempt to forward bad sectors on anything but an ML11. 230 * Interpret format error bit as a bad block on RP06's. 231 */ 232 if (((er2 & HPER2_BSE) && !ML11) || 233 (MASKREG(er1) == HPER1_FER && RP06)) { 234 if (io->i_flgs & F_NBSF) { 235 io->i_error = EBSE; 236 goto hard; 237 } 238 if (hpecc(io, BSE) == 0) 239 goto success; 240 io->i_error = EBSE; 241 goto hard; 242 } 243 /* 244 * ECC correction? 245 */ 246 if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { 247 if (hpecc(io, ECC) == 0) 248 goto success; 249 io->i_error = EECC; 250 goto hard; 251 } 252 253 /* 254 * If a hard error, or maximum retry count 255 * exceeded, clear controller state and 256 * pass back error to caller. 257 */ 258 if (++io->i_errcnt > sc->retries || (er1 & HPER1_HARD) || 259 (!ML11 && (er2 & HPER2_HARD)) || (ML11 && (io->i_errcnt >= 16))) { 260 io->i_error = EHER; 261 if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) 262 io->i_error = EWCK; 263 hard: 264 io->i_errblk = bn + sc->ssect; 265 if (sc->debug & (HPF_BSEDEBUG|HPF_ECCDEBUG)) 266 printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc), 267 MASKREG(hpaddr->hpda)); 268 else { 269 printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 270 bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 271 printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 272 } 273 hpaddr->hpcs1 = HP_DCLR|HP_GO; 274 printf("\n"); 275 rv = -1; 276 goto done; 277 278 } 279 /* fall thru to retry */ 280 hpaddr->hpcs1 = HP_DCLR|HP_GO; 281 HPWAIT(hpaddr); 282 283 /* 284 * Every fourth retry recalibrate. 285 */ 286 if (((io->i_errcnt & 07) == 4) ) { 287 hpaddr->hpcs1 = HP_RECAL|HP_GO; 288 HPWAIT(hpaddr); 289 hpaddr->hpdc = cn; 290 hpaddr->hpcs1 = HP_SEEK|HP_GO; 291 HPWAIT(hpaddr); 292 } 293 294 if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) { 295 hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; 296 hpaddr->hpcs1 = HP_OFFSET|HP_GO; 297 HPWAIT(hpaddr); 298 } 299 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) 300 printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", 301 io->i_bn, io->i_cc, io->i_ma, hprecal); 302 goto restart; 303 304 success: 305 /* 306 * On successful error recovery, bump 307 * block number to advance to next portion 308 * of i/o transfer. 309 */ 310 bn++; 311 if ((bn-startblock) * sectsiz < bytecnt) { 312 io->i_bn = bn; 313 io->i_ma = membase + (io->i_bn - startblock)*sectsiz; 314 io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; 315 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) 316 printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", 317 io->i_bn, io->i_cc, io->i_ma, hprecal); 318 goto restart; 319 } 320 done: 321 if (io->i_errcnt >= 16) { 322 hpaddr->hpcs1 = HP_RTC|HP_GO; 323 while (hpaddr->hpds & HPDS_PIP) 324 ; 325 } 326 io->i_bn = startblock; /*reset i_bn to original */ 327 io->i_cc = bytecnt; /*reset i_cc to total count xfered*/ 328 io->i_ma = membase; /*reset i_ma to original */ 329 return (rv); 330 } 331 332 hpecc(io, flag) 333 register struct iob *io; 334 int flag; 335 { 336 register unit = io->i_unit; 337 register struct mba_regs *mbp = mbamba(unit); 338 register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit); 339 register struct hp_softc *sc = &hp_softc[unit]; 340 register struct st *st = &hpst[sc->type]; 341 int npf, bn, cn, tn, sn, bcr; 342 343 bcr = MASKREG(mbp->mba_bcr); 344 if (bcr) 345 bcr |= 0xffff0000; /* sxt */ 346 npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ 347 if (flag == ECC) 348 npf--; /* Error is in prev block --ghg */ 349 bn = io->i_bn + npf + sc->ssect; /* physical block #*/ 350 if (sc->debug & HPF_ECCDEBUG) 351 printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n", 352 bcr, npf, sc->ssect, sectsiz, io->i_cc); 353 /* 354 * ECC correction logic. 355 */ 356 if (flag == ECC) { 357 register int i; 358 caddr_t addr; 359 int bit, o, mask; 360 361 printf("hp%d: soft ecc sn%d\n", unit, bn); 362 mask = MASKREG(rp->hpec2); 363 for (i = mask, bit = 0; i; i >>= 1) 364 if (i & 1) 365 bit++; 366 if (bit > sc->ecclim) { 367 printf("%d-bit error\n", bit); 368 return (1); 369 } 370 i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ 371 bit = i&07; 372 o = (i & ~07) >> 3; 373 rp->hpcs1 = HP_DCLR | HP_GO; 374 while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) { 375 addr = io->i_ma + (npf*sectsiz) + o; 376 /* 377 * No data transfer occurs with a write check, 378 * so don't correct the resident copy of data. 379 */ 380 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { 381 if (sc->debug & HPF_ECCDEBUG) 382 printf("addr=%x old=%x ", addr, 383 (*addr & 0xff)); 384 *addr ^= (mask << bit); 385 if (sc->debug & HPF_ECCDEBUG) 386 printf("new=%x\n",(*addr & 0xff)); 387 } 388 o++, bit -= 8; 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 if (sc->debug & HPF_BSEDEBUG) 413 printf("hpecc: BSE @ bn %d\n", bn); 414 cn = bn/st->nspc; 415 sn = bn%st->nspc; 416 tn = sn/st->nsect; 417 sn = sn%st->nsect; 418 bcr += sectsiz; 419 if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0) 420 return (1); 421 bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn; 422 cn = bbn/st->nspc; 423 sn = bbn%st->nspc; 424 tn = sn/st->nsect; 425 sn = sn%st->nsect; 426 io->i_cc = sectsiz; 427 io->i_ma += npf*sectsiz; 428 if (sc->debug & HPF_BSEDEBUG) 429 printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 430 rp->hpof &= ~HPOF_SSEI; 431 mbp->mba_sr = -1; 432 rp->hpdc = cn; 433 rp->hpda = (tn<<8) + sn; 434 mbastart(io,io->i_flgs); 435 io->i_errcnt = 0; 436 HPWAIT(rp); 437 return (rp->hpds&HPDS_ERR); 438 } 439 printf("hpecc: flag=%d\n", flag); 440 return (1); 441 } 442 443 /*ARGSUSED*/ 444 hpioctl(io, cmd, arg) 445 struct iob *io; 446 int cmd; 447 caddr_t arg; 448 { 449 register unit = io->i_unit; 450 register struct hp_softc *sc = &hp_softc[unit]; 451 struct st *st = &hpst[sc->type]; 452 struct mba_drv *drv = mbadrv(unit); 453 454 switch(cmd) { 455 456 case SAIODEBUG: 457 sc->debug = (int)arg; 458 break; 459 460 case SAIODEVDATA: 461 if (drv->mbd_dt&MBDT_TAP) 462 return (ECMD); 463 *(struct st *)arg = *st; 464 break; 465 466 case SAIOGBADINFO: 467 if (drv->mbd_dt&MBDT_TAP) 468 return (ECMD); 469 *(struct dkbad *)arg = hpbad[unit]; 470 break; 471 472 case SAIOECCLIM: 473 sc->ecclim = (int)arg; 474 break; 475 476 case SAIORETRIES: 477 sc->retries = (int)arg; 478 break; 479 480 case SAIOSSI: /* skip-sector-inhibit */ 481 if (drv->mbd_dt&MBDT_TAP) 482 return (ECMD); 483 if ((io->i_flgs&F_SSI) == 0) { 484 /* make sure this is done once only */ 485 io->i_flgs |= F_SSI; 486 st->nsect++; 487 st->nspc += st->ntrak; 488 } 489 break; 490 491 case SAIONOSSI: /* remove skip-sector-inhibit */ 492 if (io->i_flgs & F_SSI) { 493 io->i_flgs &= ~F_SSI; 494 drv->mbd_of &= ~HPOF_SSEI; 495 st->nsect--; 496 st->nspc -= st->ntrak; 497 } 498 break; 499 500 case SAIOSSDEV: /* drive have skip sector? */ 501 return (RM80 ? 0 : ECMD); 502 503 default: 504 return (ECMD); 505 } 506 return (0); 507 } 508