1: /* 2: * BR disk driver 3: * modified from the UNIX RP03 driver for BR disk drive -JM 4: * 11/11/84 - Added dump routine for taking 2.9 crash dumps in swap. -SMS 5: * 9/28/85 - Use brreg.h so as to look more like a 2.9 disk handler. -SMS 6: * 2/16/86 - Rewrite! Drop the bropen, brclose and brgch functions. Do 7: * initialization on a per drive basis rather than controller. 8: * The bropen and brclose functions were only used to perform 9: * the init'ing of a drive, and there was a problem in single 10: * user mode where a 'umount' could close the device before all 11: * data for that filesystem was written out thereby giving offline 12: * errors and causing corruption of the disc. Also defined a 13: * disc slice that encompassed the whole drive for ease in copying, 14: * several other mods made because this was done. Overall, several 15: * pages of code were removed. -SMS 16: * Just discovered that bropen() and brclose() were defined as 17: * nulldev() in c.c! Wasted code all this time! The offline errors 18: * observed were a result of entry into brstrategy() during a 19: * 'umount' when bropen() had never been called in the first place!!! 20: * 12/6/87 - Changes to run under 2.10bsd. Still single controller only. 21: * Considering we don't make the controller any more that's fairly 22: * safe to assume. Partitions drastically changed to allow room 23: * on T300 and T200 to hold the source distribution. 24: * Autoconfigure logic finally added though. -SMS 25: * 2/17/89 - For 2.10.1BSD added old 2.9BSD /usr,/userfiles, and /minkie 26: * partitions as partitions 'e', 'f', and 'g' as an aid in 27: * converting the systems. BE CAREFUL! For T300 only. 28: * 8/4/89 - Use the log() function to record soft errors. 29: * 9/22/91 - remove read and write entry - use common raw read/write routine. 30: * 12/23/92 - add the partition size routine. 31: * 1/2/93 - remove unibus map ifdefs, the run time check using 'ubmap' is 32: * sufficient and does the right thing. 33: * 1995/04/13 - change reference to dkunit. 34: */ 35: 36: #include "br.h" 37: #if NBR > 0 38: 39: #include "param.h" 40: #include "../machine/seg.h" 41: 42: #include "systm.h" 43: #include "buf.h" 44: #include "conf.h" 45: #include "user.h" 46: #include "brreg.h" 47: #include "dk.h" 48: #include "disklabel.h" 49: #include "disk.h" 50: #include "syslog.h" 51: #include "map.h" 52: #include "uba.h" 53: 54: #define BRADDR ((struct brdevice *) 0176710) 55: #define brunit(dev) ((dev >> 3) & 7) 56: #define SECTRK brc->sectrk 57: #define TRKCYL brc->trkcyl 58: 59: struct br_char { 60: struct br_dsz { 61: daddr_t nblocks; 62: int cyloff; 63: } br_sizes[8]; 64: int sectrk, trkcyl; 65: } br_chars[] = 66: { /* T300 */ 67: 18240, 0, /* cyl 000 - 029 */ 68: 12160, 30, /* cyl 030 - 049 */ 69: 232256, 50, /* cyl 050 - 431 */ 70: 232256, 432, /* cyl 432 - 813 */ 71: 154432, 50, /* 'e' is old 2.9 'c' partition */ 72: 154432, 304, /* 'f' is old 2.9 'd' partition */ 73: 154432, 558, /* 'g' is old 2.9 'e' partition */ 74: 495520, 0, /* cyl 000 - 814 */ 75: 32, 19, /* 32 sectrk, 19 trkcyl */ 76: /* T200 */ 77: 18392, 0, /* cyl 000 - 043 */ 78: 12122, 43, /* cyl 044 - 072 */ 79: 231990, 73, /* cyl 073 - 627 */ 80: 78166, 443, /* cyl 628 - 814 */ 81: 0, 0, 82: 0, 0, 83: 0, 0, 84: 340670, 0, /* cyl 000 - 814 */ 85: 22, 19, /* 22 sectrk, 19 trkcyl */ 86: /* T80 */ 87: 18400, 0, /* cyl 000 - 114 */ 88: 12320, 115, /* cyl 115 - 190 */ 89: 99840, 191, /* cyl 191 - 814 */ 90: 0, 0, 91: 0, 0, 92: 0, 0, 93: 0, 0, 94: 130300, 0, 95: 32, 5, /* 32 sectrk, 5 trkcyl */ 96: /* T50 */ 97: 18260, 0, /* cyl 000 - 165 */ 98: 12210, 166, /* cyl 166 - 276 */ 99: 59180, 277, /* cyl 277 - 814 */ 100: 0, 0, 101: 0, 0, 102: 0, 0, 103: 0, 0, 104: 89650, 0, 105: 22, 5, /* 22 sectrk, 5 trkcyl */ 106: }; 107: 108: /* 109: * Define the recovery strobes and offsets in br_da 110: */ 111: static int br_offs[] = { 112: 0, 0, 0, STBE, 113: STBE, STBL, STBL, OFFP+STBL, 114: OFFP+STBL, OFFP, OFFP, OFFP+STBE, 115: OFFP+STBE, OFFM+STBE, OFFM+STBE, OFFP, 116: OFFP, OFFP+STBL, OFFP+STBL, 0 117: }; 118: 119: #ifdef UCB_METER 120: static int br_dkn = -1; 121: #endif 122: struct buf brtab; 123: struct br_char *br_disk[NBR]; 124: struct brdevice *Br_addr; 125: 126: brroot() 127: { 128: brattach((struct brdevice *)BRADDR, 0); 129: } 130: 131: brattach(braddr, unit) 132: register struct brdevice *braddr; 133: int unit; 134: { 135: 136: #ifdef UCB_METER 137: if (br_dkn < 0) 138: dk_alloc(&br_dkn, NBR, "br", 0L); 139: #endif 140: if (unit >= NBR) 141: return(0); 142: if (braddr && (fioword(braddr) != -1)) { 143: Br_addr = braddr; 144: return(1); 145: } 146: return(0); 147: } 148: 149: bropen(dev, flag) 150: dev_t dev; 151: int flag; 152: { 153: register int dn = brunit(dev); 154: 155: if (dn >= NBR || !Br_addr) 156: return(ENXIO); 157: if (!br_disk[dn]) 158: brinit(dn); 159: if (!br_disk[dn]) 160: return(EIO); 161: return(0); 162: } 163: 164: brstrategy(bp) 165: register struct buf *bp; 166: { 167: register struct buf *dp; 168: register int unit; 169: struct br_char *brc; 170: struct br_dsz *brz; 171: long sz; 172: int drive, s; 173: 174: unit = bp->b_dev & 07; 175: drive = brunit(bp->b_dev); 176: if (!(brc = br_disk[drive])) { 177: brinit(drive); 178: if (!(brc = br_disk[drive])) { 179: bp->b_error = ENODEV; 180: bp->b_flags |= B_ERROR; 181: iodone(bp); 182: return; 183: } 184: } 185: brz = &brc->br_sizes[unit]; 186: sz = (bp->b_bcount + 511L) >> 9; 187: if (bp->b_blkno == brz->nblocks) { 188: bp->b_resid = bp->b_bcount; 189: iodone(bp); 190: return; 191: } 192: if (bp->b_blkno + sz > brz->nblocks) { 193: bp->b_error = EINVAL; 194: bp->b_flags |= B_ERROR; 195: iodone(bp); 196: return; 197: } 198: if (Br_addr->brae >= 0) 199: mapalloc(bp); 200: bp->b_cylin = bp->b_blkno/(SECTRK*TRKCYL) + brz->cyloff; 201: s = splbio(); 202: dp = &brtab; 203: disksort(dp, bp); 204: if (dp->b_active == NULL) 205: brstart(); 206: splx(s); 207: } 208: 209: static 210: brstart() 211: { 212: register struct buf *bp; 213: register int unit; 214: int com,cn,tn,sn,dn; 215: daddr_t bn; 216: struct br_char *brc; 217: struct br_dsz *brz; 218: 219: if ((bp = brtab.b_actf) == NULL) 220: return; 221: Br_addr->brds = -1; 222: brtab.b_active++; 223: if (!(Br_addr->brcs.w & BR_RDY)) { 224: timeout(brstart, 0, 4); 225: return; 226: } 227: unit = bp->b_dev & 07; 228: dn = brunit(bp->b_dev); 229: if (!(brc = br_disk[dn])) { 230: brinit(dn); 231: if (!(brc = br_disk[dn])) { 232: bp->b_flags |= B_ERROR; 233: brdone(bp); 234: return; 235: } 236: } 237: brz = &brc->br_sizes[unit]; 238: bn = bp->b_blkno; 239: cn = bn/(SECTRK*TRKCYL) + brz->cyloff; 240: sn = bn%(SECTRK*TRKCYL); 241: tn = sn/SECTRK; 242: sn = sn%SECTRK; 243: if (Br_addr->brae < 0) 244: Br_addr->brae = bp->b_xmem; 245: Br_addr->brcs.w = (dn<<8); 246: Br_addr->brda = (tn<<8) | sn; 247: cn |= br_offs[brtab.b_errcnt]; 248: Br_addr->brca = cn; 249: Br_addr->brba = bp->b_un.b_addr; 250: Br_addr->brwc = -(bp->b_bcount>>1); 251: com = ((bp->b_xmem&3)<<4) | BR_IDE | BR_GO; 252: if (bp->b_flags & B_READ) 253: com |= BR_RCOM; 254: else 255: com |= BR_WCOM; 256: Br_addr->brcs.w |= com; 257: #ifdef UCB_METER 258: if (br_dkn >= 0) { 259: dk_busy |= 1 << (br_dkn + dn); 260: dk_xfer[br_dkn + dn]++; 261: dk_seek[br_dkn + dn]++; 262: dk_wds[br_dkn + dn] += (bp->b_bcount >> 6); 263: } 264: #endif 265: } 266: 267: static 268: brinit(drive) 269: register int drive; 270: { 271: register int ctr = 0; 272: register struct br_char **br = &br_disk[drive]; 273: 274: /* 275: * Clear the drive's entry in br_disk. Select the unit. If the 276: * unit exists, switch on the spindle type. and set the br_disk 277: * table entry 278: */ 279: *br = (struct br_char *)NULL; 280: do { 281: Br_addr->brcs.w = (drive << 8) | BR_HSEEK | BR_GO; 282: while ((Br_addr->brcs.w & BR_RDY) == 0 && --ctr) ; 283: } while (Br_addr->brer & BRER_SUBUSY); 284: if ((Br_addr->brcs.w & BR_HE) == 0) { 285: switch (Br_addr->brae & AE_DTYP) { 286: case AE_T300: 287: *br = &br_chars[0]; 288: break; 289: case AE_T200: 290: *br = &br_chars[1]; 291: break; 292: case AE_T80: 293: *br = &br_chars[2]; 294: break; 295: case AE_T50: 296: *br = &br_chars[3]; 297: break; 298: } 299: #ifdef UCB_METER 300: if (br_dkn >= 0) 301: dk_wps[br_dkn + drive] = 302: (long)(*br)->sectrk * (60L * 256L); 303: #endif 304: } 305: } 306: 307: brintr(dev) 308: int dev; 309: { 310: register struct buf *bp; 311: register int ctr = 0; 312: struct brdevice brsave; 313: 314: if (brtab.b_active == NULL) 315: return; 316: brsave = *Br_addr; 317: bp = brtab.b_actf; 318: if (!(brsave.brcs.w & BR_RDY)) 319: return; 320: #ifdef UCB_METER 321: if (br_dkn >= 0) 322: dk_busy &= ~(1<<(br_dkn + dev)); 323: #endif 324: if (brsave.brcs.w < 0) { 325: if (brsave.brer & BRER_SUBUSY) { 326: timeout(brstart, 0, 5); 327: return; 328: } 329: if (brsave.brds & (BRDS_SUFU|BRDS_SUSI|BRDS_HNF)) { 330: Br_addr->brcs.c[0] = BR_HSEEK|BR_GO; 331: while (((Br_addr->brds&BRDS_SURDY) == 0) && --ctr); 332: } 333: Br_addr->brcs.w = BR_IDLE|BR_GO; 334: ctr = 0; 335: while (((Br_addr->brcs.w&BR_RDY) == 0) && --ctr) ; 336: if (brtab.b_errcnt == 0) { 337: log(LOG_WARNING,"br%d%c ds:%b er:%b cs:%b wc:%o ba:%o ca:%o da:%o bae:%o\n", 338: dkunit(bp->b_dev), 'a'+ dkpart(bp->b_dev), 339: brsave.brds, BRDS_BITS, brsave.brer, BRER_BITS, 340: brsave.brcs.w, BR_BITS, brsave.brwc,brsave.brba, 341: brsave.brca, brsave.brda, brsave.brae); 342: } 343: brtab.b_errcnt++; 344: if (brtab.b_errcnt < 20) { 345: brstart(); 346: return; 347: } 348: harderr(bp,"br"); 349: bp->b_flags |= B_ERROR; 350: } 351: brdone(bp); 352: } 353: 354: static 355: brdone (bp) 356: register struct buf *bp; 357: { 358: brtab.b_active = NULL; 359: brtab.b_errcnt = 0; 360: brtab.b_actf = bp->av_forw; 361: bp->b_resid = 0; 362: iodone(bp); 363: brstart(); 364: } 365: 366: #ifdef BR_DUMP 367: /* 368: * Dump routine. Dumps from dumplo to end of memory/end of disk section for 369: * minor(dev). 370: */ 371: #define DBSIZE 16 /* unit of transfer, same number */ 372: 373: brdump(dev) 374: dev_t dev; 375: { 376: struct br_char *brc; 377: struct ubmap *ubp; 378: daddr_t bn, dumpsize; 379: long paddr; 380: int count, cyl, dn, cn, tn, sn, unit, com; 381: 382: unit = dev & 07; 383: dn = brunit(dev); 384: if ((bdevsw[major(dev)].d_strategy != brstrategy) || dn >= NBR) 385: return(EINVAL); 386: if (!Br_addr || !(brc = br_disk[dn])) 387: return(ENXIO); 388: dumpsize = brc->br_sizes[unit].nblocks; 389: cyl = brc->br_sizes[unit].cyloff; 390: if ((dumplo < 0) || (dumplo >= dumpsize)) 391: return(EINVAL); 392: dumpsize -= dumplo; 393: while (!(Br_addr->brcs.w & BR_RDY)); 394: ubp = &UBMAP[0]; 395: for (paddr = 0L; dumpsize > 0; dumpsize -= count) { 396: count = dumpsize > DBSIZE ? DBSIZE : dumpsize; 397: bn = dumplo + (paddr >> PGSHIFT); 398: cn = (bn / (SECTRK * TRKCYL)) + cyl; 399: sn = bn % (SECTRK * TRKCYL); 400: tn = sn / SECTRK; 401: sn = sn % SECTRK; 402: Br_addr->brca = cn; 403: Br_addr->brda = (tn << 8) | sn; 404: Br_addr->brwc = -(count << (PGSHIFT-1)); 405: com = (dn << 8) | BR_GO | BR_WCOM; 406: if (ubmap && Br_addr->brae >= 0) { 407: ubp->ub_lo = loint(paddr); 408: ubp->ub_hi = hiint(paddr); 409: Br_addr->brba = 0; 410: } 411: else { 412: Br_addr->brba = (caddr_t)loint(paddr); 413: Br_addr->brae = hiint(paddr); 414: com |= ((hiint(paddr) & 3) << 4); 415: } 416: Br_addr->brcs.w = com; 417: while (!(Br_addr->brcs.w & BR_RDY)); 418: if (Br_addr->brcs.w < 0) { 419: if (Br_addr->brer & BRER_NXME) 420: return(0); /* end of memory */ 421: return(EIO); 422: } 423: paddr += (DBSIZE << PGSHIFT); 424: } 425: return(0); /* filled disk */ 426: } 427: #endif /* BR_DUMP */ 428: 429: /* 430: * Assumes the 'open' entry point has been called to validate the unit 431: * number and fill in the drive type structure. 432: */ 433: daddr_t 434: brsize(dev) 435: register dev_t dev; 436: { 437: register struct br_char *brc; 438: 439: brc = br_disk[brunit(dev)]; 440: return(brc->br_sizes[dev & 7].nblocks); 441: } 442: #endif /* NBR */