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