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