Annotation of src/sys/dev/ccd.c, Revision 1.40
1.40 ! thorpej 1: /* $NetBSD: ccd.c,v 1.39 1997/03/12 22:31:37 mycroft Exp $ */
1.11 thorpej 2:
1.28 thorpej 3: /*-
1.38 thorpej 4: * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
1.11 thorpej 5: * All rights reserved.
6: *
1.28 thorpej 7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Jason R. Thorpe.
9: *
1.11 thorpej 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:
1.28 thorpej 20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
1.11 thorpej 25: *
1.28 thorpej 26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
1.11 thorpej 37: */
1.2 cgd 38:
1.1 hpeyerl 39: /*
40: * Copyright (c) 1988 University of Utah.
1.3 hpeyerl 41: * Copyright (c) 1990, 1993
42: * The Regents of the University of California. All rights reserved.
1.1 hpeyerl 43: *
44: * This code is derived from software contributed to Berkeley by
45: * the Systems Programming Group of the University of Utah Computer
46: * Science Department.
47: *
48: * Redistribution and use in source and binary forms, with or without
49: * modification, are permitted provided that the following conditions
50: * are met:
51: * 1. Redistributions of source code must retain the above copyright
52: * notice, this list of conditions and the following disclaimer.
53: * 2. Redistributions in binary form must reproduce the above copyright
54: * notice, this list of conditions and the following disclaimer in the
55: * documentation and/or other materials provided with the distribution.
56: * 3. All advertising materials mentioning features or use of this software
57: * must display the following acknowledgement:
58: * This product includes software developed by the University of
59: * California, Berkeley and its contributors.
60: * 4. Neither the name of the University nor the names of its contributors
61: * may be used to endorse or promote products derived from this software
62: * without specific prior written permission.
63: *
64: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74: * SUCH DAMAGE.
75: *
1.2 cgd 76: * from: Utah $Hdr: cd.c 1.6 90/11/28$
77: *
1.3 hpeyerl 78: * @(#)cd.c 8.2 (Berkeley) 11/16/93
1.1 hpeyerl 79: */
80:
81: /*
82: * "Concatenated" disk driver.
1.11 thorpej 83: *
84: * Dynamic configuration and disklabel support by:
85: * Jason R. Thorpe <thorpej@nas.nasa.gov>
86: * Numerical Aerodynamic Simulation Facility
87: * Mail Stop 258-6
88: * NASA Ames Research Center
89: * Moffett Field, CA 94035
1.24 thorpej 90: *
91: * Mirroring support based on code written by Satoshi Asami
92: * and Nisha Talagala.
1.1 hpeyerl 93: */
94:
95: #include <sys/param.h>
96: #include <sys/systm.h>
1.3 hpeyerl 97: #include <sys/proc.h>
1.1 hpeyerl 98: #include <sys/errno.h>
99: #include <sys/buf.h>
100: #include <sys/malloc.h>
1.11 thorpej 101: #include <sys/namei.h>
1.3 hpeyerl 102: #include <sys/stat.h>
103: #include <sys/ioctl.h>
104: #include <sys/disklabel.h>
1.11 thorpej 105: #include <sys/device.h>
106: #include <sys/disk.h>
107: #include <sys/syslog.h>
1.3 hpeyerl 108: #include <sys/fcntl.h>
1.11 thorpej 109: #include <sys/vnode.h>
1.31 christos 110: #include <sys/conf.h>
1.1 hpeyerl 111:
112: #include <dev/ccdvar.h>
113:
1.11 thorpej 114: #if defined(CCDDEBUG) && !defined(DEBUG)
115: #define DEBUG
116: #endif
117:
1.1 hpeyerl 118: #ifdef DEBUG
1.3 hpeyerl 119: #define CCDB_FOLLOW 0x01
120: #define CCDB_INIT 0x02
121: #define CCDB_IO 0x04
1.11 thorpej 122: #define CCDB_LABEL 0x08
123: #define CCDB_VNODE 0x10
1.24 thorpej 124: int ccddebug = 0x00;
1.1 hpeyerl 125: #endif
126:
1.6 cgd 127: #define ccdunit(x) DISKUNIT(x)
128:
129: struct ccdbuf {
130: struct buf cb_buf; /* new I/O buf */
131: struct buf *cb_obp; /* ptr. to original I/O buf */
132: int cb_unit; /* target unit */
133: int cb_comp; /* target component */
1.24 thorpej 134: int cb_flags; /* misc. flags */
1.38 thorpej 135: LIST_ENTRY(ccdbuf) cb_list; /* entry on freelist */
136: };
1.24 thorpej 137:
1.38 thorpej 138: /* cb_flags */
1.24 thorpej 139: #define CBF_MIRROR 0x01 /* we're for a mirror component */
1.6 cgd 140:
1.38 thorpej 141: /*
142: * Number of freelist buffers per component. Overridable in kernel
143: * config file and patchable.
144: */
145: #ifndef CCDNBUF
146: #define CCDNBUF 8
147: #endif
148: int ccdnbuf = CCDNBUF;
149:
150: /*
151: * XXX Is it OK to wait here?
152: * XXX maybe set up a timeout when we hit some lowater?
153: * XXX --thorpej
154: */
155: #define CCDGETBUF(cs, cbp) do { \
156: (cs)->sc_ngetbuf++; \
157: if (((cbp) = (cs)->sc_freelist.lh_first) != NULL) { \
158: LIST_REMOVE((cbp), cb_list); \
159: (cs)->sc_freecount--; \
160: } else { \
161: (cs)->sc_nmisses++; \
162: MALLOC((cbp), struct ccdbuf *, \
163: sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK); \
164: } \
165: } while (0)
166:
167: #define CCDPUTBUF(cs, cbp) do { \
168: if ((cs)->sc_freecount == (cs)->sc_hiwat) { \
169: FREE((cbp), M_DEVBUF); \
170: } else { \
171: LIST_INSERT_HEAD(&(cs)->sc_freelist, (cbp), cb_list); \
172: (cs)->sc_freecount++; \
173: } \
174: } while (0)
1.1 hpeyerl 175:
1.11 thorpej 176: #define CCDLABELDEV(dev) \
177: (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
1.1 hpeyerl 178:
1.11 thorpej 179: /* called by main() at boot time */
180: void ccdattach __P((int));
181:
182: /* called by biodone() at interrupt time */
1.29 christos 183: void ccdiodone __P((struct buf *));
184: int ccdsize __P((dev_t));
1.11 thorpej 185:
186: static void ccdstart __P((struct ccd_softc *, struct buf *));
187: static void ccdinterleave __P((struct ccd_softc *, int));
188: static void ccdintr __P((struct ccd_softc *, struct buf *));
189: static int ccdinit __P((struct ccddevice *, char **, struct proc *));
190: static int ccdlookup __P((char *, struct proc *p, struct vnode **));
1.24 thorpej 191: static void ccdbuffer __P((struct ccd_softc *, struct buf *,
192: daddr_t, caddr_t, long, struct ccdbuf **));
1.11 thorpej 193: static void ccdgetdisklabel __P((dev_t));
194: static void ccdmakedisklabel __P((struct ccd_softc *));
1.15 thorpej 195: static int ccdlock __P((struct ccd_softc *));
196: static void ccdunlock __P((struct ccd_softc *));
1.3 hpeyerl 197:
1.11 thorpej 198: #ifdef DEBUG
199: static void printiinfo __P((struct ccdiinfo *));
200: #endif
201:
202: /* Non-private for the benefit of libkvm. */
203: struct ccd_softc *ccd_softc;
204: struct ccddevice *ccddevs;
205: int numccd = 0;
1.1 hpeyerl 206:
1.3 hpeyerl 207: /*
1.11 thorpej 208: * Called by main() during pseudo-device attachment. All we need
209: * to do is allocate enough space for devices to be configured later.
1.1 hpeyerl 210: */
211: void
1.3 hpeyerl 212: ccdattach(num)
213: int num;
214: {
1.11 thorpej 215: if (num <= 0) {
216: #ifdef DIAGNOSTIC
217: panic("ccdattach: count <= 0");
218: #endif
1.3 hpeyerl 219: return;
1.11 thorpej 220: }
221:
222: ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
223: M_DEVBUF, M_NOWAIT);
224: ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
225: M_DEVBUF, M_NOWAIT);
226: if ((ccd_softc == NULL) || (ccddevs == NULL)) {
1.35 christos 227: printf("WARNING: no memory for concatenated disks\n");
1.11 thorpej 228: if (ccd_softc != NULL)
229: free(ccd_softc, M_DEVBUF);
230: if (ccddevs != NULL)
231: free(ccddevs, M_DEVBUF);
1.3 hpeyerl 232: return;
233: }
234: numccd = num;
1.11 thorpej 235: bzero(ccd_softc, num * sizeof(struct ccd_softc));
236: bzero(ccddevs, num * sizeof(struct ccddevice));
1.1 hpeyerl 237: }
238:
1.11 thorpej 239: static int
240: ccdinit(ccd, cpaths, p)
1.1 hpeyerl 241: struct ccddevice *ccd;
1.11 thorpej 242: char **cpaths;
243: struct proc *p;
1.1 hpeyerl 244: {
245: register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
1.29 christos 246: register struct ccdcinfo *ci = NULL;
1.1 hpeyerl 247: register size_t size;
248: register int ix;
1.11 thorpej 249: struct vnode *vp;
250: struct vattr va;
1.1 hpeyerl 251: size_t minsize;
1.11 thorpej 252: int maxsecsize;
1.7 cgd 253: struct partinfo dpart;
1.11 thorpej 254: struct ccdgeom *ccg = &cs->sc_geom;
255: char tmppath[MAXPATHLEN];
1.38 thorpej 256: struct ccdbuf *cbp;
1.11 thorpej 257: int error;
1.1 hpeyerl 258:
259: #ifdef DEBUG
1.3 hpeyerl 260: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 261: printf("ccdinit: unit %d\n", ccd->ccd_unit);
1.1 hpeyerl 262: #endif
1.11 thorpej 263:
1.1 hpeyerl 264: cs->sc_size = 0;
265: cs->sc_ileave = ccd->ccd_interleave;
1.11 thorpej 266: cs->sc_nccdisks = ccd->ccd_ndev;
1.35 christos 267: sprintf(cs->sc_xname, "ccd%d", ccd->ccd_unit); /* XXX */
1.11 thorpej 268:
269: /* Allocate space for the component info. */
270: cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
271: M_DEVBUF, M_WAITOK);
272:
1.1 hpeyerl 273: /*
274: * Verify that each component piece exists and record
275: * relevant information about it.
276: */
1.11 thorpej 277: maxsecsize = 0;
1.1 hpeyerl 278: minsize = 0;
1.11 thorpej 279: for (ix = 0; ix < cs->sc_nccdisks; ix++) {
280: vp = ccd->ccd_vpp[ix];
1.1 hpeyerl 281: ci = &cs->sc_cinfo[ix];
1.11 thorpej 282: ci->ci_vp = vp;
283:
284: /*
285: * Copy in the pathname of the component.
286: */
287: bzero(tmppath, sizeof(tmppath)); /* sanity */
1.29 christos 288: error = copyinstr(cpaths[ix], tmppath,
289: MAXPATHLEN, &ci->ci_pathlen);
290: if (error) {
1.11 thorpej 291: #ifdef DEBUG
292: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 293: printf("%s: can't copy path, error = %d\n",
1.23 thorpej 294: cs->sc_xname, error);
1.11 thorpej 295: #endif
296: free(cs->sc_cinfo, M_DEVBUF);
297: return (error);
298: }
299: ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
300: bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
301:
302: /*
303: * XXX: Cache the component's dev_t.
304: */
1.29 christos 305: if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1.11 thorpej 306: #ifdef DEBUG
307: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 308: printf("%s: %s: getattr failed %s = %d\n",
1.23 thorpej 309: cs->sc_xname, ci->ci_path,
1.11 thorpej 310: "error", error);
311: #endif
312: free(ci->ci_path, M_DEVBUF);
313: free(cs->sc_cinfo, M_DEVBUF);
314: return (error);
315: }
316: ci->ci_dev = va.va_rdev;
317:
1.3 hpeyerl 318: /*
1.11 thorpej 319: * Get partition information for the component.
1.3 hpeyerl 320: */
1.29 christos 321: error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
322: FREAD, p->p_ucred, p);
323: if (error) {
1.11 thorpej 324: #ifdef DEBUG
325: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 326: printf("%s: %s: ioctl failed, error = %d\n",
1.23 thorpej 327: cs->sc_xname, ci->ci_path, error);
1.11 thorpej 328: #endif
329: free(ci->ci_path, M_DEVBUF);
330: free(cs->sc_cinfo, M_DEVBUF);
331: return (error);
332: }
333: if (dpart.part->p_fstype == FS_BSDFFS) {
334: maxsecsize =
335: ((dpart.disklab->d_secsize > maxsecsize) ?
336: dpart.disklab->d_secsize : maxsecsize);
337: size = dpart.part->p_size;
338: } else {
339: #ifdef DEBUG
340: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 341: printf("%s: %s: incorrect partition type\n",
1.23 thorpej 342: cs->sc_xname, ci->ci_path);
1.11 thorpej 343: #endif
344: free(ci->ci_path, M_DEVBUF);
345: free(cs->sc_cinfo, M_DEVBUF);
346: return (EFTYPE);
347: }
1.7 cgd 348:
1.11 thorpej 349: /*
350: * Calculate the size, truncating to an interleave
351: * boundary if necessary.
352: */
1.1 hpeyerl 353: if (cs->sc_ileave > 1)
354: size -= size % cs->sc_ileave;
1.11 thorpej 355:
1.1 hpeyerl 356: if (size == 0) {
1.11 thorpej 357: #ifdef DEBUG
358: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 359: printf("%s: %s: size == 0\n",
1.23 thorpej 360: cs->sc_xname, ci->ci_path);
1.11 thorpej 361: #endif
362: free(ci->ci_path, M_DEVBUF);
363: free(cs->sc_cinfo, M_DEVBUF);
364: return (ENODEV);
1.3 hpeyerl 365: }
1.11 thorpej 366:
1.1 hpeyerl 367: if (minsize == 0 || size < minsize)
368: minsize = size;
369: ci->ci_size = size;
370: cs->sc_size += size;
371: }
1.11 thorpej 372:
373: /*
374: * Don't allow the interleave to be smaller than
375: * the biggest component sector.
376: */
377: if ((cs->sc_ileave > 0) &&
378: (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
379: #ifdef DEBUG
380: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 381: printf("%s: interleave must be at least %d\n",
1.23 thorpej 382: cs->sc_xname, (maxsecsize / DEV_BSIZE));
1.11 thorpej 383: #endif
384: free(ci->ci_path, M_DEVBUF);
385: free(cs->sc_cinfo, M_DEVBUF);
386: return (EINVAL);
387: }
388:
1.1 hpeyerl 389: /*
1.24 thorpej 390: * Mirroring support requires uniform interleave and
391: * and even number of components.
392: */
393: if (ccd->ccd_flags & CCDF_MIRROR) {
394: ccd->ccd_flags |= CCDF_UNIFORM;
395: if (cs->sc_ileave == 0) {
396: #ifdef DEBUG
397: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 398: printf("%s: mirroring requires interleave\n",
1.25 thorpej 399: cs->sc_xname);
1.24 thorpej 400: #endif
401: free(ci->ci_path, M_DEVBUF);
402: free(cs->sc_cinfo, M_DEVBUF);
403: return (EINVAL);
404: }
405: if (cs->sc_nccdisks % 2) {
406: #ifdef DEBUG
407: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 408: printf("%s: mirroring requires even # of components\n",
1.24 thorpej 409: cs->sc_xname);
410: #endif
411: free(ci->ci_path, M_DEVBUF);
412: free(cs->sc_cinfo, M_DEVBUF);
413: return (EINVAL);
414: }
415: }
416:
417: /*
1.1 hpeyerl 418: * If uniform interleave is desired set all sizes to that of
419: * the smallest component.
420: */
1.3 hpeyerl 421: if (ccd->ccd_flags & CCDF_UNIFORM) {
1.1 hpeyerl 422: for (ci = cs->sc_cinfo;
423: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
424: ci->ci_size = minsize;
1.24 thorpej 425:
426: if (ccd->ccd_flags & CCDF_MIRROR)
427: cs->sc_size = (cs->sc_nccdisks / 2) * minsize;
428: else
429: cs->sc_size = cs->sc_nccdisks * minsize;
1.1 hpeyerl 430: }
1.11 thorpej 431:
432: /*
433: * Construct the interleave table.
434: */
435: ccdinterleave(cs, ccd->ccd_unit);
436:
1.1 hpeyerl 437: /*
1.11 thorpej 438: * Create pseudo-geometry based on 1MB cylinders. It's
439: * pretty close.
1.1 hpeyerl 440: */
1.11 thorpej 441: ccg->ccg_secsize = DEV_BSIZE;
1.19 thorpej 442: ccg->ccg_ntracks = 1;
1.11 thorpej 443: ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
444: ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
445:
1.38 thorpej 446: /*
447: * Allocate the component buffer header freelist. We allocate
448: * ccdnbuf buffers per component.
449: */
450: LIST_INIT(&cs->sc_freelist);
451: cs->sc_hiwat = cs->sc_nccdisks * ccdnbuf;
452: cs->sc_freecount = cs->sc_hiwat;
453: for (ix = 0; ix < cs->sc_hiwat; ix++) {
454: MALLOC(cbp, struct ccdbuf *, sizeof(struct ccdbuf),
455: M_DEVBUF, M_WAITOK);
456: LIST_INSERT_HEAD(&cs->sc_freelist, cbp, cb_list);
457: }
458:
459: /* Reset statistics. */
460: cs->sc_nmisses = 0;
461: cs->sc_ngetbuf = 0;
462:
1.11 thorpej 463: cs->sc_flags |= CCDF_INITED;
464: cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
465: cs->sc_unit = ccd->ccd_unit;
1.23 thorpej 466:
1.11 thorpej 467: return (0);
1.1 hpeyerl 468: }
469:
1.11 thorpej 470: static void
471: ccdinterleave(cs, unit)
1.1 hpeyerl 472: register struct ccd_softc *cs;
1.11 thorpej 473: int unit;
1.1 hpeyerl 474: {
475: register struct ccdcinfo *ci, *smallci;
476: register struct ccdiinfo *ii;
477: register daddr_t bn, lbn;
478: register int ix;
479: u_long size;
480:
481: #ifdef DEBUG
1.3 hpeyerl 482: if (ccddebug & CCDB_INIT)
1.35 christos 483: printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
1.1 hpeyerl 484: #endif
485: /*
486: * Allocate an interleave table.
487: * Chances are this is too big, but we don't care.
488: */
489: size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
490: cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
491: bzero((caddr_t)cs->sc_itable, size);
1.11 thorpej 492:
1.1 hpeyerl 493: /*
494: * Trivial case: no interleave (actually interleave of disk size).
1.11 thorpej 495: * Each table entry represents a single component in its entirety.
1.1 hpeyerl 496: */
497: if (cs->sc_ileave == 0) {
498: bn = 0;
499: ii = cs->sc_itable;
1.11 thorpej 500:
1.1 hpeyerl 501: for (ix = 0; ix < cs->sc_nccdisks; ix++) {
1.19 thorpej 502: /* Allocate space for ii_index. */
503: ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
1.1 hpeyerl 504: ii->ii_ndisk = 1;
505: ii->ii_startblk = bn;
506: ii->ii_startoff = 0;
507: ii->ii_index[0] = ix;
508: bn += cs->sc_cinfo[ix].ci_size;
509: ii++;
510: }
511: ii->ii_ndisk = 0;
512: #ifdef DEBUG
1.3 hpeyerl 513: if (ccddebug & CCDB_INIT)
1.1 hpeyerl 514: printiinfo(cs->sc_itable);
515: #endif
1.11 thorpej 516: return;
1.1 hpeyerl 517: }
1.11 thorpej 518:
1.1 hpeyerl 519: /*
520: * The following isn't fast or pretty; it doesn't have to be.
521: */
522: size = 0;
523: bn = lbn = 0;
524: for (ii = cs->sc_itable; ; ii++) {
1.11 thorpej 525: /* Allocate space for ii_index. */
1.19 thorpej 526: ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
527: M_DEVBUF, M_WAITOK);
1.11 thorpej 528:
1.1 hpeyerl 529: /*
530: * Locate the smallest of the remaining components
531: */
532: smallci = NULL;
533: for (ci = cs->sc_cinfo;
534: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
535: if (ci->ci_size > size &&
536: (smallci == NULL ||
537: ci->ci_size < smallci->ci_size))
538: smallci = ci;
1.11 thorpej 539:
1.1 hpeyerl 540: /*
541: * Nobody left, all done
542: */
543: if (smallci == NULL) {
544: ii->ii_ndisk = 0;
545: break;
546: }
1.11 thorpej 547:
1.1 hpeyerl 548: /*
549: * Record starting logical block and component offset
550: */
551: ii->ii_startblk = bn / cs->sc_ileave;
552: ii->ii_startoff = lbn;
1.11 thorpej 553:
1.1 hpeyerl 554: /*
555: * Determine how many disks take part in this interleave
556: * and record their indices.
557: */
558: ix = 0;
559: for (ci = cs->sc_cinfo;
560: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
561: if (ci->ci_size >= smallci->ci_size)
562: ii->ii_index[ix++] = ci - cs->sc_cinfo;
563: ii->ii_ndisk = ix;
564: bn += ix * (smallci->ci_size - size);
565: lbn = smallci->ci_size / cs->sc_ileave;
566: size = smallci->ci_size;
567: }
568: #ifdef DEBUG
1.3 hpeyerl 569: if (ccddebug & CCDB_INIT)
1.1 hpeyerl 570: printiinfo(cs->sc_itable);
571: #endif
572: }
573:
1.11 thorpej 574: /* ARGSUSED */
575: int
576: ccdopen(dev, flags, fmt, p)
1.1 hpeyerl 577: dev_t dev;
1.11 thorpej 578: int flags, fmt;
579: struct proc *p;
1.1 hpeyerl 580: {
581: int unit = ccdunit(dev);
1.11 thorpej 582: struct ccd_softc *cs;
583: struct disklabel *lp;
1.15 thorpej 584: int error = 0, part, pmask;
1.1 hpeyerl 585:
586: #ifdef DEBUG
1.3 hpeyerl 587: if (ccddebug & CCDB_FOLLOW)
1.35 christos 588: printf("ccdopen(%x, %x)\n", dev, flags);
1.1 hpeyerl 589: #endif
1.11 thorpej 590: if (unit >= numccd)
591: return (ENXIO);
592: cs = &ccd_softc[unit];
1.15 thorpej 593:
1.29 christos 594: if ((error = ccdlock(cs)) != 0)
1.15 thorpej 595: return (error);
596:
1.23 thorpej 597: lp = cs->sc_dkdev.dk_label;
1.11 thorpej 598:
599: part = DISKPART(dev);
600: pmask = (1 << part);
601:
1.15 thorpej 602: /*
603: * If we're initialized, check to see if there are any other
604: * open partitions. If not, then it's safe to update
605: * the in-core disklabel.
606: */
607: if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
608: ccdgetdisklabel(dev);
609:
1.11 thorpej 610: /* Check that the partition exists. */
1.27 thorpej 611: if (part != RAW_PART) {
612: if (((cs->sc_flags & CCDF_INITED) == 0) ||
1.37 thorpej 613: ((part >= lp->d_npartitions) ||
1.27 thorpej 614: (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
615: error = ENXIO;
616: goto done;
617: }
1.15 thorpej 618: }
1.11 thorpej 619:
620: /* Prevent our unit from being unconfigured while open. */
621: switch (fmt) {
622: case S_IFCHR:
623: cs->sc_dkdev.dk_copenmask |= pmask;
624: break;
625:
626: case S_IFBLK:
627: cs->sc_dkdev.dk_bopenmask |= pmask;
628: break;
629: }
630: cs->sc_dkdev.dk_openmask =
631: cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
632:
1.15 thorpej 633: done:
634: ccdunlock(cs);
1.33 thorpej 635: return (error);
1.7 cgd 636: }
637:
1.11 thorpej 638: /* ARGSUSED */
639: int
640: ccdclose(dev, flags, fmt, p)
1.7 cgd 641: dev_t dev;
1.11 thorpej 642: int flags, fmt;
643: struct proc *p;
1.7 cgd 644: {
1.11 thorpej 645: int unit = ccdunit(dev);
646: struct ccd_softc *cs;
1.15 thorpej 647: int error = 0, part;
1.11 thorpej 648:
1.7 cgd 649: #ifdef DEBUG
650: if (ccddebug & CCDB_FOLLOW)
1.35 christos 651: printf("ccdclose(%x, %x)\n", dev, flags);
1.7 cgd 652: #endif
1.11 thorpej 653:
654: if (unit >= numccd)
655: return (ENXIO);
656: cs = &ccd_softc[unit];
1.15 thorpej 657:
1.29 christos 658: if ((error = ccdlock(cs)) != 0)
1.15 thorpej 659: return (error);
660:
1.11 thorpej 661: part = DISKPART(dev);
662:
663: /* ...that much closer to allowing unconfiguration... */
664: switch (fmt) {
665: case S_IFCHR:
666: cs->sc_dkdev.dk_copenmask &= ~(1 << part);
667: break;
668:
669: case S_IFBLK:
670: cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
671: break;
672: }
673: cs->sc_dkdev.dk_openmask =
674: cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
675:
1.15 thorpej 676: ccdunlock(cs);
1.7 cgd 677: return (0);
1.1 hpeyerl 678: }
679:
1.11 thorpej 680: void
1.1 hpeyerl 681: ccdstrategy(bp)
682: register struct buf *bp;
683: {
684: register int unit = ccdunit(bp->b_dev);
685: register struct ccd_softc *cs = &ccd_softc[unit];
1.29 christos 686: register int s;
1.11 thorpej 687: int wlabel;
1.15 thorpej 688: struct disklabel *lp;
1.1 hpeyerl 689:
690: #ifdef DEBUG
1.3 hpeyerl 691: if (ccddebug & CCDB_FOLLOW)
1.35 christos 692: printf("ccdstrategy(%p): unit %d\n", bp, unit);
1.1 hpeyerl 693: #endif
1.3 hpeyerl 694: if ((cs->sc_flags & CCDF_INITED) == 0) {
1.1 hpeyerl 695: bp->b_error = ENXIO;
696: bp->b_flags |= B_ERROR;
697: goto done;
698: }
1.11 thorpej 699:
700: /* If it's a nil transfer, wake up the top half now. */
701: if (bp->b_bcount == 0)
702: goto done;
703:
1.23 thorpej 704: lp = cs->sc_dkdev.dk_label;
1.15 thorpej 705:
1.11 thorpej 706: /*
1.17 thorpej 707: * Do bounds checking and adjust transfer. If there's an
1.11 thorpej 708: * error, the bounds check will flag that for us.
709: */
710: wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
1.16 thorpej 711: if (DISKPART(bp->b_dev) != RAW_PART)
1.15 thorpej 712: if (bounds_check_with_label(bp, lp, wlabel) <= 0)
1.1 hpeyerl 713: goto done;
1.11 thorpej 714:
1.1 hpeyerl 715: bp->b_resid = bp->b_bcount;
1.11 thorpej 716:
1.1 hpeyerl 717: /*
718: * "Start" the unit.
719: */
720: s = splbio();
1.3 hpeyerl 721: ccdstart(cs, bp);
1.1 hpeyerl 722: splx(s);
723: return;
724: done:
725: biodone(bp);
726: }
727:
1.11 thorpej 728: static void
1.3 hpeyerl 729: ccdstart(cs, bp)
730: register struct ccd_softc *cs;
731: register struct buf *bp;
1.1 hpeyerl 732: {
733: register long bcount, rcount;
1.24 thorpej 734: struct ccdbuf *cbp[4];
1.1 hpeyerl 735: caddr_t addr;
736: daddr_t bn;
1.20 thorpej 737: struct partition *pp;
1.1 hpeyerl 738:
739: #ifdef DEBUG
1.3 hpeyerl 740: if (ccddebug & CCDB_FOLLOW)
1.35 christos 741: printf("ccdstart(%p, %p)\n", cs, bp);
1.1 hpeyerl 742: #endif
1.11 thorpej 743:
1.23 thorpej 744: /* Instrumentation. */
745: disk_busy(&cs->sc_dkdev);
1.11 thorpej 746:
1.1 hpeyerl 747: /*
1.17 thorpej 748: * Translate the partition-relative block number to an absolute.
1.1 hpeyerl 749: */
1.20 thorpej 750: bn = bp->b_blkno;
751: if (DISKPART(bp->b_dev) != RAW_PART) {
1.23 thorpej 752: pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
1.20 thorpej 753: bn += pp->p_offset;
754: }
1.17 thorpej 755:
756: /*
757: * Allocate component buffers and fire off the requests
758: */
1.3 hpeyerl 759: addr = bp->b_data;
1.1 hpeyerl 760: for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
1.24 thorpej 761: ccdbuffer(cs, bp, bn, addr, bcount, cbp);
762: rcount = cbp[0]->cb_buf.b_bcount;
763: if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
764: cbp[0]->cb_buf.b_vp->v_numoutput++;
765: VOP_STRATEGY(&cbp[0]->cb_buf);
766:
767: /*
768: * Mirror requires additional write.
769: */
770: if ((cs->sc_cflags & CCDF_MIRROR) &&
771: ((cbp[0]->cb_buf.b_flags & B_READ) == 0)) {
772: cbp[1]->cb_buf.b_vp->v_numoutput++;
773: VOP_STRATEGY(&cbp[1]->cb_buf);
774: }
775:
1.1 hpeyerl 776: bn += btodb(rcount);
777: addr += rcount;
778: }
779: }
780:
781: /*
782: * Build a component buffer header.
783: */
1.24 thorpej 784: static void
785: ccdbuffer(cs, bp, bn, addr, bcount, cbpp)
1.1 hpeyerl 786: register struct ccd_softc *cs;
787: struct buf *bp;
788: daddr_t bn;
789: caddr_t addr;
790: long bcount;
1.24 thorpej 791: struct ccdbuf **cbpp;
1.1 hpeyerl 792: {
1.29 christos 793: register struct ccdcinfo *ci, *ci2 = NULL;
1.6 cgd 794: register struct ccdbuf *cbp;
1.1 hpeyerl 795: register daddr_t cbn, cboff;
1.36 thorpej 796: int ccdisk;
1.1 hpeyerl 797:
798: #ifdef DEBUG
1.3 hpeyerl 799: if (ccddebug & CCDB_IO)
1.35 christos 800: printf("ccdbuffer(%p, %p, %d, %p, %ld)\n",
1.1 hpeyerl 801: cs, bp, bn, addr, bcount);
802: #endif
803: /*
804: * Determine which component bn falls in.
805: */
806: cbn = bn;
807: cboff = 0;
1.11 thorpej 808:
1.1 hpeyerl 809: /*
810: * Serially concatenated
811: */
812: if (cs->sc_ileave == 0) {
813: register daddr_t sblk;
814:
815: sblk = 0;
1.36 thorpej 816: for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
817: cbn >= sblk + ci->ci_size;
818: ccdisk++, ci = &cs->sc_cinfo[ccdisk])
1.1 hpeyerl 819: sblk += ci->ci_size;
820: cbn -= sblk;
821: }
822: /*
823: * Interleaved
824: */
825: else {
826: register struct ccdiinfo *ii;
1.36 thorpej 827: int off;
1.1 hpeyerl 828:
829: cboff = cbn % cs->sc_ileave;
830: cbn /= cs->sc_ileave;
831: for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
832: if (ii->ii_startblk > cbn)
833: break;
834: ii--;
835: off = cbn - ii->ii_startblk;
836: if (ii->ii_ndisk == 1) {
837: ccdisk = ii->ii_index[0];
838: cbn = ii->ii_startoff + off;
839: } else {
1.24 thorpej 840: if (cs->sc_cflags & CCDF_MIRROR) {
841: ccdisk =
842: ii->ii_index[off % (ii->ii_ndisk / 2)];
843: cbn = ii->ii_startoff +
844: (off / (ii->ii_ndisk / 2));
845: /* Mirrored data */
846: ci2 =
847: &cs->sc_cinfo[ccdisk + (ii->ii_ndisk / 2)];
848: } else {
849: /* Normal case. */
850: ccdisk = ii->ii_index[off % ii->ii_ndisk];
851: cbn = ii->ii_startoff + off / ii->ii_ndisk;
852: }
1.1 hpeyerl 853: }
854: cbn *= cs->sc_ileave;
855: ci = &cs->sc_cinfo[ccdisk];
856: }
1.11 thorpej 857:
1.1 hpeyerl 858: /*
859: * Fill in the component buf structure.
860: */
1.38 thorpej 861: CCDGETBUF(cs, cbp);
1.24 thorpej 862: cbp->cb_flags = 0;
1.6 cgd 863: cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
1.29 christos 864: cbp->cb_buf.b_iodone = ccdiodone;
1.6 cgd 865: cbp->cb_buf.b_proc = bp->b_proc;
1.11 thorpej 866: cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */
1.6 cgd 867: cbp->cb_buf.b_blkno = cbn + cboff;
868: cbp->cb_buf.b_data = addr;
1.11 thorpej 869: cbp->cb_buf.b_vp = ci->ci_vp;
1.1 hpeyerl 870: if (cs->sc_ileave == 0)
1.6 cgd 871: cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn);
1.1 hpeyerl 872: else
1.6 cgd 873: cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff);
874: if (cbp->cb_buf.b_bcount > bcount)
875: cbp->cb_buf.b_bcount = bcount;
876:
1.1 hpeyerl 877: /*
1.6 cgd 878: * context for ccdiodone
1.1 hpeyerl 879: */
1.6 cgd 880: cbp->cb_obp = bp;
1.36 thorpej 881: cbp->cb_unit = cs->sc_unit;
882: cbp->cb_comp = ccdisk;
1.6 cgd 883:
1.24 thorpej 884: /* First buffer is dealt with. */
885: cbpp[0] = cbp;
886:
1.1 hpeyerl 887: #ifdef DEBUG
1.3 hpeyerl 888: if (ccddebug & CCDB_IO)
1.35 christos 889: printf(" dev %x(u%d): cbp %p bn %d addr %p bcnt %ld\n",
1.34 christos 890: ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
891: cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1.1 hpeyerl 892: #endif
1.24 thorpej 893:
894: /*
895: * Mirrors have an additional write operation that is nearly
896: * identical to the first.
897: */
898: if ((cs->sc_cflags & CCDF_MIRROR) &&
899: ((cbp->cb_buf.b_flags & B_READ) == 0)) {
1.38 thorpej 900: CCDGETBUF(cs, cbp);
1.24 thorpej 901: *cbp = *cbpp[0];
902: cbp->cb_flags = CBF_MIRROR;
903: cbp->cb_buf.b_dev = ci2->ci_dev; /* XXX */
904: cbp->cb_buf.b_vp = ci2->ci_vp;
905: cbp->cb_comp = ci2 - cs->sc_cinfo;
906: cbpp[1] = cbp;
907: }
1.1 hpeyerl 908: }
909:
1.11 thorpej 910: static void
1.3 hpeyerl 911: ccdintr(cs, bp)
912: register struct ccd_softc *cs;
913: register struct buf *bp;
1.1 hpeyerl 914: {
915:
916: #ifdef DEBUG
1.3 hpeyerl 917: if (ccddebug & CCDB_FOLLOW)
1.35 christos 918: printf("ccdintr(%p, %p)\n", cs, bp);
1.1 hpeyerl 919: #endif
920: /*
921: * Request is done for better or worse, wakeup the top half.
922: */
923: if (bp->b_flags & B_ERROR)
924: bp->b_resid = bp->b_bcount;
1.23 thorpej 925: disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid));
1.1 hpeyerl 926: biodone(bp);
927: }
928:
929: /*
1.11 thorpej 930: * Called at interrupt time.
1.1 hpeyerl 931: * Mark the component as done and if all components are done,
932: * take a ccd interrupt.
933: */
1.3 hpeyerl 934: void
1.29 christos 935: ccdiodone(vbp)
936: struct buf *vbp;
1.1 hpeyerl 937: {
1.29 christos 938: struct ccdbuf *cbp = (struct ccdbuf *) vbp;
1.6 cgd 939: register struct buf *bp = cbp->cb_obp;
940: register int unit = cbp->cb_unit;
1.23 thorpej 941: struct ccd_softc *cs = &ccd_softc[unit];
1.24 thorpej 942: int count, cbflags, s;
943: char *comptype;
1.1 hpeyerl 944:
945: s = splbio();
946: #ifdef DEBUG
1.3 hpeyerl 947: if (ccddebug & CCDB_FOLLOW)
1.35 christos 948: printf("ccdiodone(%p)\n", cbp);
1.3 hpeyerl 949: if (ccddebug & CCDB_IO) {
1.24 thorpej 950: if (cbp->cb_flags & CBF_MIRROR)
1.35 christos 951: printf("ccdiodone: mirror component\n");
1.24 thorpej 952: else
1.35 christos 953: printf("ccdiodone: bp %p bcount %ld resid %ld\n",
1.24 thorpej 954: bp, bp->b_bcount, bp->b_resid);
1.35 christos 955: printf(" dev %x(u%d), cbp %p bn %d addr %p bcnt %ld\n",
1.6 cgd 956: cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
957: cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
958: cbp->cb_buf.b_bcount);
1.1 hpeyerl 959: }
960: #endif
961:
1.6 cgd 962: if (cbp->cb_buf.b_flags & B_ERROR) {
1.24 thorpej 963: if (cbp->cb_flags & CBF_MIRROR)
964: comptype = " (mirror)";
965: else {
966: bp->b_flags |= B_ERROR;
967: bp->b_error = cbp->cb_buf.b_error ?
968: cbp->cb_buf.b_error : EIO;
969: comptype = "";
970: }
971:
1.35 christos 972: printf("%s: error %d on component %d%s\n",
1.24 thorpej 973: cs->sc_xname, bp->b_error, cbp->cb_comp, comptype);
1.1 hpeyerl 974: }
1.6 cgd 975: count = cbp->cb_buf.b_bcount;
1.24 thorpej 976: cbflags = cbp->cb_flags;
1.38 thorpej 977: CCDPUTBUF(cs, cbp);
1.1 hpeyerl 978:
979: /*
980: * If all done, "interrupt".
1.24 thorpej 981: *
982: * Note that mirror component buffers aren't counted against
983: * the original I/O buffer.
984: */
985: if ((cbflags & CBF_MIRROR) == 0) {
986: bp->b_resid -= count;
987: if (bp->b_resid < 0)
988: panic("ccdiodone: count");
989: if (bp->b_resid == 0)
990: ccdintr(&ccd_softc[unit], bp);
991: }
1.1 hpeyerl 992: splx(s);
993: }
994:
1.11 thorpej 995: /* ARGSUSED */
1.10 mycroft 996: int
1.11 thorpej 997: ccdread(dev, uio, flags)
1.3 hpeyerl 998: dev_t dev;
999: struct uio *uio;
1.11 thorpej 1000: int flags;
1.3 hpeyerl 1001: {
1.11 thorpej 1002: int unit = ccdunit(dev);
1003: struct ccd_softc *cs;
1.3 hpeyerl 1004:
1005: #ifdef DEBUG
1006: if (ccddebug & CCDB_FOLLOW)
1.35 christos 1007: printf("ccdread(%x, %p)\n", dev, uio);
1.3 hpeyerl 1008: #endif
1.11 thorpej 1009: if (unit >= numccd)
1010: return (ENXIO);
1011: cs = &ccd_softc[unit];
1012:
1013: if ((cs->sc_flags & CCDF_INITED) == 0)
1014: return (ENXIO);
1015:
1016: /*
1017: * XXX: It's not clear that using minphys() is completely safe,
1018: * in particular, for raw I/O. Underlying devices might have some
1019: * non-obvious limits, because of the copy to user-space.
1020: */
1.10 mycroft 1021: return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
1.3 hpeyerl 1022: }
1023:
1.11 thorpej 1024: /* ARGSUSED */
1.10 mycroft 1025: int
1.11 thorpej 1026: ccdwrite(dev, uio, flags)
1.3 hpeyerl 1027: dev_t dev;
1028: struct uio *uio;
1.11 thorpej 1029: int flags;
1.3 hpeyerl 1030: {
1.11 thorpej 1031: int unit = ccdunit(dev);
1032: struct ccd_softc *cs;
1.3 hpeyerl 1033:
1034: #ifdef DEBUG
1035: if (ccddebug & CCDB_FOLLOW)
1.35 christos 1036: printf("ccdwrite(%x, %p)\n", dev, uio);
1.3 hpeyerl 1037: #endif
1.11 thorpej 1038: if (unit >= numccd)
1039: return (ENXIO);
1040: cs = &ccd_softc[unit];
1041:
1042: if ((cs->sc_flags & CCDF_INITED) == 0)
1043: return (ENXIO);
1044:
1045: /*
1046: * XXX: It's not clear that using minphys() is completely safe,
1047: * in particular, for raw I/O. Underlying devices might have some
1048: * non-obvious limits, because of the copy to user-space.
1049: */
1.10 mycroft 1050: return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
1.3 hpeyerl 1051: }
1052:
1.11 thorpej 1053: int
1054: ccdioctl(dev, cmd, data, flag, p)
1.1 hpeyerl 1055: dev_t dev;
1.5 cgd 1056: u_long cmd;
1.1 hpeyerl 1057: caddr_t data;
1058: int flag;
1.11 thorpej 1059: struct proc *p;
1.1 hpeyerl 1060: {
1.11 thorpej 1061: int unit = ccdunit(dev);
1062: int i, j, lookedup = 0, error = 0;
1.39 mycroft 1063: int part, pmask;
1.11 thorpej 1064: struct ccd_softc *cs;
1065: struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1066: struct ccddevice ccd;
1.38 thorpej 1067: struct ccdbuf *cbp;
1.11 thorpej 1068: char **cpp;
1069: struct vnode **vpp;
1070:
1071: if (unit >= numccd)
1072: return (ENXIO);
1073: cs = &ccd_softc[unit];
1074:
1075: bzero(&ccd, sizeof(ccd));
1076:
1077: switch (cmd) {
1078: case CCDIOCSET:
1079: if (cs->sc_flags & CCDF_INITED)
1080: return (EBUSY);
1081:
1082: if ((flag & FWRITE) == 0)
1083: return (EBADF);
1084:
1.29 christos 1085: if ((error = ccdlock(cs)) != 0)
1.15 thorpej 1086: return (error);
1087:
1.11 thorpej 1088: /* Fill in some important bits. */
1089: ccd.ccd_unit = unit;
1090: ccd.ccd_interleave = ccio->ccio_ileave;
1091: ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1092:
1093: /*
1094: * Allocate space for and copy in the array of
1095: * componet pathnames and device numbers.
1096: */
1097: cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1098: M_DEVBUF, M_WAITOK);
1099: vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1100: M_DEVBUF, M_WAITOK);
1101:
1102: error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1103: ccio->ccio_ndisks * sizeof(char **));
1104: if (error) {
1105: free(vpp, M_DEVBUF);
1106: free(cpp, M_DEVBUF);
1.15 thorpej 1107: ccdunlock(cs);
1.11 thorpej 1108: return (error);
1109: }
1110:
1111: #ifdef DEBUG
1112: if (ccddebug & CCDB_INIT)
1113: for (i = 0; i < ccio->ccio_ndisks; ++i)
1.35 christos 1114: printf("ccdioctl: component %d: 0x%p\n",
1.11 thorpej 1115: i, cpp[i]);
1116: #endif
1117:
1118: for (i = 0; i < ccio->ccio_ndisks; ++i) {
1119: #ifdef DEBUG
1120: if (ccddebug & CCDB_INIT)
1.35 christos 1121: printf("ccdioctl: lookedup = %d\n", lookedup);
1.11 thorpej 1122: #endif
1.29 christos 1123: if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1.11 thorpej 1124: for (j = 0; j < lookedup; ++j)
1.12 thorpej 1125: (void)vn_close(vpp[j], FREAD|FWRITE,
1.11 thorpej 1126: p->p_ucred, p);
1127: free(vpp, M_DEVBUF);
1128: free(cpp, M_DEVBUF);
1.15 thorpej 1129: ccdunlock(cs);
1.11 thorpej 1130: return (error);
1131: }
1132: ++lookedup;
1133: }
1134: ccd.ccd_cpp = cpp;
1135: ccd.ccd_vpp = vpp;
1136: ccd.ccd_ndev = ccio->ccio_ndisks;
1137:
1138: /*
1139: * Initialize the ccd. Fills in the softc for us.
1140: */
1.29 christos 1141: if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1.11 thorpej 1142: for (j = 0; j < lookedup; ++j)
1.18 thorpej 1143: (void)vn_close(vpp[j], FREAD|FWRITE,
1.11 thorpej 1144: p->p_ucred, p);
1145: bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1146: free(vpp, M_DEVBUF);
1147: free(cpp, M_DEVBUF);
1.15 thorpej 1148: ccdunlock(cs);
1.11 thorpej 1149: return (error);
1150: }
1151:
1152: /*
1153: * The ccd has been successfully initialized, so
1.23 thorpej 1154: * we can place it into the array. Don't try to
1155: * read the disklabel until the disk has been attached,
1156: * because space for the disklabel is allocated
1157: * in disk_attach();
1.11 thorpej 1158: */
1159: bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1160: ccio->ccio_unit = unit;
1161: ccio->ccio_size = cs->sc_size;
1.23 thorpej 1162:
1163: /* Attach the disk. */
1164: cs->sc_dkdev.dk_name = cs->sc_xname;
1165: disk_attach(&cs->sc_dkdev);
1166:
1167: /* Try and read the disklabel. */
1.11 thorpej 1168: ccdgetdisklabel(dev);
1169:
1.15 thorpej 1170: ccdunlock(cs);
1171:
1.11 thorpej 1172: break;
1173:
1174: case CCDIOCCLR:
1175: if ((cs->sc_flags & CCDF_INITED) == 0)
1176: return (ENXIO);
1177:
1178: if ((flag & FWRITE) == 0)
1179: return (EBADF);
1180:
1.29 christos 1181: if ((error = ccdlock(cs)) != 0)
1.15 thorpej 1182: return (error);
1183:
1.11 thorpej 1184: /*
1185: * Don't unconfigure if any other partitions are open
1186: * or if both the character and block flavors of this
1187: * partition are open.
1188: */
1189: part = DISKPART(dev);
1190: pmask = (1 << part);
1191: if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1192: ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1.15 thorpej 1193: (cs->sc_dkdev.dk_copenmask & pmask))) {
1194: ccdunlock(cs);
1.11 thorpej 1195: return (EBUSY);
1.15 thorpej 1196: }
1.11 thorpej 1197:
1198: /*
1199: * Free ccd_softc information and clear entry.
1200: */
1.22 thorpej 1201:
1202: /* Close the components and free their pathnames. */
1.11 thorpej 1203: for (i = 0; i < cs->sc_nccdisks; ++i) {
1204: /*
1205: * XXX: this close could potentially fail and
1206: * cause Bad Things. Maybe we need to force
1207: * the close to happen?
1208: */
1209: #ifdef DEBUG
1210: if (ccddebug & CCDB_VNODE)
1211: vprint("CCDIOCCLR: vnode info",
1212: cs->sc_cinfo[i].ci_vp);
1213: #endif
1214: (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1215: p->p_ucred, p);
1216: free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1.38 thorpej 1217: }
1218:
1219: /* Free component buffer freelist. */
1220: while ((cbp = cs->sc_freelist.lh_first) != NULL) {
1221: LIST_REMOVE(cbp, cb_list);
1222: FREE(cbp, M_DEVBUF);
1.22 thorpej 1223: }
1224:
1225: /* Free interleave index. */
1226: for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1.19 thorpej 1227: free(cs->sc_itable[i].ii_index, M_DEVBUF);
1.22 thorpej 1228:
1229: /* Free component info and interleave table. */
1.11 thorpej 1230: free(cs->sc_cinfo, M_DEVBUF);
1231: free(cs->sc_itable, M_DEVBUF);
1.21 thorpej 1232: cs->sc_flags &= ~CCDF_INITED;
1.11 thorpej 1233:
1234: /*
1235: * Free ccddevice information and clear entry.
1236: */
1237: free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1238: free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1239: bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1.15 thorpej 1240:
1.23 thorpej 1241: /* Detatch the disk. */
1.26 hpeyerl 1242: disk_detach(&cs->sc_dkdev);
1.23 thorpej 1243:
1.15 thorpej 1244: ccdunlock(cs);
1245:
1.11 thorpej 1246: break;
1247:
1248: case DIOCGDINFO:
1249: if ((cs->sc_flags & CCDF_INITED) == 0)
1250: return (ENXIO);
1251:
1.23 thorpej 1252: *(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
1.11 thorpej 1253: break;
1254:
1255: case DIOCGPART:
1256: if ((cs->sc_flags & CCDF_INITED) == 0)
1257: return (ENXIO);
1258:
1.23 thorpej 1259: ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
1.11 thorpej 1260: ((struct partinfo *)data)->part =
1.23 thorpej 1261: &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
1.11 thorpej 1262: break;
1263:
1264: case DIOCWDINFO:
1265: case DIOCSDINFO:
1266: if ((cs->sc_flags & CCDF_INITED) == 0)
1267: return (ENXIO);
1268:
1269: if ((flag & FWRITE) == 0)
1270: return (EBADF);
1271:
1.29 christos 1272: if ((error = ccdlock(cs)) != 0)
1.15 thorpej 1273: return (error);
1274:
1.11 thorpej 1275: cs->sc_flags |= CCDF_LABELLING;
1276:
1.23 thorpej 1277: error = setdisklabel(cs->sc_dkdev.dk_label,
1278: (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel);
1.11 thorpej 1279: if (error == 0) {
1280: if (cmd == DIOCWDINFO)
1281: error = writedisklabel(CCDLABELDEV(dev),
1.23 thorpej 1282: ccdstrategy, cs->sc_dkdev.dk_label,
1283: cs->sc_dkdev.dk_cpulabel);
1.11 thorpej 1284: }
1285:
1286: cs->sc_flags &= ~CCDF_LABELLING;
1287:
1.15 thorpej 1288: ccdunlock(cs);
1289:
1.11 thorpej 1290: if (error)
1291: return (error);
1292: break;
1293:
1294: case DIOCWLABEL:
1295: if ((cs->sc_flags & CCDF_INITED) == 0)
1296: return (ENXIO);
1297:
1298: if ((flag & FWRITE) == 0)
1299: return (EBADF);
1300: if (*(int *)data != 0)
1301: cs->sc_flags |= CCDF_WLABEL;
1302: else
1303: cs->sc_flags &= ~CCDF_WLABEL;
1304: break;
1305:
1306: default:
1307: return (ENOTTY);
1308: }
1309:
1310: return (0);
1.1 hpeyerl 1311: }
1312:
1.11 thorpej 1313: int
1.1 hpeyerl 1314: ccdsize(dev)
1315: dev_t dev;
1316: {
1.11 thorpej 1317: struct ccd_softc *cs;
1.40 ! thorpej 1318: struct disklabel *lp;
! 1319: int part, unit, omask, size;
! 1320:
! 1321: unit = ccdunit(dev);
! 1322: if (unit >= numccd)
! 1323: return (-1);
! 1324: cs = &ccd_softc[unit];
1.11 thorpej 1325:
1.40 ! thorpej 1326: if ((cs->sc_flags & CCDF_INITED) == 0)
1.11 thorpej 1327: return (-1);
1328:
1329: part = DISKPART(dev);
1.40 ! thorpej 1330: omask = cs->sc_dkdev.dk_openmask & (1 << part);
! 1331: lp = cs->sc_dkdev.dk_label;
1.11 thorpej 1332:
1.40 ! thorpej 1333: if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc))
1.11 thorpej 1334: return (-1);
1335:
1.40 ! thorpej 1336: if (lp->d_partitions[part].p_fstype != FS_SWAP)
1.11 thorpej 1337: size = -1;
1338: else
1.40 ! thorpej 1339: size = lp->d_partitions[part].p_size *
! 1340: (lp->d_secsize / DEV_BSIZE);
1.11 thorpej 1341:
1.40 ! thorpej 1342: if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc))
1.11 thorpej 1343: return (-1);
1.1 hpeyerl 1344:
1.11 thorpej 1345: return (size);
1.1 hpeyerl 1346: }
1347:
1.9 cgd 1348: int
1349: ccddump(dev, blkno, va, size)
1350: dev_t dev;
1351: daddr_t blkno;
1352: caddr_t va;
1353: size_t size;
1.1 hpeyerl 1354: {
1.9 cgd 1355:
1356: /* Not implemented. */
1357: return ENXIO;
1.11 thorpej 1358: }
1359:
1360: /*
1361: * Lookup the provided name in the filesystem. If the file exists,
1362: * is a valid block device, and isn't being used by anyone else,
1363: * set *vpp to the file's vnode.
1364: */
1365: static int
1366: ccdlookup(path, p, vpp)
1367: char *path;
1368: struct proc *p;
1369: struct vnode **vpp; /* result */
1370: {
1371: struct nameidata nd;
1372: struct vnode *vp;
1373: struct vattr va;
1374: int error;
1375:
1376: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1.29 christos 1377: if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1.11 thorpej 1378: #ifdef DEBUG
1.29 christos 1379: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 1380: printf("ccdlookup: vn_open error = %d\n", error);
1.11 thorpej 1381: #endif
1382: return (error);
1383: }
1384: vp = nd.ni_vp;
1385:
1386: if (vp->v_usecount > 1) {
1387: VOP_UNLOCK(vp);
1388: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1389: return (EBUSY);
1390: }
1391:
1.29 christos 1392: if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1.11 thorpej 1393: #ifdef DEBUG
1.29 christos 1394: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 1395: printf("ccdlookup: getattr error = %d\n", error);
1.11 thorpej 1396: #endif
1397: VOP_UNLOCK(vp);
1398: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1399: return (error);
1400: }
1401:
1402: /* XXX: eventually we should handle VREG, too. */
1403: if (va.va_type != VBLK) {
1404: VOP_UNLOCK(vp);
1405: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1406: return (ENOTBLK);
1407: }
1408:
1409: #ifdef DEBUG
1410: if (ccddebug & CCDB_VNODE)
1411: vprint("ccdlookup: vnode info", vp);
1412: #endif
1413:
1414: VOP_UNLOCK(vp);
1415: *vpp = vp;
1416: return (0);
1417: }
1418:
1419: /*
1420: * Read the disklabel from the ccd. If one is not present, fake one
1421: * up.
1422: */
1423: static void
1424: ccdgetdisklabel(dev)
1425: dev_t dev;
1426: {
1427: int unit = ccdunit(dev);
1428: struct ccd_softc *cs = &ccd_softc[unit];
1429: char *errstring;
1.23 thorpej 1430: struct disklabel *lp = cs->sc_dkdev.dk_label;
1431: struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
1.11 thorpej 1432: struct ccdgeom *ccg = &cs->sc_geom;
1433:
1434: bzero(lp, sizeof(*lp));
1435: bzero(clp, sizeof(*clp));
1436:
1437: lp->d_secperunit = cs->sc_size;
1438: lp->d_secsize = ccg->ccg_secsize;
1439: lp->d_nsectors = ccg->ccg_nsectors;
1440: lp->d_ntracks = ccg->ccg_ntracks;
1441: lp->d_ncylinders = ccg->ccg_ncylinders;
1.19 thorpej 1442: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1.11 thorpej 1443:
1444: strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1445: lp->d_type = DTYPE_CCD;
1446: strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1447: lp->d_rpm = 3600;
1448: lp->d_interleave = 1;
1449: lp->d_flags = 0;
1450:
1451: lp->d_partitions[RAW_PART].p_offset = 0;
1452: lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1453: lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1454: lp->d_npartitions = RAW_PART + 1;
1455:
1456: lp->d_magic = DISKMAGIC;
1457: lp->d_magic2 = DISKMAGIC;
1.23 thorpej 1458: lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
1.11 thorpej 1459:
1460: /*
1461: * Call the generic disklabel extraction routine.
1462: */
1.29 christos 1463: errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1464: cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
1465: if (errstring)
1.11 thorpej 1466: ccdmakedisklabel(cs);
1467:
1468: #ifdef DEBUG
1469: /* It's actually extremely common to have unlabeled ccds. */
1470: if (ccddebug & CCDB_LABEL)
1471: if (errstring != NULL)
1.35 christos 1472: printf("%s: %s\n", cs->sc_xname, errstring);
1.11 thorpej 1473: #endif
1474: }
1475:
1476: /*
1477: * Take care of things one might want to take care of in the event
1478: * that a disklabel isn't present.
1479: */
1480: static void
1481: ccdmakedisklabel(cs)
1482: struct ccd_softc *cs;
1483: {
1.23 thorpej 1484: struct disklabel *lp = cs->sc_dkdev.dk_label;
1.11 thorpej 1485:
1486: /*
1487: * For historical reasons, if there's no disklabel present
1488: * the raw partition must be marked FS_BSDFFS.
1489: */
1490: lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1491:
1492: strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1.15 thorpej 1493: }
1494:
1495: /*
1496: * Wait interruptibly for an exclusive lock.
1497: *
1498: * XXX
1499: * Several drivers do this; it should be abstracted and made MP-safe.
1500: */
1501: static int
1502: ccdlock(cs)
1503: struct ccd_softc *cs;
1504: {
1505: int error;
1506:
1507: while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1508: cs->sc_flags |= CCDF_WANTED;
1509: if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1510: return (error);
1511: }
1512: cs->sc_flags |= CCDF_LOCKED;
1513: return (0);
1514: }
1515:
1516: /*
1517: * Unlock and wake up any waiters.
1518: */
1519: static void
1520: ccdunlock(cs)
1521: struct ccd_softc *cs;
1522: {
1523:
1524: cs->sc_flags &= ~CCDF_LOCKED;
1525: if ((cs->sc_flags & CCDF_WANTED) != 0) {
1526: cs->sc_flags &= ~CCDF_WANTED;
1527: wakeup(cs);
1528: }
1.11 thorpej 1529: }
1530:
1531: #ifdef DEBUG
1532: static void
1533: printiinfo(ii)
1534: struct ccdiinfo *ii;
1535: {
1536: register int ix, i;
1537:
1538: for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1.35 christos 1539: printf(" itab[%d]: #dk %d sblk %d soff %d",
1.34 christos 1540: ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1.11 thorpej 1541: for (i = 0; i < ii->ii_ndisk; i++)
1.35 christos 1542: printf(" %d", ii->ii_index[i]);
1543: printf("\n");
1.11 thorpej 1544: }
1.1 hpeyerl 1545: }
1546: #endif
CVSweb <webmaster@jp.NetBSD.org>