|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. ! 9: * ! 10: * Redistribution is only permitted until one year after the first shipment ! 11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 12: * binary forms are permitted provided that: (1) source distributions retain ! 13: * this entire copyright notice and comment, and (2) distributions including ! 14: * binaries display the following acknowledgement: This product includes ! 15: * software developed by the University of California, Berkeley and its ! 16: * contributors'' in the documentation or other materials provided with the ! 17: * distribution and in all advertising materials mentioning features or use ! 18: * of this software. Neither the name of the University nor the names of ! 19: * its contributors may be used to endorse or promote products derived from ! 20: * this software without specific prior written permission. ! 21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 24: * ! 25: * from: Utah $Hdr: cd.c 1.4 89/09/17$ ! 26: * ! 27: * @(#)cd.c 7.1 (Berkeley) 5/8/90 ! 28: */ ! 29: ! 30: /* ! 31: * "Concatenated" disk driver. ! 32: */ ! 33: #include "cd.h" ! 34: #if NCD > 0 ! 35: ! 36: #include "param.h" ! 37: #include "systm.h" ! 38: #include "errno.h" ! 39: #include "dkstat.h" ! 40: #include "buf.h" ! 41: #include "malloc.h" ! 42: #include "conf.h" ! 43: ! 44: #include "cdvar.h" ! 45: ! 46: #ifdef DEBUG ! 47: int cddebug = 0x00; ! 48: #define CDB_FOLLOW 0x01 ! 49: #define CDB_INIT 0x02 ! 50: #define CDB_IO 0x04 ! 51: #endif ! 52: ! 53: struct buf cdbuf[NCD]; ! 54: struct buf *cdbuffer(); ! 55: int cdiodone(); ! 56: ! 57: #define cdunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ ! 58: ! 59: #define getcbuf() \ ! 60: ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) ! 61: #define putcbuf(bp) \ ! 62: free((caddr_t)(bp), M_DEVBUF) ! 63: ! 64: struct cd_softc { ! 65: int sc_flags; /* flags */ ! 66: size_t sc_size; /* size of cd */ ! 67: int sc_ileave; /* interleave */ ! 68: int sc_ncdisks; /* number of components */ ! 69: struct cdcinfo sc_cinfo[NCDISKS]; /* component info */ ! 70: struct cdiinfo *sc_itable; /* interleave table */ ! 71: int sc_usecnt; /* number of requests active */ ! 72: struct buf *sc_bp; /* "current" request */ ! 73: int sc_dk; /* disk index */ ! 74: } cd_softc[NCD]; ! 75: ! 76: /* sc_flags */ ! 77: #define CDF_ALIVE 0x01 ! 78: #define CDF_INITED 0x02 ! 79: ! 80: cdinit(cd) ! 81: struct cddevice *cd; ! 82: { ! 83: register struct cd_softc *cs = &cd_softc[cd->cd_unit]; ! 84: register struct cdcinfo *ci; ! 85: register size_t size; ! 86: register int ix; ! 87: size_t minsize; ! 88: dev_t dev; ! 89: ! 90: #ifdef DEBUG ! 91: if (cddebug & (CDB_FOLLOW|CDB_INIT)) ! 92: printf("cdinit: unit %d\n", cd->cd_unit); ! 93: #endif ! 94: cs->sc_dk = cd->cd_dk; ! 95: cs->sc_size = 0; ! 96: cs->sc_ileave = cd->cd_interleave; ! 97: cs->sc_ncdisks = 0; ! 98: /* ! 99: * Verify that each component piece exists and record ! 100: * relevant information about it. ! 101: */ ! 102: minsize = 0; ! 103: for (ix = 0; ix < NCDISKS; ix++) { ! 104: if ((dev = cd->cd_dev[ix]) == NODEV) ! 105: break; ! 106: ci = &cs->sc_cinfo[ix]; ! 107: ci->ci_dev = dev; ! 108: /* ! 109: * Calculate size (truncated to interleave boundary ! 110: * if necessary. ! 111: */ ! 112: if (bdevsw[major(dev)].d_psize) { ! 113: size = (*bdevsw[major(dev)].d_psize)(dev); ! 114: if (size <= 0) ! 115: size = 0; ! 116: } else ! 117: size = 0; ! 118: if (cs->sc_ileave > 1) ! 119: size -= size % cs->sc_ileave; ! 120: if (size == 0) ! 121: return(0); ! 122: if (minsize == 0 || size < minsize) ! 123: minsize = size; ! 124: ci->ci_size = size; ! 125: cs->sc_size += size; ! 126: cs->sc_ncdisks++; ! 127: } ! 128: /* ! 129: * If uniform interleave is desired set all sizes to that of ! 130: * the smallest component. ! 131: */ ! 132: if (cd->cd_flags & CDF_UNIFORM) { ! 133: for (ci = cs->sc_cinfo; ! 134: ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) ! 135: ci->ci_size = minsize; ! 136: cs->sc_size = cs->sc_ncdisks * minsize; ! 137: } ! 138: /* ! 139: * Construct the interleave table ! 140: */ ! 141: if (!cdinterleave(cs)) ! 142: return(0); ! 143: if (cd->cd_dk >= 0) ! 144: dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */ ! 145: printf("cd%d: %d components (%d blocks) concatenated", ! 146: cd->cd_unit, cs->sc_ncdisks, cs->sc_size); ! 147: if (cs->sc_ileave) ! 148: printf(", %d block interleave\n", cs->sc_ileave); ! 149: else ! 150: printf(" serially\n"); ! 151: cs->sc_flags = CDF_ALIVE | CDF_INITED; ! 152: return(1); ! 153: } ! 154: ! 155: cdinterleave(cs) ! 156: register struct cd_softc *cs; ! 157: { ! 158: register struct cdcinfo *ci, *smallci; ! 159: register struct cdiinfo *ii; ! 160: register daddr_t bn, lbn; ! 161: register int ix; ! 162: u_long size; ! 163: ! 164: #ifdef DEBUG ! 165: if (cddebug & CDB_INIT) ! 166: printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); ! 167: #endif ! 168: /* ! 169: * Allocate an interleave table. ! 170: * Chances are this is too big, but we don't care. ! 171: */ ! 172: size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo); ! 173: cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); ! 174: bzero((caddr_t)cs->sc_itable, size); ! 175: /* ! 176: * Trivial case: no interleave (actually interleave of disk size). ! 177: * Each table entry represent a single component in its entirety. ! 178: */ ! 179: if (cs->sc_ileave == 0) { ! 180: bn = 0; ! 181: ii = cs->sc_itable; ! 182: for (ix = 0; ix < cs->sc_ncdisks; ix++) { ! 183: ii->ii_ndisk = 1; ! 184: ii->ii_startblk = bn; ! 185: ii->ii_startoff = 0; ! 186: ii->ii_index[0] = ix; ! 187: bn += cs->sc_cinfo[ix].ci_size; ! 188: ii++; ! 189: } ! 190: ii->ii_ndisk = 0; ! 191: #ifdef DEBUG ! 192: if (cddebug & CDB_INIT) ! 193: printiinfo(cs->sc_itable); ! 194: #endif ! 195: return(1); ! 196: } ! 197: /* ! 198: * The following isn't fast or pretty; it doesn't have to be. ! 199: */ ! 200: size = 0; ! 201: bn = lbn = 0; ! 202: for (ii = cs->sc_itable; ; ii++) { ! 203: /* ! 204: * Locate the smallest of the remaining components ! 205: */ ! 206: smallci = NULL; ! 207: for (ci = cs->sc_cinfo; ! 208: ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) ! 209: if (ci->ci_size > size && ! 210: (smallci == NULL || ! 211: ci->ci_size < smallci->ci_size)) ! 212: smallci = ci; ! 213: /* ! 214: * Nobody left, all done ! 215: */ ! 216: if (smallci == NULL) { ! 217: ii->ii_ndisk = 0; ! 218: break; ! 219: } ! 220: /* ! 221: * Record starting logical block and component offset ! 222: */ ! 223: ii->ii_startblk = bn / cs->sc_ileave; ! 224: ii->ii_startoff = lbn; ! 225: /* ! 226: * Determine how many disks take part in this interleave ! 227: * and record their indices. ! 228: */ ! 229: ix = 0; ! 230: for (ci = cs->sc_cinfo; ! 231: ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) ! 232: if (ci->ci_size >= smallci->ci_size) ! 233: ii->ii_index[ix++] = ci - cs->sc_cinfo; ! 234: ii->ii_ndisk = ix; ! 235: bn += ix * (smallci->ci_size - size); ! 236: lbn = smallci->ci_size / cs->sc_ileave; ! 237: size = smallci->ci_size; ! 238: } ! 239: #ifdef DEBUG ! 240: if (cddebug & CDB_INIT) ! 241: printiinfo(cs->sc_itable); ! 242: #endif ! 243: return(1); ! 244: } ! 245: ! 246: #ifdef DEBUG ! 247: printiinfo(ii) ! 248: struct cdiinfo *ii; ! 249: { ! 250: register int ix, i; ! 251: ! 252: for (ix = 0; ii->ii_ndisk; ix++, ii++) { ! 253: printf(" itab[%d]: #dk %d sblk %d soff %d", ! 254: ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); ! 255: for (i = 0; i < ii->ii_ndisk; i++) ! 256: printf(" %d", ii->ii_index[i]); ! 257: printf("\n"); ! 258: } ! 259: } ! 260: #endif ! 261: ! 262: cdopen(dev, flags) ! 263: dev_t dev; ! 264: { ! 265: int unit = cdunit(dev); ! 266: register struct cd_softc *cs = &cd_softc[unit]; ! 267: ! 268: #ifdef DEBUG ! 269: if (cddebug & CDB_FOLLOW) ! 270: printf("cdopen(%x, %x)\n", dev, flags); ! 271: #endif ! 272: if (unit >= NCD || (cs->sc_flags & CDF_ALIVE) == 0) ! 273: return(ENXIO); ! 274: return(0); ! 275: } ! 276: ! 277: cdstrategy(bp) ! 278: register struct buf *bp; ! 279: { ! 280: register int unit = cdunit(bp->b_dev); ! 281: register struct cd_softc *cs = &cd_softc[unit]; ! 282: register int bn, sz; ! 283: int s; ! 284: ! 285: #ifdef DEBUG ! 286: if (cddebug & CDB_FOLLOW) ! 287: printf("cdstrategy(%x): unit %d\n", bp, unit); ! 288: #endif ! 289: if ((cs->sc_flags & CDF_INITED) == 0) { ! 290: bp->b_error = ENXIO; ! 291: goto bad; ! 292: } ! 293: bn = bp->b_blkno; ! 294: sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT; ! 295: bp->b_resid = bp->b_bcount; ! 296: if (bn < 0 || bn + sz > cs->sc_size) { ! 297: if (bn == cs->sc_size) ! 298: goto done; ! 299: bp->b_error = EINVAL; ! 300: goto bad; ! 301: } ! 302: /* ! 303: * "Start" the unit. ! 304: * XXX: the use of sc_bp is just to retain the "traditional" ! 305: * interface to the start routine. ! 306: */ ! 307: s = splbio(); ! 308: cs->sc_bp = bp; ! 309: cdstart(unit); ! 310: splx(s); ! 311: return; ! 312: bad: ! 313: bp->b_flags |= B_ERROR; ! 314: done: ! 315: iodone(bp); ! 316: } ! 317: ! 318: cdstart(unit) ! 319: int unit; ! 320: { ! 321: register struct cd_softc *cs = &cd_softc[unit]; ! 322: register struct buf *bp = cs->sc_bp; ! 323: register long bcount, rcount; ! 324: struct buf *cbp; ! 325: caddr_t addr; ! 326: daddr_t bn; ! 327: ! 328: #ifdef DEBUG ! 329: if (cddebug & CDB_FOLLOW) ! 330: printf("cdstart(%d)\n", unit); ! 331: #endif ! 332: /* ! 333: * Instumentation (not real meaningful) ! 334: */ ! 335: cs->sc_usecnt++; ! 336: if (cs->sc_dk >= 0) { ! 337: dk_busy |= 1 << cs->sc_dk; ! 338: dk_xfer[cs->sc_dk]++; ! 339: dk_wds[cs->sc_dk] += bp->b_bcount >> 6; ! 340: } ! 341: /* ! 342: * Allocate component buffers and fire off the requests ! 343: */ ! 344: bn = bp->b_blkno; ! 345: addr = bp->b_un.b_addr; ! 346: for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { ! 347: cbp = cdbuffer(cs, bp, bn, addr, bcount); ! 348: rcount = cbp->b_bcount; ! 349: (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp); ! 350: bn += btodb(rcount); ! 351: addr += rcount; ! 352: } ! 353: } ! 354: ! 355: /* ! 356: * Build a component buffer header. ! 357: */ ! 358: struct buf * ! 359: cdbuffer(cs, bp, bn, addr, bcount) ! 360: register struct cd_softc *cs; ! 361: struct buf *bp; ! 362: daddr_t bn; ! 363: caddr_t addr; ! 364: long bcount; ! 365: { ! 366: register struct cdcinfo *ci; ! 367: register struct buf *cbp; ! 368: register daddr_t cbn, cboff; ! 369: ! 370: #ifdef DEBUG ! 371: if (cddebug & CDB_IO) ! 372: printf("cdbuffer(%x, %x, %d, %x, %d)\n", ! 373: cs, bp, bn, addr, bcount); ! 374: #endif ! 375: /* ! 376: * Determine which component bn falls in. ! 377: */ ! 378: cbn = bn; ! 379: cboff = 0; ! 380: /* ! 381: * Serially concatenated ! 382: */ ! 383: if (cs->sc_ileave == 0) { ! 384: register daddr_t sblk; ! 385: ! 386: sblk = 0; ! 387: for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) ! 388: sblk += ci->ci_size; ! 389: cbn -= sblk; ! 390: } ! 391: /* ! 392: * Interleaved ! 393: */ ! 394: else { ! 395: register struct cdiinfo *ii; ! 396: int cdisk, off; ! 397: ! 398: cboff = cbn % cs->sc_ileave; ! 399: cbn /= cs->sc_ileave; ! 400: for (ii = cs->sc_itable; ii->ii_ndisk; ii++) ! 401: if (ii->ii_startblk > cbn) ! 402: break; ! 403: ii--; ! 404: off = cbn - ii->ii_startblk; ! 405: if (ii->ii_ndisk == 1) { ! 406: cdisk = ii->ii_index[0]; ! 407: cbn = ii->ii_startoff + off; ! 408: } else { ! 409: cdisk = ii->ii_index[off % ii->ii_ndisk]; ! 410: cbn = ii->ii_startoff + off / ii->ii_ndisk; ! 411: } ! 412: cbn *= cs->sc_ileave; ! 413: ci = &cs->sc_cinfo[cdisk]; ! 414: } ! 415: /* ! 416: * Fill in the component buf structure. ! 417: */ ! 418: cbp = getcbuf(); ! 419: cbp->b_flags = bp->b_flags | B_CALL; ! 420: cbp->b_iodone = cdiodone; ! 421: cbp->b_proc = bp->b_proc; ! 422: cbp->b_dev = ci->ci_dev; ! 423: cbp->b_blkno = cbn + cboff; ! 424: cbp->b_un.b_addr = addr; ! 425: if (cs->sc_ileave == 0) ! 426: cbp->b_bcount = dbtob(ci->ci_size - cbn); ! 427: else ! 428: cbp->b_bcount = dbtob(cs->sc_ileave - cboff); ! 429: if (cbp->b_bcount > bcount) ! 430: cbp->b_bcount = bcount; ! 431: /* ! 432: * XXX: context for cdiodone ! 433: */ ! 434: cbp->b_vp = (struct vnode *)bp; ! 435: cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo); ! 436: #ifdef DEBUG ! 437: if (cddebug & CDB_IO) ! 438: printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", ! 439: ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno, ! 440: cbp->b_un.b_addr, cbp->b_bcount); ! 441: #endif ! 442: return(cbp); ! 443: } ! 444: ! 445: cdintr(unit) ! 446: int unit; ! 447: { ! 448: register struct cd_softc *cs = &cd_softc[unit]; ! 449: register struct buf *bp = cs->sc_bp; ! 450: ! 451: #ifdef DEBUG ! 452: if (cddebug & CDB_FOLLOW) ! 453: printf("cdintr(%d)\n", unit); ! 454: #endif ! 455: /* ! 456: * Request is done for better or worse, wakeup the top half. ! 457: */ ! 458: if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0) ! 459: dk_busy &= ~(1 << cs->sc_dk); ! 460: if (bp->b_flags & B_ERROR) ! 461: bp->b_resid = bp->b_bcount; ! 462: iodone(bp); ! 463: } ! 464: ! 465: /* ! 466: * Called by iodone at interrupt time. ! 467: * Mark the component as done and if all components are done, ! 468: * take a cd interrupt. ! 469: */ ! 470: cdiodone(cbp) ! 471: register struct buf *cbp; ! 472: { ! 473: register struct buf *bp = (struct buf *)cbp->b_vp; /* XXX */ ! 474: register int unit = (cbp->b_pfcent >> 16) & 0xFFFF; /* XXX */ ! 475: int count, s; ! 476: ! 477: s = splbio(); ! 478: #ifdef DEBUG ! 479: if (cddebug & CDB_FOLLOW) ! 480: printf("cdiodone(%x)\n", cbp); ! 481: if (cddebug & CDB_IO) { ! 482: printf("cdiodone: bp %x bcount %d resid %d\n", ! 483: bp, bp->b_bcount, bp->b_resid); ! 484: printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", ! 485: cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp, ! 486: cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount); ! 487: } ! 488: #endif ! 489: ! 490: if (cbp->b_flags & B_ERROR) { ! 491: bp->b_flags |= B_ERROR; ! 492: bp->b_error = geterror(cbp); ! 493: #ifdef DEBUG ! 494: printf("cd%d: error %d on component %d\n", ! 495: unit, bp->b_error, cbp->b_pfcent & 0xFFFF); ! 496: #endif ! 497: } ! 498: count = cbp->b_bcount; ! 499: putcbuf(cbp); ! 500: ! 501: /* ! 502: * If all done, "interrupt". ! 503: * Again, sc_bp is only used to preserve the traditional interface. ! 504: */ ! 505: bp->b_resid -= count; ! 506: if (bp->b_resid < 0) ! 507: panic("cdiodone: count"); ! 508: if (bp->b_resid == 0) { ! 509: cd_softc[unit].sc_bp = bp; ! 510: cdintr(unit); ! 511: } ! 512: splx(s); ! 513: } ! 514: ! 515: cdread(dev, uio) ! 516: dev_t dev; ! 517: struct uio *uio; ! 518: { ! 519: register int unit = cdunit(dev); ! 520: ! 521: #ifdef DEBUG ! 522: if (cddebug & CDB_FOLLOW) ! 523: printf("cdread(%x, %x)\n", dev, uio); ! 524: #endif ! 525: return(physio(cdstrategy, &cdbuf[unit], dev, B_READ, minphys, uio)); ! 526: } ! 527: ! 528: cdwrite(dev, uio) ! 529: dev_t dev; ! 530: struct uio *uio; ! 531: { ! 532: register int unit = cdunit(dev); ! 533: ! 534: #ifdef DEBUG ! 535: if (cddebug & CDB_FOLLOW) ! 536: printf("cdwrite(%x, %x)\n", dev, uio); ! 537: #endif ! 538: return(physio(cdstrategy, &cdbuf[unit], dev, B_WRITE, minphys, uio)); ! 539: } ! 540: ! 541: cdioctl(dev, cmd, data, flag) ! 542: dev_t dev; ! 543: int cmd; ! 544: caddr_t data; ! 545: int flag; ! 546: { ! 547: return(EINVAL); ! 548: } ! 549: ! 550: cdsize(dev) ! 551: dev_t dev; ! 552: { ! 553: int unit = cdunit(dev); ! 554: register struct cd_softc *cs = &cd_softc[unit]; ! 555: ! 556: if (unit >= NCD || (cs->sc_flags & CDF_INITED) == 0) ! 557: return(-1); ! 558: return(cs->sc_size); ! 559: } ! 560: ! 561: cddump(dev) ! 562: { ! 563: return(ENXIO); ! 564: } ! 565: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.