1: /*
   2:  * Copyright (c) 1982, 1986 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:  *	@(#)up.c	7.1 (Berkeley) 6/5/86
   7:  */
   8: 
   9: /*
  10:  * UNIBUS peripheral standalone driver
  11:  * with ECC correction and bad block forwarding.
  12:  * Also supports header operation and write
  13:  * check for data and/or header.
  14:  */
  15: #include "../h/param.h"
  16: #include "../h/inode.h"
  17: #include "../h/fs.h"
  18: #include "../h/dkbad.h"
  19: #include "../h/vmmac.h"
  20: 
  21: #include "../vax/pte.h"
  22: #include "../vaxuba/upreg.h"
  23: #include "../vaxuba/ubareg.h"
  24: 
  25: #include "saio.h"
  26: #include "savax.h"
  27: 
  28: #define RETRIES     27
  29: 
  30: #define MAXBADDESC  126 /* max number of bad sectors recorded */
  31: #define SECTSIZ     512 /* sector size in bytes */
  32: #define HDRSIZ      4   /* number of bytes in sector header */
  33: 
  34: u_short ubastd[] = { 0776700 };
  35: 
  36: extern  struct st upst[];
  37: 
  38: struct  dkbad upbad[MAXNUBA*8];     /* bad sector table */
  39: int     sectsiz;            /* real sector size */
  40: 
  41: struct  up_softc {
  42:     char    gottype;
  43:     char    type;
  44:     char    debug;
  45: #	define    UPF_BSEDEBUG    01  /* debugging bad sector forwarding */
  46: #	define    UPF_ECCDEBUG    02  /* debugging ecc correction */
  47:     int retries;
  48:     int ecclim;
  49: } up_softc[MAXNUBA * 8];
  50: 
  51: u_char  up_offset[16] = {
  52:     UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
  53:     UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
  54:     UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
  55:     0, 0, 0, 0
  56: };
  57: 
  58: upopen(io)
  59:     register struct iob *io;
  60: {
  61:     register unit = io->i_unit;
  62:     register struct updevice *upaddr;
  63:     register struct up_softc *sc = &up_softc[unit];
  64:     register struct st *st;
  65: 
  66:     if (io->i_boff < 0 || io->i_boff > 7)
  67:         _stop("up bad unit");
  68:     upaddr = (struct updevice *)ubamem(unit, ubastd[0]);
  69:     upaddr->upcs2 = unit % 8;
  70:     while ((upaddr->upcs1 & UP_DVA) == 0)
  71:         ;
  72:     if (sc->gottype == 0) {
  73:         register int i;
  74:         struct iob tio;
  75: 
  76:         sc->retries = RETRIES;
  77:         sc->ecclim = 11;
  78:         sc->debug = 0;
  79:         sc->type = upmaptype(unit, upaddr);
  80:         if (sc->type < 0)
  81:             _stop("unknown drive type");
  82:         st = &upst[sc->type];
  83:         if (st->off[io->i_boff] == -1)
  84:             _stop("up bad unit");
  85:         /*
  86: 		 * Read in the bad sector table.
  87: 		 */
  88:         tio = *io;
  89:         tio.i_bn = st->nspc * st->ncyl - st->nsect;
  90:         tio.i_ma = (char *)&upbad[tio.i_unit];
  91:         tio.i_cc = sizeof (struct dkbad);
  92:         tio.i_flgs |= F_RDDATA;
  93:         for (i = 0; i < 5; i++) {
  94:             if (upstrategy(&tio, READ) == sizeof (struct dkbad))
  95:                 break;
  96:             tio.i_bn += 2;
  97:         }
  98:         if (i == 5) {
  99:             printf("Unable to read bad sector table\n");
 100:             for (i = 0; i < MAXBADDESC; i++) {
 101:                 upbad[unit].bt_bad[i].bt_cyl = -1;
 102:                 upbad[unit].bt_bad[i].bt_trksec = -1;
 103:             }
 104:         }
 105:         sc->gottype = 1;
 106:     }
 107:     st = &upst[sc->type];
 108:     io->i_boff = st->off[io->i_boff] * st->nspc;
 109:     io->i_flgs &= ~F_TYPEMASK;
 110: }
 111: 
 112: upstrategy(io, func)
 113:     register struct iob *io;
 114: {
 115:     int cn, tn, sn, o;
 116:     register unit = io->i_unit;
 117:     daddr_t bn;
 118:     int recal, info, waitdry;
 119:     register struct updevice *upaddr =
 120:         (struct updevice *)ubamem(unit, ubastd[0]);
 121:     struct up_softc *sc = &up_softc[unit];
 122:     register struct st *st = &upst[sc->type];
 123:     int doprintf = 0, error, rv = io->i_cc;
 124: 
 125:     sectsiz = SECTSIZ;
 126:     if (io->i_flgs & (F_HDR|F_HCHECK))
 127:         sectsiz += HDRSIZ;
 128:     upaddr->upcs2 = unit % 8;
 129:     if ((upaddr->upds & UPDS_VV) == 0) {
 130:         upaddr->upcs1 = UP_DCLR|UP_GO;
 131:         upaddr->upcs1 = UP_PRESET|UP_GO;
 132:         upaddr->upof = UPOF_FMT22;
 133:     }
 134:     if ((upaddr->upds & UPDS_DREADY) == 0) {
 135:         printf("up%d not ready", unit);
 136:         return (-1);
 137:     }
 138:     info = ubasetup(io, 1);
 139:     upaddr->upwc = -io->i_cc / sizeof (short);
 140:     recal = 0;
 141:     io->i_errcnt = 0;
 142: 
 143: restart:
 144:     error = 0;
 145:     o = io->i_cc + (upaddr->upwc * sizeof (short));
 146:     upaddr->upba = info + o;
 147:     bn = io->i_bn + o / sectsiz;
 148:     if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG))
 149:         printf("wc=%d o=%d i_bn=%d bn=%d\n",
 150:             upaddr->upwc, o, io->i_bn, bn);
 151:     while((upaddr->upds & UPDS_DRY) == 0)
 152:         ;
 153:     if (upstart(io, bn) != 0) {
 154:         rv = -1;
 155:         goto done;
 156:     }
 157:     do {
 158:         DELAY(25);
 159:     } while ((upaddr->upcs1 & UP_RDY) == 0);
 160:     /*
 161: 	 * If transfer has completed, free UNIBUS
 162: 	 * resources and return transfer size.
 163: 	 */
 164:     if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0)
 165:         goto done;
 166:     bn = io->i_bn +
 167:         (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz;
 168:     if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH))
 169:         bn--;
 170:     cn = bn/st->nspc;
 171:     sn = bn%st->nspc;
 172:     tn = sn/st->nsect;
 173:     sn = sn%st->nsect;
 174:     if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) {
 175:         printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
 176:            bn, cn, tn, sn);
 177:         printf("cs2=%b er1=%b er2=%b wc=%d\n",
 178:               upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
 179:           UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc);
 180:     }
 181:     waitdry = 0;
 182:     while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz)
 183:         DELAY(5);
 184:     if (upaddr->uper1&UPER1_WLE) {
 185:         /*
 186: 		 * Give up on write locked devices immediately.
 187: 		 */
 188:         printf("up%d: write locked\n", unit);
 189:         rv = -1;
 190:         goto done;
 191:     }
 192:     if (upaddr->uper2 & UPER2_BSE) {
 193:         if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0)
 194:             goto success;
 195:         error = EBSE;
 196:         goto hard;
 197:     }
 198:     /*
 199: 	 * ECC error. If a soft error, correct it;
 200: 	 * if correction is too large, no more retries.
 201: 	 */
 202:     if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) {
 203:         if (upecc(io, ECC) == 0)
 204:             goto success;
 205:         error = EECC;
 206:         goto hard;
 207:     }
 208:     /*
 209: 	 * If the error is a header CRC,
 210: 	 * check if a replacement sector exists in
 211: 	 * the bad sector table.
 212: 	 */
 213:     if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 &&
 214:          upecc(io, BSE) == 0)
 215:         goto success;
 216:     if (++io->i_errcnt > sc->retries) {
 217:         /*
 218: 		 * After 28 retries (16 without offset, and
 219: 		 * 12 with offset positioning) give up.
 220: 		 */
 221: hard:
 222:         if (error == 0) {
 223:             error = EHER;
 224:             if (upaddr->upcs2 & UPCS2_WCE)
 225:                 error = EWCK;
 226:         }
 227:         printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
 228:            bn, cn, tn, sn);
 229:         printf("cs2=%b er1=%b er2=%b\n",
 230:            upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
 231:            UPER1_BITS, upaddr->uper2, UPER2_BITS);
 232:         upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
 233:         io->i_errblk = bn;
 234:         if (io->i_errcnt >= 16) {
 235:             upaddr->upof = UPOF_FMT22;
 236:             upaddr->upcs1 = UP_RTC|UP_GO;
 237:             while ((upaddr->upds&UPDS_DRY) == 0)
 238:                 DELAY(25);
 239:         }
 240:         rv = -1;
 241:         goto done;
 242:     }
 243:     /*
 244: 	 * Clear drive error and, every eight attempts,
 245: 	 * (starting with the fourth)
 246: 	 * recalibrate to clear the slate.
 247: 	 */
 248:     upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
 249:     if ((io->i_errcnt&07) == 4 ) {
 250:         upaddr->upcs1 = UP_RECAL|UP_GO;
 251:         while ((upaddr->upds&UPDS_DRY) == 0)
 252:             DELAY(25);
 253:         upaddr->updc = cn;
 254:         upaddr->upcs1 = UP_SEEK|UP_GO;
 255:         while ((upaddr->upds&UPDS_DRY) == 0)
 256:             DELAY(25);
 257:     }
 258:     if (io->i_errcnt >= 16 && (func & READ)) {
 259:         upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
 260:         upaddr->upcs1 = UP_OFFSET|UP_GO;
 261:         while ((upaddr->upds&UPDS_DRY) == 0)
 262:             DELAY(25);
 263:     }
 264:     goto restart;
 265: 
 266: success:
 267: #define rounddown(x, y) (((x) / (y)) * (y))
 268:     upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short));
 269:     if (upaddr->upwc) {
 270:         doprintf++;
 271:         goto restart;
 272:     }
 273: done:
 274:     /*
 275: 	 * Release UNIBUS
 276: 	 */
 277:     ubafree(io, info);
 278:     /*
 279: 	 * If we were offset positioning,
 280: 	 * return to centerline.
 281: 	 */
 282:     if (io->i_errcnt >= 16) {
 283:         upaddr->upof = UPOF_FMT22;
 284:         upaddr->upcs1 = UP_RTC|UP_GO;
 285:         while ((upaddr->upds&UPDS_DRY) == 0)
 286:             DELAY(25);
 287:     }
 288:     return (rv);
 289: }
 290: 
 291: /*
 292:  * Correct an ECC error, and restart the
 293:  * i/o to complete the transfer (if necessary).
 294:  * This is quite complicated because the transfer
 295:  * may be going to an odd memory address base and/or
 296:  * across a page boundary.
 297:  */
 298: upecc(io, flag)
 299:     register struct iob *io;
 300:     int flag;
 301: {
 302:     register i, unit = io->i_unit;
 303:     register struct up_softc *sc = &up_softc[unit];
 304:     register struct updevice *up =
 305:         (struct updevice *)ubamem(unit, ubastd[0]);
 306:     register struct st *st;
 307:     caddr_t addr;
 308:     int bn, twc, npf, mask, cn, tn, sn;
 309:     daddr_t bbn;
 310: 
 311:     /*
 312: 	 * Npf is the number of sectors transferred
 313: 	 * before the sector containing the ECC error;
 314: 	 * bn is the current block number.
 315: 	 */
 316:     twc = up->upwc;
 317:     npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz;
 318:     if (flag == ECC)
 319:         npf--;
 320:     if (sc->debug & UPF_ECCDEBUG)
 321:         printf("npf=%d mask=0x%x ec1=%d wc=%d\n",
 322:             npf, up->upec2, up->upec1, twc);
 323:     bn = io->i_bn + npf;
 324:     st = &upst[sc->type];
 325:     cn = bn/st->nspc;
 326:     sn = bn%st->nspc;
 327:     tn = sn/st->nsect;
 328:     sn = sn%st->nsect;
 329: 
 330:     /*
 331: 	 * ECC correction.
 332: 	 */
 333:     if (flag == ECC) {
 334:         int bit, o;
 335: 
 336:         mask = up->upec2;
 337:         printf("up%d: soft ecc sn%d\n", unit, bn);
 338:         for (i = mask, bit = 0; i; i >>= 1)
 339:             if (i & 1)
 340:                 bit++;
 341:         if (bit > sc->ecclim) {
 342:             printf("%d-bit error\n", bit);
 343:             return (1);
 344:         }
 345:         /*
 346: 		 * Compute the byte and bit position of
 347: 		 * the error.  o is the byte offset in
 348: 		 * the transfer at which the correction
 349: 		 * applied.
 350: 		 */
 351:         i = up->upec1 - 1;      /* -1 makes 0 origin */
 352:         bit = i & 07;
 353:         o = (i & ~07) >> 3;
 354:         up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
 355:         /*
 356: 		 * Correct while possible bits remain of mask.
 357: 		 * Since mask contains 11 bits, we continue while
 358: 		 * the bit offset is > -11.  Also watch out for
 359: 		 * end of this block and the end of the transfer.
 360: 		 */
 361:         while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) {
 362:             /*
 363: 			 * addr =
 364: 			 *  (base address of transfer) +
 365: 			 *  (# sectors transferred before the error) *
 366: 			 *    (sector size) +
 367: 			 *  (byte offset to incorrect data)
 368: 			 */
 369:             addr = io->i_ma + (npf * sectsiz) + o;
 370:             /*
 371: 			 * No data transfer occurs with a write check,
 372: 			 * so don't correct the resident copy of data.
 373: 			 */
 374:             if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
 375:                 if (sc->debug & UPF_ECCDEBUG)
 376:                     printf("addr=0x%x old=0x%x ", addr,
 377:                         (*addr&0xff));
 378:                 *addr ^= (mask << bit);
 379:                 if (sc->debug & UPF_ECCDEBUG)
 380:                     printf("new=0x%x\n", (*addr&0xff));
 381:             }
 382:             o++, bit -= 8;
 383:         }
 384:         return (0);
 385:     }
 386: 
 387:     /*
 388: 	 * Bad sector forwarding.
 389: 	 */
 390:     if (flag == BSE) {
 391:         /*
 392: 		 * If not in bad sector table,
 393: 		 * indicate a hard error to caller.
 394: 		 */
 395:         up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
 396:         if ((bbn = isbad(&upbad[unit], cn, tn, sn)) < 0)
 397:             return (1);
 398:         bbn = (st->ncyl * st->nspc) - st->nsect - 1 - bbn;
 399:         twc = up->upwc + sectsiz;
 400:         up->upwc = - (sectsiz / sizeof (short));
 401:         if (sc->debug & UPF_BSEDEBUG)
 402:             printf("revector sn %d to %d\n", sn, bbn);
 403:         /*
 404: 	 	 * Clear the drive & read the replacement
 405: 		 * sector.  If this is in the middle of a
 406: 		 * transfer, then set up the controller
 407: 		 * registers in a normal fashion.
 408: 	 	 * The UNIBUS address need not be changed.
 409: 	 	 */
 410:         while ((up->upcs1 & UP_RDY) == 0)
 411:             ;
 412:         if (upstart(io, bbn))
 413:             return (1);     /* error */
 414:         io->i_errcnt = 0;       /* success */
 415:         do {
 416:             DELAY(25);
 417:         } while ((up->upcs1 & UP_RDY) == 0) ;
 418:         if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) {
 419:             up->upwc = twc - sectsiz;
 420:             return (1);
 421:         }
 422:     }
 423:     if (twc)
 424:         up->upwc = twc;
 425:     return (0);
 426: }
 427: 
 428: upstart(io, bn)
 429:     register struct iob *io;
 430:     daddr_t bn;
 431: {
 432:     register struct updevice *upaddr =
 433:         (struct updevice *)ubamem(io->i_unit, ubastd[0]);
 434:     register struct up_softc *sc = &up_softc[io->i_unit];
 435:     register struct st *st = &upst[sc->type];
 436:     int sn, tn;
 437: 
 438:     sn = bn%st->nspc;
 439:     tn = sn/st->nsect;
 440:     sn %= st->nsect;
 441:     upaddr->updc = bn/st->nspc;
 442:     upaddr->upda = (tn << 8) + sn;
 443:     switch (io->i_flgs & F_TYPEMASK) {
 444: 
 445:     case F_RDDATA:
 446:         upaddr->upcs1 = UP_RCOM|UP_GO;
 447:         break;
 448: 
 449:     case F_WRDATA:
 450:         upaddr->upcs1 = UP_WCOM|UP_GO;
 451:         break;
 452: 
 453:     case F_HDR|F_RDDATA:
 454:         upaddr->upcs1 = UP_RHDR|UP_GO;
 455:         break;
 456: 
 457:     case F_HDR|F_WRDATA:
 458:         upaddr->upcs1 = UP_WHDR|UP_GO;
 459:         break;
 460: 
 461:     case F_CHECK|F_WRDATA:
 462:     case F_CHECK|F_RDDATA:
 463:         upaddr->upcs1 = UP_WCDATA|UP_GO;
 464:         break;
 465: 
 466:     case F_HCHECK|F_WRDATA:
 467:     case F_HCHECK|F_RDDATA:
 468:         upaddr->upcs1 = UP_WCHDR|UP_GO;
 469:         break;
 470: 
 471:     default:
 472:         io->i_error = ECMD;
 473:         io->i_flgs &= ~F_TYPEMASK;
 474:         return (1);
 475:     }
 476:     return (0);
 477: }
 478: 
 479: /*ARGSUSED*/
 480: upioctl(io, cmd, arg)
 481:     struct iob *io;
 482:     int cmd;
 483:     caddr_t arg;
 484: {
 485:     int unit = io->i_unit;
 486:     register struct up_softc *sc = &up_softc[unit];
 487:     struct st *st = &upst[sc->type];
 488: 
 489:     switch(cmd) {
 490: 
 491:     case SAIODEBUG:
 492:         sc->debug = (int)arg;
 493:         break;
 494: 
 495:     case SAIODEVDATA:
 496:         *(struct st *)arg = *st;
 497:         break;
 498: 
 499:     case SAIOGBADINFO:
 500:         *(struct dkbad *)arg = upbad[unit];
 501:         break;
 502: 
 503:     case SAIOECCLIM:
 504:         sc->ecclim = (int)arg;
 505:         break;
 506: 
 507:     case SAIORETRIES:
 508:         sc->retries = (int)arg;
 509:         break;
 510: 
 511:     default:
 512:         return (ECMD);
 513:     }
 514:     return (0);
 515: }

Defined functions

upecc defined in line 298; used 3 times
upioctl defined in line 480; never used
upopen defined in line 58; never used
upstart defined in line 428; used 2 times
upstrategy defined in line 112; used 1 times
  • in line 94

Defined variables

sectsiz defined in line 39; used 13 times
ubastd defined in line 34; used 4 times
up_offset defined in line 51; used 1 times
up_softc defined in line 49; used 5 times
upbad defined in line 38; used 5 times

Defined struct's

up_softc defined in line 41; used 10 times

Defined macros

HDRSIZ defined in line 32; used 1 times
MAXBADDESC defined in line 30; used 1 times
RETRIES defined in line 28; used 1 times
  • in line 76
SECTSIZ defined in line 31; used 1 times
UPF_BSEDEBUG defined in line 45; used 3 times
UPF_ECCDEBUG defined in line 46; used 5 times
rounddown defined in line 267; used 1 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1407
Valid CSS Valid XHTML 1.0 Strict