|
|
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.