1*9974Ssam /* up.c 4.1 82/12/26 */ 2*9974Ssam 3*9974Ssam #include "../h/param.h" 4*9974Ssam #include "../h/inode.h" 5*9974Ssam #include "../h/fs.h" 6*9974Ssam #include "../h/dkbad.h" 7*9974Ssam #include "../h/vmmac.h" 8*9974Ssam 9*9974Ssam #include "../vax/pte.h" 10*9974Ssam #include "../vaxuba/upreg.h" 11*9974Ssam #include "../vaxuba/ubareg.h" 12*9974Ssam 13*9974Ssam #include "nsaio.h" 14*9974Ssam #include "savax.h" 15*9974Ssam 16*9974Ssam #define updevctl(io, func) (up_ctl[io->i_unit] = func) 17*9974Ssam 18*9974Ssam struct dkbad upbad[MAXNUBA*8]; /* bad block pointers */ 19*9974Ssam u_short ubastd[] = { 0776700 }; 20*9974Ssam char up_gottype[MAXNUBA*8] = { 0 }; 21*9974Ssam char up_type[MAXNUBA*8] = { 0 }; 22*9974Ssam char up_ctl[MAXNUBA*8] = { 0 }; 23*9974Ssam short up_off[] = { 0, 27, 68, -1, -1, -1, -1, 82 }; 24*9974Ssam short fj_off[] = { 0, 50, 0, -1, -1, -1, -1, 155 }; 25*9974Ssam /* this is called upam instead of am because hp.c has a similar array */ 26*9974Ssam short upam_off[] = { 0, 32, 0, 668, 723, 778, 668, 98 }; 27*9974Ssam struct upst { 28*9974Ssam short nsect; 29*9974Ssam short ntrak; 30*9974Ssam short nspc; 31*9974Ssam short ncyl; 32*9974Ssam short *off; 33*9974Ssam } upst[] = { 34*9974Ssam /* sectors, surfaces,sect/cyl,cylind, */ 35*9974Ssam 32, 19, 32*19, 823, up_off, 36*9974Ssam 32, 10, 32*10, 823, fj_off, 37*9974Ssam 32, 16, 32*16, 1024, upam_off, 38*9974Ssam }; 39*9974Ssam u_char up_offset[16] = { 40*9974Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 41*9974Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 42*9974Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 43*9974Ssam 0, 0, 0, 0 44*9974Ssam }; 45*9974Ssam 46*9974Ssam upopen(io) 47*9974Ssam register struct iob *io; 48*9974Ssam { 49*9974Ssam register struct updevice *upaddr = 50*9974Ssam (struct updevice *)ubamem(io->i_unit, ubastd[0]); 51*9974Ssam register struct upst *st; 52*9974Ssam struct iob tio; 53*9974Ssam int i = 0; 54*9974Ssam 55*9974Ssam while ((upaddr->upcs1 & UP_DVA) == 0) /* infinite wait */ 56*9974Ssam ; 57*9974Ssam st = &upst[up_type[io->i_unit]]; 58*9974Ssam if (up_gottype[io->i_unit] == 0) { 59*9974Ssam upaddr->uphr = UPHR_MAXTRAK; 60*9974Ssam if (upaddr->uphr == 9) 61*9974Ssam up_type[io->i_unit] = 1; /* fuji kludge */ 62*9974Ssam else if (upaddr->uphr == 15) 63*9974Ssam up_type[io->i_unit] = 2; /* capricorn kludge */ 64*9974Ssam upaddr->upcs2 = UPCS2_CLR; 65*9974Ssam #ifdef DEBUG 66*9974Ssam printf("Unittype=%d\n",up_type[io->i_unit]); 67*9974Ssam #endif 68*9974Ssam st = &upst[up_type[io->i_unit]]; 69*9974Ssam 70*9974Ssam /* read in bad block ptrs */ 71*9974Ssam tio = *io; /* copy the contents of the io structure 72*9974Ssam * to tio for use during the bb pointer 73*9974Ssam * read operation */ 74*9974Ssam tio.i_bn = (st->nspc * st->ncyl - st->nsect); 75*9974Ssam tio.i_ma = (char *)&upbad[tio.i_unit]; 76*9974Ssam tio.i_cc = sizeof(upbad); 77*9974Ssam for (i=0; i<5; i++) { 78*9974Ssam if (upstrategy(&tio, READ) == sizeof(upbad)) break; 79*9974Ssam tio.i_bn += 2; 80*9974Ssam } 81*9974Ssam if (i == 5) { 82*9974Ssam printf("Unable to read bad block ptrs\n"); 83*9974Ssam for (i=0; i<126; i++) { 84*9974Ssam upbad[io->i_unit].bt_bad[i].bt_cyl = -1; 85*9974Ssam upbad[io->i_unit].bt_bad[i].bt_trksec = -1; 86*9974Ssam } 87*9974Ssam } 88*9974Ssam up_gottype[io->i_unit] = 1; 89*9974Ssam } 90*9974Ssam if (io->i_boff < 0 || io->i_boff > 7 || st->off[io->i_boff] == -1) 91*9974Ssam _stop("up bad unit"); 92*9974Ssam io->i_boff = st->off[io->i_boff] * st->nspc; 93*9974Ssam updevctl(io, NORMAL); 94*9974Ssam } 95*9974Ssam 96*9974Ssam upstrategy(io, func) 97*9974Ssam register struct iob *io; 98*9974Ssam { 99*9974Ssam int unit, cn, tn, sn; 100*9974Ssam daddr_t bn; 101*9974Ssam int recal, info, waitdry; 102*9974Ssam register struct updevice *upaddr = 103*9974Ssam (struct updevice *)ubamem(io->i_unit, ubastd[0]); 104*9974Ssam register struct upst *st = &upst[up_type[io->i_unit]]; 105*9974Ssam 106*9974Ssam if (func == READ) 107*9974Ssam io->i_flgs |= IO_READ; 108*9974Ssam else 109*9974Ssam io->i_flgs |= IO_WRITE; 110*9974Ssam unit = io->i_unit; 111*9974Ssam io->i_errcnt = 0; 112*9974Ssam recal = 3; 113*9974Ssam upaddr->upcs2 = unit; 114*9974Ssam if ((upaddr->upds & UPDS_VV) == 0) { 115*9974Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 116*9974Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 117*9974Ssam upaddr->upof = UPOF_FMT22; 118*9974Ssam } 119*9974Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 120*9974Ssam _stop("up not ready"); 121*9974Ssam info = ubasetup(io, 1); 122*9974Ssam upaddr->upwc = -io->i_cc / sizeof (short); 123*9974Ssam upaddr->upba = info; 124*9974Ssam readmore: 125*9974Ssam bn = io->i_bn + btop(io->i_cc + upaddr->upwc*sizeof(short)); 126*9974Ssam while((upaddr->upds & UPDS_DRY) == 0) ; 127*9974Ssam if (upstart(io, bn) != 0) 128*9974Ssam return (-1); 129*9974Ssam do { 130*9974Ssam DELAY(25); 131*9974Ssam } while ((upaddr->upcs1 & UP_RDY) == 0); 132*9974Ssam 133*9974Ssam if (((upaddr->upds&UPDS_ERR) | (upaddr->upcs1&UP_TRE)) == 0 ) 134*9974Ssam return(io->i_cc); 135*9974Ssam 136*9974Ssam #ifdef LOGALLERRS 137*9974Ssam printf("uper: (c,t,s)=(%d,%d,%d) cs2=%b er1=%b er2=%b wc=%x\n", 138*9974Ssam upaddr->updc, upaddr->upda>>8, (upaddr->upda&0x1f-1), 139*9974Ssam upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 140*9974Ssam UPER1_BITS, upaddr->uper2, UPER2_BITS,-upaddr->upwc); 141*9974Ssam #endif 142*9974Ssam waitdry = 0; 143*9974Ssam while ((upaddr->upds & UPDS_DRY) == 0) { 144*9974Ssam if (++waitdry > 512) 145*9974Ssam break; 146*9974Ssam } 147*9974Ssam if (++io->i_errcnt > 27) { 148*9974Ssam /* 149*9974Ssam * After 28 retries (16 without offset, and 150*9974Ssam * 12 with offset positioning) give up. 151*9974Ssam */ 152*9974Ssam io->i_error = IOERR_HER; 153*9974Ssam hard: 154*9974Ssam if (upaddr->upcs2 & UPCS2_WCE) io->i_error=IOERR_WCK; 155*9974Ssam bn = io->i_bn + btop(io->i_cc + upaddr->upwc*sizeof(short)); 156*9974Ssam cn = bn/st->nspc; 157*9974Ssam sn = bn%st->nspc; 158*9974Ssam tn = sn/st->nsect; 159*9974Ssam sn = sn%st->nsect; 160*9974Ssam printf("up error: (cyl,trk,sec)=(%d,%d,%d) cs2=%b er1=%b er2=%b\n", 161*9974Ssam cn, tn, sn, 162*9974Ssam upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 163*9974Ssam UPER1_BITS, upaddr->uper2, UPER2_BITS); 164*9974Ssam upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 165*9974Ssam return (io->i_cc + upaddr->upwc*sizeof(short)); 166*9974Ssam } else 167*9974Ssam if (upaddr->uper1&UPER1_WLE) { 168*9974Ssam /* 169*9974Ssam * Give up on write locked devices 170*9974Ssam * immediately. 171*9974Ssam */ 172*9974Ssam printf("up%d: write locked\n", unit); 173*9974Ssam return(-1); 174*9974Ssam } 175*9974Ssam #ifndef NOBADSECT 176*9974Ssam else if (upaddr->uper2 & UPER2_BSE) { 177*9974Ssam if (upecc( io, BSE)) 178*9974Ssam goto success; 179*9974Ssam else { 180*9974Ssam io->i_error = IOERR_BSE; 181*9974Ssam goto hard; 182*9974Ssam } 183*9974Ssam } 184*9974Ssam #endif 185*9974Ssam else { 186*9974Ssam /* 187*9974Ssam * Retriable error. 188*9974Ssam * If a soft ecc, correct it 189*9974Ssam * Otherwise fall through and retry the transfer 190*9974Ssam */ 191*9974Ssam if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 192*9974Ssam upecc( io, ECC); 193*9974Ssam goto success; 194*9974Ssam } else { 195*9974Ssam io->i_active = 0; /* force retry */ 196*9974Ssam } 197*9974Ssam } 198*9974Ssam /* 199*9974Ssam * Clear drive error and, every eight attempts, 200*9974Ssam * (starting with the fourth) 201*9974Ssam * recalibrate to clear the slate. 202*9974Ssam */ 203*9974Ssam upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 204*9974Ssam if ((io->i_errcnt&07) == 4 && io->i_active == 0) { 205*9974Ssam upaddr->upcs1 = UP_RECAL|UP_GO; 206*9974Ssam recal = 0; 207*9974Ssam goto nextrecal; 208*9974Ssam } 209*9974Ssam /* 210*9974Ssam * Advance recalibration finite state machine 211*9974Ssam * if recalibrate in progress, through 212*9974Ssam * RECAL 213*9974Ssam * SEEK 214*9974Ssam * OFFSET (optional) 215*9974Ssam * RETRY 216*9974Ssam */ 217*9974Ssam switch (recal) { 218*9974Ssam 219*9974Ssam case 1: 220*9974Ssam upaddr->updc = cn; 221*9974Ssam upaddr->upcs1 = UP_SEEK|UP_GO; 222*9974Ssam goto nextrecal; 223*9974Ssam case 2: 224*9974Ssam if (io->i_errcnt < 16 || (func & READ) == 0) 225*9974Ssam goto donerecal; 226*9974Ssam upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22; 227*9974Ssam upaddr->upcs1 = UP_OFFSET|UP_GO; 228*9974Ssam nextrecal: 229*9974Ssam recal++; 230*9974Ssam io->i_active = 1; 231*9974Ssam goto readmore; 232*9974Ssam donerecal: 233*9974Ssam case 3: 234*9974Ssam recal = 0; 235*9974Ssam io->i_active = 0; 236*9974Ssam break; 237*9974Ssam } 238*9974Ssam /* 239*9974Ssam * If still ``active'', then don't need any more retries. 240*9974Ssam */ 241*9974Ssam if (io->i_active) { 242*9974Ssam /* 243*9974Ssam * If we were offset positioning, 244*9974Ssam * return to centerline. 245*9974Ssam */ 246*9974Ssam if (io->i_errcnt >= 16) { 247*9974Ssam upaddr->upof = UPOF_FMT22; 248*9974Ssam upaddr->upcs1 = UP_RTC|UP_GO; 249*9974Ssam while (!upaddr->upds & UPDS_DRY) /* removed PIP test*/ 250*9974Ssam DELAY(25); 251*9974Ssam } 252*9974Ssam goto readmore; 253*9974Ssam } 254*9974Ssam success: 255*9974Ssam io->i_active = 1; 256*9974Ssam if (upaddr->upwc != 0) { 257*9974Ssam goto readmore; 258*9974Ssam } 259*9974Ssam /* 260*9974Ssam * Release unibus 261*9974Ssam */ 262*9974Ssam ubafree(io, info); 263*9974Ssam return (io->i_cc); 264*9974Ssam } 265*9974Ssam 266*9974Ssam /* 267*9974Ssam * Correct an ECC error, and restart the i/o to complete 268*9974Ssam * the transfer if necessary. This is quite complicated because 269*9974Ssam * the transfer may be going to an odd memory address base and/or 270*9974Ssam * across a page boundary. 271*9974Ssam */ 272*9974Ssam upecc( io, flag) 273*9974Ssam register struct iob *io; 274*9974Ssam int flag; 275*9974Ssam { 276*9974Ssam register struct updevice *up = 277*9974Ssam (struct updevice *)ubamem(io->i_unit, ubastd[0]); 278*9974Ssam register struct upst *st; 279*9974Ssam register int i; 280*9974Ssam caddr_t addr; 281*9974Ssam int bit, byte, npf, mask; 282*9974Ssam int bn, twc, bbn; 283*9974Ssam 284*9974Ssam /* 285*9974Ssam * Npf is the number of sectors transferred before the sector 286*9974Ssam * containing the ECC error, bn is the current block number 287*9974Ssam */ 288*9974Ssam npf = btop((up->upwc * sizeof(short)) + io->i_cc); 289*9974Ssam mask = up->upec2; 290*9974Ssam #ifdef UPECCDEBUG 291*9974Ssam printf("npf %d mask 0x%x pos %d wc 0x%x\n",npf,mask,up->upec1,-up->upwc); 292*9974Ssam #endif 293*9974Ssam bn = io->i_bn + npf + 1 ; 294*9974Ssam st = &upst[up_type[io->i_unit]]; 295*9974Ssam twc = up->upwc; 296*9974Ssam io->i_active = 2; 297*9974Ssam /* 298*9974Ssam * action taken depends on the flag 299*9974Ssam */ 300*9974Ssam if (flag == ECC) { 301*9974Ssam mask = up->upec2; 302*9974Ssam printf("up%d: soft ecc sn%d\n", io->i_unit, io->i_bn + npf +1); 303*9974Ssam /* 304*9974Ssam * Compute the 305*9974Ssam * byte and bit position of the error. The variable i 306*9974Ssam * is the byte offset in the transfer. 307*9974Ssam */ 308*9974Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 309*9974Ssam bit = i&07; 310*9974Ssam i = (i&~07)>>3; 311*9974Ssam byte = i; 312*9974Ssam up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 313*9974Ssam /* 314*9974Ssam * Correct while possible bits remain of mask. Since mask 315*9974Ssam * contains 11 bits, we continue while the bit offset is > -11. 316*9974Ssam * Also watch out for end of this block and the end of the whole 317*9974Ssam * transfer. 318*9974Ssam */ 319*9974Ssam while (i < 512 && (int)ptob(npf)+i < io->i_cc && bit > -11) { 320*9974Ssam /* 321*9974Ssam * addr = vax base addr + ( number of sectors transferred 322*9974Ssam * before the error sector times the sector size) 323*9974Ssam * + byte number 324*9974Ssam */ 325*9974Ssam addr = io->i_ma + (npf*512) + byte; 326*9974Ssam #ifdef UPECCDEBUG 327*9974Ssam printf("addr %x old: %x ",addr, *addr); 328*9974Ssam #endif 329*9974Ssam *addr ^= (mask << bit); 330*9974Ssam #ifdef UPECCDEBUG 331*9974Ssam printf("new: %x\n", *addr); 332*9974Ssam #endif 333*9974Ssam byte++; 334*9974Ssam i++; 335*9974Ssam bit -= 8; 336*9974Ssam } 337*9974Ssam #ifndef NOBADSECT 338*9974Ssam } else if (flag == BSE) { 339*9974Ssam /* 340*9974Ssam * if not in bad sector table, return 0 341*9974Ssam */ 342*9974Ssam if ((bbn = isbad(&upbad[io->i_unit], st, bn)) < 0) 343*9974Ssam return(0); 344*9974Ssam up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 345*9974Ssam bbn = st->ncyl * st->nspc -st->nsect - 1 - bbn; 346*9974Ssam twc = up->upwc + 512; 347*9974Ssam up->upwc = -(512 / sizeof (short)); 348*9974Ssam #ifdef UPECCDEBUG 349*9974Ssam printf("revector to block %d\n", bbn); 350*9974Ssam #endif 351*9974Ssam /* 352*9974Ssam * Clear the drive & read the replacement sector. 353*9974Ssam * If this is in the middle of a transfer, then set up the 354*9974Ssam * controller registers in a normal fashion. 355*9974Ssam * The ub-address need not be changed. 356*9974Ssam */ 357*9974Ssam while ( up->upcs1 & UP_RDY == 0) 358*9974Ssam ; 359*9974Ssam up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 360*9974Ssam if (upstart(io, bbn) != 0) return (0); 361*9974Ssam io->i_errcnt = 0; 362*9974Ssam do { 363*9974Ssam DELAY(25); 364*9974Ssam } while ( up->upcs1 & UP_RDY == 0) ; 365*9974Ssam if (up->upds & UPDS_ERR || up->upcs1 & UP_TRE) { 366*9974Ssam up->upwc = twc -512; 367*9974Ssam return (0); 368*9974Ssam } 369*9974Ssam } 370*9974Ssam if (twc != 0) { 371*9974Ssam up->upwc = twc; 372*9974Ssam } 373*9974Ssam return (1); 374*9974Ssam } 375*9974Ssam 376*9974Ssam #ifndef NOBADSECT 377*9974Ssam 378*9974Ssam /* 379*9974Ssam * Search the bad sector table looking for 380*9974Ssam * the specified sector. Return index if found. 381*9974Ssam * Return -1 if not found. 382*9974Ssam */ 383*9974Ssam 384*9974Ssam isbad(bt, st, blno) 385*9974Ssam register struct dkbad *bt; 386*9974Ssam register struct upst *st; 387*9974Ssam { 388*9974Ssam register int i; 389*9974Ssam register long blk, bblk; 390*9974Ssam int trk, sec; 391*9974Ssam 392*9974Ssam sec = blno % st->nspc; 393*9974Ssam trk = sec / st->nsect; 394*9974Ssam sec %= st->nsect; 395*9974Ssam blk = ((long)(blno/st->nspc) << 16) + (trk << 8) + sec; 396*9974Ssam for (i = 0; i < 126; i++) { 397*9974Ssam bblk = ((long)bt->bt_bad[i].bt_cyl << 16) + bt->bt_bad[i].bt_trksec; 398*9974Ssam if (blk == bblk) 399*9974Ssam return (i); 400*9974Ssam if (blk < bblk || bblk < 0) 401*9974Ssam break; 402*9974Ssam } 403*9974Ssam return (-1); 404*9974Ssam } 405*9974Ssam #endif 406*9974Ssam 407*9974Ssam upstart(io, bn) 408*9974Ssam register struct iob *io; 409*9974Ssam daddr_t bn; 410*9974Ssam { 411*9974Ssam register struct updevice *upaddr = 412*9974Ssam (struct updevice *)ubamem(io->i_unit, ubastd[0]); 413*9974Ssam register struct upst *st = &upst[up_type[io->i_unit]]; 414*9974Ssam int sn, tn; 415*9974Ssam 416*9974Ssam sn = bn%st->nspc; 417*9974Ssam tn = sn/st->nsect; 418*9974Ssam sn %= st->nsect; 419*9974Ssam upaddr->updc = bn/st->nspc; 420*9974Ssam upaddr->upda = (tn << 8) + sn; 421*9974Ssam switch (up_ctl[io->i_unit]) { 422*9974Ssam case NORMAL: 423*9974Ssam if (io->i_flgs & IO_READ) 424*9974Ssam upaddr->upcs1 = UP_RCOM|UP_GO; 425*9974Ssam else 426*9974Ssam upaddr->upcs1 = UP_WCOM|UP_GO; 427*9974Ssam break; 428*9974Ssam case HDRIO: 429*9974Ssam if (io->i_flgs & IO_READ) 430*9974Ssam upaddr->upcs1 = UP_RHDR|UP_GO; 431*9974Ssam else 432*9974Ssam upaddr->upcs1 = UP_WHDR|UP_GO; 433*9974Ssam break; 434*9974Ssam case WCHECK: 435*9974Ssam /* don't care if read or write, write check is writecheck 436*9974Ssam * anyhow */ 437*9974Ssam upaddr->upcs1 = UP_WCDATA|UP_GO; 438*9974Ssam break; 439*9974Ssam case WHCHECK: 440*9974Ssam /* don't care if read or write, write check is writecheck 441*9974Ssam * anyhow */ 442*9974Ssam upaddr->upcs1 = UP_WCHDR|UP_GO; 443*9974Ssam break; 444*9974Ssam default: 445*9974Ssam io->i_error = IOERR_CMD; 446*9974Ssam return(1); 447*9974Ssam } 448*9974Ssam return(0) ; 449*9974Ssam } 450*9974Ssam 451