Annotation of src/sys/dev/ccd.c, Revision 1.72.2.3
1.72.2.3! jdolecek 1: /* $NetBSD: ccd.c,v 1.72.2.2 2002/01/10 19:52:45 thorpej Exp $ */
1.11 thorpej 2:
1.28 thorpej 3: /*-
1.59 thorpej 4: * Copyright (c) 1996, 1997, 1998, 1999 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
1.45 jtc 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1.28 thorpej 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.1 hpeyerl 90: */
1.72.2.2 thorpej 91:
92: #include <sys/cdefs.h>
1.72.2.3! jdolecek 93: __KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.72.2.2 2002/01/10 19:52:45 thorpej Exp $");
1.1 hpeyerl 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.63 thorpej 101: #include <sys/pool.h>
1.11 thorpej 102: #include <sys/namei.h>
1.3 hpeyerl 103: #include <sys/stat.h>
104: #include <sys/ioctl.h>
105: #include <sys/disklabel.h>
1.11 thorpej 106: #include <sys/device.h>
107: #include <sys/disk.h>
108: #include <sys/syslog.h>
1.3 hpeyerl 109: #include <sys/fcntl.h>
1.11 thorpej 110: #include <sys/vnode.h>
1.31 christos 111: #include <sys/conf.h>
1.57 thorpej 112: #include <sys/lock.h>
1.56 thorpej 113: #include <sys/queue.h>
1.1 hpeyerl 114:
115: #include <dev/ccdvar.h>
116:
1.11 thorpej 117: #if defined(CCDDEBUG) && !defined(DEBUG)
118: #define DEBUG
119: #endif
120:
1.1 hpeyerl 121: #ifdef DEBUG
1.3 hpeyerl 122: #define CCDB_FOLLOW 0x01
123: #define CCDB_INIT 0x02
124: #define CCDB_IO 0x04
1.11 thorpej 125: #define CCDB_LABEL 0x08
126: #define CCDB_VNODE 0x10
1.24 thorpej 127: int ccddebug = 0x00;
1.1 hpeyerl 128: #endif
129:
1.6 cgd 130: #define ccdunit(x) DISKUNIT(x)
131:
132: struct ccdbuf {
133: struct buf cb_buf; /* new I/O buf */
134: struct buf *cb_obp; /* ptr. to original I/O buf */
1.59 thorpej 135: struct ccd_softc *cb_sc; /* pointer to ccd softc */
1.6 cgd 136: int cb_comp; /* target component */
1.56 thorpej 137: SIMPLEQ_ENTRY(ccdbuf) cb_q; /* fifo of component buffers */
1.38 thorpej 138: };
1.24 thorpej 139:
1.63 thorpej 140: /* component buffer pool */
141: struct pool ccd_cbufpool;
142:
143: #define CCD_GETBUF() pool_get(&ccd_cbufpool, PR_NOWAIT)
144: #define CCD_PUTBUF(cbp) pool_put(&ccd_cbufpool, cbp)
1.1 hpeyerl 145:
1.11 thorpej 146: #define CCDLABELDEV(dev) \
147: (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
1.1 hpeyerl 148:
1.11 thorpej 149: /* called by main() at boot time */
150: void ccdattach __P((int));
151:
152: /* called by biodone() at interrupt time */
1.29 christos 153: void ccdiodone __P((struct buf *));
154: int ccdsize __P((dev_t));
1.11 thorpej 155:
156: static void ccdstart __P((struct ccd_softc *, struct buf *));
1.57 thorpej 157: static void ccdinterleave __P((struct ccd_softc *));
1.11 thorpej 158: static void ccdintr __P((struct ccd_softc *, struct buf *));
1.57 thorpej 159: static int ccdinit __P((struct ccd_softc *, char **, struct vnode **,
160: struct proc *));
1.11 thorpej 161: static int ccdlookup __P((char *, struct proc *p, struct vnode **));
1.55 thorpej 162: static struct ccdbuf *ccdbuffer __P((struct ccd_softc *, struct buf *,
163: daddr_t, caddr_t, long));
1.44 thorpej 164: static void ccdgetdefaultlabel __P((struct ccd_softc *, struct disklabel *));
1.11 thorpej 165: static void ccdgetdisklabel __P((dev_t));
166: static void ccdmakedisklabel __P((struct ccd_softc *));
1.3 hpeyerl 167:
1.11 thorpej 168: #ifdef DEBUG
169: static void printiinfo __P((struct ccdiinfo *));
170: #endif
171:
172: /* Non-private for the benefit of libkvm. */
173: struct ccd_softc *ccd_softc;
174: int numccd = 0;
1.1 hpeyerl 175:
1.3 hpeyerl 176: /*
1.11 thorpej 177: * Called by main() during pseudo-device attachment. All we need
178: * to do is allocate enough space for devices to be configured later.
1.1 hpeyerl 179: */
180: void
1.3 hpeyerl 181: ccdattach(num)
182: int num;
183: {
1.57 thorpej 184: struct ccd_softc *cs;
185: int i;
186:
1.11 thorpej 187: if (num <= 0) {
188: #ifdef DIAGNOSTIC
189: panic("ccdattach: count <= 0");
190: #endif
1.3 hpeyerl 191: return;
1.11 thorpej 192: }
193:
194: ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
1.72.2.3! jdolecek 195: M_DEVBUF, M_NOWAIT|M_ZERO);
1.57 thorpej 196: if (ccd_softc == NULL) {
1.35 christos 197: printf("WARNING: no memory for concatenated disks\n");
1.3 hpeyerl 198: return;
199: }
200: numccd = num;
1.57 thorpej 201:
1.63 thorpej 202: /* Initialize the component buffer pool. */
203: pool_init(&ccd_cbufpool, sizeof(struct ccdbuf), 0,
204: 0, 0, "ccdpl", 0, NULL, NULL, M_DEVBUF);
205:
1.57 thorpej 206: /* Initialize per-softc structures. */
207: for (i = 0; i < num; i++) {
208: cs = &ccd_softc[i];
209: sprintf(cs->sc_xname, "ccd%d", i); /* XXX */
210: cs->sc_dkdev.dk_name = cs->sc_xname; /* XXX */
211: lockinit(&cs->sc_lock, PRIBIO, "ccdlk", 0, 0);
212: }
1.1 hpeyerl 213: }
214:
1.11 thorpej 215: static int
1.57 thorpej 216: ccdinit(cs, cpaths, vpp, p)
217: struct ccd_softc *cs;
1.11 thorpej 218: char **cpaths;
1.57 thorpej 219: struct vnode **vpp;
1.11 thorpej 220: struct proc *p;
1.1 hpeyerl 221: {
1.68 augustss 222: struct ccdcinfo *ci = NULL;
223: size_t size;
224: int ix;
1.11 thorpej 225: struct vattr va;
1.1 hpeyerl 226: size_t minsize;
1.11 thorpej 227: int maxsecsize;
1.7 cgd 228: struct partinfo dpart;
1.11 thorpej 229: struct ccdgeom *ccg = &cs->sc_geom;
230: char tmppath[MAXPATHLEN];
1.67 enami 231: int error, path_alloced;
1.1 hpeyerl 232:
233: #ifdef DEBUG
1.3 hpeyerl 234: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.59 thorpej 235: printf("%s: ccdinit\n", cs->sc_xname);
1.1 hpeyerl 236: #endif
1.11 thorpej 237:
238: /* Allocate space for the component info. */
239: cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
240: M_DEVBUF, M_WAITOK);
241:
1.57 thorpej 242: cs->sc_size = 0;
243:
1.1 hpeyerl 244: /*
245: * Verify that each component piece exists and record
246: * relevant information about it.
247: */
1.11 thorpej 248: maxsecsize = 0;
1.1 hpeyerl 249: minsize = 0;
1.67 enami 250: for (ix = 0, path_alloced = 0; ix < cs->sc_nccdisks; ix++) {
1.1 hpeyerl 251: ci = &cs->sc_cinfo[ix];
1.57 thorpej 252: ci->ci_vp = vpp[ix];
1.11 thorpej 253:
254: /*
255: * Copy in the pathname of the component.
256: */
1.72 thorpej 257: memset(tmppath, 0, sizeof(tmppath)); /* sanity */
1.29 christos 258: error = copyinstr(cpaths[ix], tmppath,
259: MAXPATHLEN, &ci->ci_pathlen);
260: if (error) {
1.11 thorpej 261: #ifdef DEBUG
262: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 263: printf("%s: can't copy path, error = %d\n",
1.23 thorpej 264: cs->sc_xname, error);
1.11 thorpej 265: #endif
1.67 enami 266: goto out;
1.11 thorpej 267: }
268: ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
1.72 thorpej 269: memcpy(ci->ci_path, tmppath, ci->ci_pathlen);
1.67 enami 270: path_alloced++;
1.11 thorpej 271:
272: /*
273: * XXX: Cache the component's dev_t.
274: */
1.57 thorpej 275: if ((error = VOP_GETATTR(vpp[ix], &va, p->p_ucred, p)) != 0) {
1.11 thorpej 276: #ifdef DEBUG
277: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 278: printf("%s: %s: getattr failed %s = %d\n",
1.23 thorpej 279: cs->sc_xname, ci->ci_path,
1.11 thorpej 280: "error", error);
281: #endif
1.67 enami 282: goto out;
1.11 thorpej 283: }
284: ci->ci_dev = va.va_rdev;
285:
1.3 hpeyerl 286: /*
1.11 thorpej 287: * Get partition information for the component.
1.3 hpeyerl 288: */
1.57 thorpej 289: error = VOP_IOCTL(vpp[ix], DIOCGPART, (caddr_t)&dpart,
1.29 christos 290: FREAD, p->p_ucred, p);
291: if (error) {
1.11 thorpej 292: #ifdef DEBUG
293: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 294: printf("%s: %s: ioctl failed, error = %d\n",
1.23 thorpej 295: cs->sc_xname, ci->ci_path, error);
1.11 thorpej 296: #endif
1.67 enami 297: goto out;
1.11 thorpej 298: }
1.69 enami 299:
300: /*
301: * This diagnostic test is disabled (for now?) since not all port supports
302: * on-disk BSD disklabel.
303: */
304: #if 0 /* def DIAGNOSTIC */
305: /* Check fstype field of component. */
306: if (dpart.part->p_fstype != FS_CCD)
307: printf("%s: WARNING: %s: fstype %d != FS_CCD\n",
308: cs->sc_xname, ci->ci_path, dpart.part->p_fstype);
309: #endif
1.7 cgd 310:
1.11 thorpej 311: /*
312: * Calculate the size, truncating to an interleave
313: * boundary if necessary.
314: */
1.46 thorpej 315: maxsecsize =
316: ((dpart.disklab->d_secsize > maxsecsize) ?
317: dpart.disklab->d_secsize : maxsecsize);
318: size = dpart.part->p_size;
1.1 hpeyerl 319: if (cs->sc_ileave > 1)
320: size -= size % cs->sc_ileave;
1.11 thorpej 321:
1.1 hpeyerl 322: if (size == 0) {
1.11 thorpej 323: #ifdef DEBUG
324: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 325: printf("%s: %s: size == 0\n",
1.23 thorpej 326: cs->sc_xname, ci->ci_path);
1.11 thorpej 327: #endif
1.67 enami 328: error = ENODEV;
329: goto out;
1.3 hpeyerl 330: }
1.11 thorpej 331:
1.1 hpeyerl 332: if (minsize == 0 || size < minsize)
333: minsize = size;
334: ci->ci_size = size;
335: cs->sc_size += size;
336: }
1.11 thorpej 337:
338: /*
339: * Don't allow the interleave to be smaller than
340: * the biggest component sector.
341: */
342: if ((cs->sc_ileave > 0) &&
343: (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
344: #ifdef DEBUG
345: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 346: printf("%s: interleave must be at least %d\n",
1.23 thorpej 347: cs->sc_xname, (maxsecsize / DEV_BSIZE));
1.11 thorpej 348: #endif
1.67 enami 349: error = EINVAL;
350: goto out;
1.11 thorpej 351: }
352:
1.1 hpeyerl 353: /*
354: * If uniform interleave is desired set all sizes to that of
355: * the smallest component.
356: */
1.57 thorpej 357: if (cs->sc_flags & CCDF_UNIFORM) {
1.1 hpeyerl 358: for (ci = cs->sc_cinfo;
359: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
360: ci->ci_size = minsize;
1.24 thorpej 361:
1.53 thorpej 362: cs->sc_size = cs->sc_nccdisks * minsize;
1.1 hpeyerl 363: }
1.11 thorpej 364:
365: /*
366: * Construct the interleave table.
367: */
1.57 thorpej 368: ccdinterleave(cs);
1.11 thorpej 369:
1.1 hpeyerl 370: /*
1.11 thorpej 371: * Create pseudo-geometry based on 1MB cylinders. It's
372: * pretty close.
1.1 hpeyerl 373: */
1.11 thorpej 374: ccg->ccg_secsize = DEV_BSIZE;
1.19 thorpej 375: ccg->ccg_ntracks = 1;
1.11 thorpej 376: ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
377: ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
378:
379: cs->sc_flags |= CCDF_INITED;
1.23 thorpej 380:
1.11 thorpej 381: return (0);
1.67 enami 382:
383: out:
384: for (ix = 0; ix < path_alloced; ix++)
385: free(cs->sc_cinfo[ix].ci_path, M_DEVBUF);
386: free(cs->sc_cinfo, M_DEVBUF);
387: return (error);
1.1 hpeyerl 388: }
389:
1.11 thorpej 390: static void
1.57 thorpej 391: ccdinterleave(cs)
1.68 augustss 392: struct ccd_softc *cs;
1.1 hpeyerl 393: {
1.68 augustss 394: struct ccdcinfo *ci, *smallci;
395: struct ccdiinfo *ii;
396: daddr_t bn, lbn;
397: int ix;
1.1 hpeyerl 398: u_long size;
399:
400: #ifdef DEBUG
1.3 hpeyerl 401: if (ccddebug & CCDB_INIT)
1.35 christos 402: printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
1.1 hpeyerl 403: #endif
404: /*
405: * Allocate an interleave table.
406: * Chances are this is too big, but we don't care.
407: */
408: size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
1.72.2.3! jdolecek 409: cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF,
! 410: M_WAITOK|M_ZERO);
1.11 thorpej 411:
1.1 hpeyerl 412: /*
413: * Trivial case: no interleave (actually interleave of disk size).
1.11 thorpej 414: * Each table entry represents a single component in its entirety.
1.1 hpeyerl 415: */
416: if (cs->sc_ileave == 0) {
417: bn = 0;
418: ii = cs->sc_itable;
1.11 thorpej 419:
1.1 hpeyerl 420: for (ix = 0; ix < cs->sc_nccdisks; ix++) {
1.19 thorpej 421: /* Allocate space for ii_index. */
422: ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
1.1 hpeyerl 423: ii->ii_ndisk = 1;
424: ii->ii_startblk = bn;
425: ii->ii_startoff = 0;
426: ii->ii_index[0] = ix;
427: bn += cs->sc_cinfo[ix].ci_size;
428: ii++;
429: }
430: ii->ii_ndisk = 0;
431: #ifdef DEBUG
1.3 hpeyerl 432: if (ccddebug & CCDB_INIT)
1.1 hpeyerl 433: printiinfo(cs->sc_itable);
434: #endif
1.11 thorpej 435: return;
1.1 hpeyerl 436: }
1.11 thorpej 437:
1.1 hpeyerl 438: /*
439: * The following isn't fast or pretty; it doesn't have to be.
440: */
441: size = 0;
442: bn = lbn = 0;
443: for (ii = cs->sc_itable; ; ii++) {
1.11 thorpej 444: /* Allocate space for ii_index. */
1.19 thorpej 445: ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
446: M_DEVBUF, M_WAITOK);
1.11 thorpej 447:
1.1 hpeyerl 448: /*
449: * Locate the smallest of the remaining components
450: */
451: smallci = NULL;
452: for (ci = cs->sc_cinfo;
453: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
454: if (ci->ci_size > size &&
455: (smallci == NULL ||
456: ci->ci_size < smallci->ci_size))
457: smallci = ci;
1.11 thorpej 458:
1.1 hpeyerl 459: /*
460: * Nobody left, all done
461: */
462: if (smallci == NULL) {
463: ii->ii_ndisk = 0;
464: break;
465: }
1.11 thorpej 466:
1.1 hpeyerl 467: /*
468: * Record starting logical block and component offset
469: */
470: ii->ii_startblk = bn / cs->sc_ileave;
471: ii->ii_startoff = lbn;
1.11 thorpej 472:
1.1 hpeyerl 473: /*
474: * Determine how many disks take part in this interleave
475: * and record their indices.
476: */
477: ix = 0;
478: for (ci = cs->sc_cinfo;
479: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
480: if (ci->ci_size >= smallci->ci_size)
481: ii->ii_index[ix++] = ci - cs->sc_cinfo;
482: ii->ii_ndisk = ix;
483: bn += ix * (smallci->ci_size - size);
484: lbn = smallci->ci_size / cs->sc_ileave;
485: size = smallci->ci_size;
486: }
487: #ifdef DEBUG
1.3 hpeyerl 488: if (ccddebug & CCDB_INIT)
1.1 hpeyerl 489: printiinfo(cs->sc_itable);
490: #endif
491: }
492:
1.11 thorpej 493: /* ARGSUSED */
494: int
495: ccdopen(dev, flags, fmt, p)
1.1 hpeyerl 496: dev_t dev;
1.11 thorpej 497: int flags, fmt;
498: struct proc *p;
1.1 hpeyerl 499: {
500: int unit = ccdunit(dev);
1.11 thorpej 501: struct ccd_softc *cs;
502: struct disklabel *lp;
1.15 thorpej 503: int error = 0, part, pmask;
1.1 hpeyerl 504:
505: #ifdef DEBUG
1.3 hpeyerl 506: if (ccddebug & CCDB_FOLLOW)
1.43 fair 507: printf("ccdopen(0x%x, 0x%x)\n", dev, flags);
1.1 hpeyerl 508: #endif
1.11 thorpej 509: if (unit >= numccd)
510: return (ENXIO);
511: cs = &ccd_softc[unit];
1.15 thorpej 512:
1.57 thorpej 513: if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
1.15 thorpej 514: return (error);
515:
1.23 thorpej 516: lp = cs->sc_dkdev.dk_label;
1.11 thorpej 517:
518: part = DISKPART(dev);
519: pmask = (1 << part);
520:
1.15 thorpej 521: /*
522: * If we're initialized, check to see if there are any other
523: * open partitions. If not, then it's safe to update
524: * the in-core disklabel.
525: */
526: if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
527: ccdgetdisklabel(dev);
528:
1.11 thorpej 529: /* Check that the partition exists. */
1.27 thorpej 530: if (part != RAW_PART) {
531: if (((cs->sc_flags & CCDF_INITED) == 0) ||
1.37 thorpej 532: ((part >= lp->d_npartitions) ||
1.27 thorpej 533: (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
534: error = ENXIO;
535: goto done;
536: }
1.15 thorpej 537: }
1.11 thorpej 538:
539: /* Prevent our unit from being unconfigured while open. */
540: switch (fmt) {
541: case S_IFCHR:
542: cs->sc_dkdev.dk_copenmask |= pmask;
543: break;
544:
545: case S_IFBLK:
546: cs->sc_dkdev.dk_bopenmask |= pmask;
547: break;
548: }
549: cs->sc_dkdev.dk_openmask =
550: cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
551:
1.15 thorpej 552: done:
1.57 thorpej 553: (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL);
1.33 thorpej 554: return (error);
1.7 cgd 555: }
556:
1.11 thorpej 557: /* ARGSUSED */
558: int
559: ccdclose(dev, flags, fmt, p)
1.7 cgd 560: dev_t dev;
1.11 thorpej 561: int flags, fmt;
562: struct proc *p;
1.7 cgd 563: {
1.11 thorpej 564: int unit = ccdunit(dev);
565: struct ccd_softc *cs;
1.15 thorpej 566: int error = 0, part;
1.11 thorpej 567:
1.7 cgd 568: #ifdef DEBUG
569: if (ccddebug & CCDB_FOLLOW)
1.43 fair 570: printf("ccdclose(0x%x, 0x%x)\n", dev, flags);
1.7 cgd 571: #endif
1.11 thorpej 572:
573: if (unit >= numccd)
574: return (ENXIO);
575: cs = &ccd_softc[unit];
1.15 thorpej 576:
1.57 thorpej 577: if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
1.15 thorpej 578: return (error);
579:
1.11 thorpej 580: part = DISKPART(dev);
581:
582: /* ...that much closer to allowing unconfiguration... */
583: switch (fmt) {
584: case S_IFCHR:
585: cs->sc_dkdev.dk_copenmask &= ~(1 << part);
586: break;
587:
588: case S_IFBLK:
589: cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
590: break;
591: }
592: cs->sc_dkdev.dk_openmask =
593: cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
594:
1.57 thorpej 595: (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL);
1.7 cgd 596: return (0);
1.1 hpeyerl 597: }
598:
1.11 thorpej 599: void
1.1 hpeyerl 600: ccdstrategy(bp)
1.68 augustss 601: struct buf *bp;
1.1 hpeyerl 602: {
1.68 augustss 603: int unit = ccdunit(bp->b_dev);
604: struct ccd_softc *cs = &ccd_softc[unit];
605: int s;
1.11 thorpej 606: int wlabel;
1.15 thorpej 607: struct disklabel *lp;
1.1 hpeyerl 608:
609: #ifdef DEBUG
1.3 hpeyerl 610: if (ccddebug & CCDB_FOLLOW)
1.35 christos 611: printf("ccdstrategy(%p): unit %d\n", bp, unit);
1.1 hpeyerl 612: #endif
1.3 hpeyerl 613: if ((cs->sc_flags & CCDF_INITED) == 0) {
1.59 thorpej 614: #ifdef DEBUG
615: if (ccddebug & CCDB_FOLLOW)
616: printf("ccdstrategy: unit %d: not inited\n", unit);
617: #endif
1.1 hpeyerl 618: bp->b_error = ENXIO;
619: bp->b_flags |= B_ERROR;
620: goto done;
621: }
1.11 thorpej 622:
623: /* If it's a nil transfer, wake up the top half now. */
624: if (bp->b_bcount == 0)
625: goto done;
626:
1.23 thorpej 627: lp = cs->sc_dkdev.dk_label;
1.15 thorpej 628:
1.11 thorpej 629: /*
1.17 thorpej 630: * Do bounds checking and adjust transfer. If there's an
1.11 thorpej 631: * error, the bounds check will flag that for us.
632: */
633: wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
1.16 thorpej 634: if (DISKPART(bp->b_dev) != RAW_PART)
1.15 thorpej 635: if (bounds_check_with_label(bp, lp, wlabel) <= 0)
1.1 hpeyerl 636: goto done;
1.11 thorpej 637:
1.1 hpeyerl 638: bp->b_resid = bp->b_bcount;
1.11 thorpej 639:
1.1 hpeyerl 640: /*
641: * "Start" the unit.
642: */
643: s = splbio();
1.3 hpeyerl 644: ccdstart(cs, bp);
1.1 hpeyerl 645: splx(s);
646: return;
647: done:
648: biodone(bp);
649: }
650:
1.11 thorpej 651: static void
1.3 hpeyerl 652: ccdstart(cs, bp)
1.68 augustss 653: struct ccd_softc *cs;
654: struct buf *bp;
1.1 hpeyerl 655: {
1.68 augustss 656: long bcount, rcount;
1.55 thorpej 657: struct ccdbuf *cbp;
1.1 hpeyerl 658: caddr_t addr;
659: daddr_t bn;
1.20 thorpej 660: struct partition *pp;
1.56 thorpej 661: SIMPLEQ_HEAD(, ccdbuf) cbufq;
1.1 hpeyerl 662:
663: #ifdef DEBUG
1.3 hpeyerl 664: if (ccddebug & CCDB_FOLLOW)
1.35 christos 665: printf("ccdstart(%p, %p)\n", cs, bp);
1.1 hpeyerl 666: #endif
1.11 thorpej 667:
1.23 thorpej 668: /* Instrumentation. */
669: disk_busy(&cs->sc_dkdev);
1.11 thorpej 670:
1.1 hpeyerl 671: /*
1.17 thorpej 672: * Translate the partition-relative block number to an absolute.
1.1 hpeyerl 673: */
1.20 thorpej 674: bn = bp->b_blkno;
675: if (DISKPART(bp->b_dev) != RAW_PART) {
1.23 thorpej 676: pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
1.20 thorpej 677: bn += pp->p_offset;
678: }
1.17 thorpej 679:
680: /*
1.56 thorpej 681: * Allocate the component buffers.
1.17 thorpej 682: */
1.56 thorpej 683: SIMPLEQ_INIT(&cbufq);
1.3 hpeyerl 684: addr = bp->b_data;
1.1 hpeyerl 685: for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
1.55 thorpej 686: cbp = ccdbuffer(cs, bp, bn, addr, bcount);
1.56 thorpej 687: if (cbp == NULL) {
688: /* Free the already allocated component buffers. */
689: while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
690: SIMPLEQ_REMOVE_HEAD(&cbufq, cbp, cb_q);
1.63 thorpej 691: CCD_PUTBUF(cbp);
1.56 thorpej 692: }
693:
694: /* Notify the upper layer we are out of memory. */
695: bp->b_error = ENOMEM;
696: bp->b_flags |= B_ERROR;
1.64 chs 697: biodone(bp);
1.59 thorpej 698: disk_unbusy(&cs->sc_dkdev, 0);
1.56 thorpej 699: return;
700: }
701: SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
1.55 thorpej 702: rcount = cbp->cb_buf.b_bcount;
1.56 thorpej 703: bn += btodb(rcount);
704: addr += rcount;
705: }
706:
707: /* Now fire off the requests. */
708: while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
709: SIMPLEQ_REMOVE_HEAD(&cbufq, cbp, cb_q);
1.55 thorpej 710: if ((cbp->cb_buf.b_flags & B_READ) == 0)
711: cbp->cb_buf.b_vp->v_numoutput++;
712: VOP_STRATEGY(&cbp->cb_buf);
1.1 hpeyerl 713: }
714: }
715:
716: /*
717: * Build a component buffer header.
718: */
1.55 thorpej 719: static struct ccdbuf *
720: ccdbuffer(cs, bp, bn, addr, bcount)
1.68 augustss 721: struct ccd_softc *cs;
1.1 hpeyerl 722: struct buf *bp;
723: daddr_t bn;
724: caddr_t addr;
725: long bcount;
726: {
1.68 augustss 727: struct ccdcinfo *ci;
728: struct ccdbuf *cbp;
729: daddr_t cbn, cboff;
730: u_int64_t cbc;
1.36 thorpej 731: int ccdisk;
1.1 hpeyerl 732:
733: #ifdef DEBUG
1.3 hpeyerl 734: if (ccddebug & CCDB_IO)
1.35 christos 735: printf("ccdbuffer(%p, %p, %d, %p, %ld)\n",
1.1 hpeyerl 736: cs, bp, bn, addr, bcount);
737: #endif
738: /*
739: * Determine which component bn falls in.
740: */
741: cbn = bn;
742: cboff = 0;
1.11 thorpej 743:
1.1 hpeyerl 744: /*
745: * Serially concatenated
746: */
747: if (cs->sc_ileave == 0) {
1.68 augustss 748: daddr_t sblk;
1.1 hpeyerl 749:
750: sblk = 0;
1.36 thorpej 751: for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
752: cbn >= sblk + ci->ci_size;
753: ccdisk++, ci = &cs->sc_cinfo[ccdisk])
1.1 hpeyerl 754: sblk += ci->ci_size;
755: cbn -= sblk;
756: }
757: /*
758: * Interleaved
759: */
760: else {
1.68 augustss 761: struct ccdiinfo *ii;
1.36 thorpej 762: int off;
1.1 hpeyerl 763:
764: cboff = cbn % cs->sc_ileave;
765: cbn /= cs->sc_ileave;
766: for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
767: if (ii->ii_startblk > cbn)
768: break;
769: ii--;
770: off = cbn - ii->ii_startblk;
771: if (ii->ii_ndisk == 1) {
772: ccdisk = ii->ii_index[0];
773: cbn = ii->ii_startoff + off;
774: } else {
1.53 thorpej 775: ccdisk = ii->ii_index[off % ii->ii_ndisk];
776: cbn = ii->ii_startoff + off / ii->ii_ndisk;
1.1 hpeyerl 777: }
778: cbn *= cs->sc_ileave;
779: ci = &cs->sc_cinfo[ccdisk];
780: }
1.11 thorpej 781:
1.1 hpeyerl 782: /*
783: * Fill in the component buf structure.
784: */
1.63 thorpej 785: cbp = CCD_GETBUF();
1.55 thorpej 786: if (cbp == NULL)
787: return (NULL);
1.6 cgd 788: cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
1.29 christos 789: cbp->cb_buf.b_iodone = ccdiodone;
1.6 cgd 790: cbp->cb_buf.b_proc = bp->b_proc;
1.11 thorpej 791: cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */
1.6 cgd 792: cbp->cb_buf.b_blkno = cbn + cboff;
793: cbp->cb_buf.b_data = addr;
1.11 thorpej 794: cbp->cb_buf.b_vp = ci->ci_vp;
1.65 fvdl 795: LIST_INIT(&cbp->cb_buf.b_dep);
1.1 hpeyerl 796: if (cs->sc_ileave == 0)
1.50 thorpej 797: cbc = dbtob((u_int64_t)(ci->ci_size - cbn));
1.1 hpeyerl 798: else
1.50 thorpej 799: cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff));
800: cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount;
1.6 cgd 801:
1.1 hpeyerl 802: /*
1.6 cgd 803: * context for ccdiodone
1.1 hpeyerl 804: */
1.6 cgd 805: cbp->cb_obp = bp;
1.59 thorpej 806: cbp->cb_sc = cs;
1.36 thorpej 807: cbp->cb_comp = ccdisk;
1.6 cgd 808:
1.1 hpeyerl 809: #ifdef DEBUG
1.3 hpeyerl 810: if (ccddebug & CCDB_IO)
1.62 mjacob 811: printf(" dev 0x%x(u%lu): cbp %p bn %d addr %p bcnt %ld\n",
812: ci->ci_dev, (unsigned long) (ci-cs->sc_cinfo), cbp,
813: cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
814: cbp->cb_buf.b_bcount);
1.1 hpeyerl 815: #endif
1.55 thorpej 816:
817: return (cbp);
1.1 hpeyerl 818: }
819:
1.11 thorpej 820: static void
1.3 hpeyerl 821: ccdintr(cs, bp)
1.68 augustss 822: struct ccd_softc *cs;
823: struct buf *bp;
1.1 hpeyerl 824: {
825:
826: #ifdef DEBUG
1.3 hpeyerl 827: if (ccddebug & CCDB_FOLLOW)
1.35 christos 828: printf("ccdintr(%p, %p)\n", cs, bp);
1.1 hpeyerl 829: #endif
830: /*
831: * Request is done for better or worse, wakeup the top half.
832: */
833: if (bp->b_flags & B_ERROR)
834: bp->b_resid = bp->b_bcount;
1.23 thorpej 835: disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid));
1.1 hpeyerl 836: biodone(bp);
837: }
838:
839: /*
1.11 thorpej 840: * Called at interrupt time.
1.1 hpeyerl 841: * Mark the component as done and if all components are done,
842: * take a ccd interrupt.
843: */
1.3 hpeyerl 844: void
1.29 christos 845: ccdiodone(vbp)
846: struct buf *vbp;
1.1 hpeyerl 847: {
1.29 christos 848: struct ccdbuf *cbp = (struct ccdbuf *) vbp;
1.59 thorpej 849: struct buf *bp = cbp->cb_obp;
850: struct ccd_softc *cs = cbp->cb_sc;
1.53 thorpej 851: int count, s;
1.1 hpeyerl 852:
853: s = splbio();
854: #ifdef DEBUG
1.3 hpeyerl 855: if (ccddebug & CCDB_FOLLOW)
1.35 christos 856: printf("ccdiodone(%p)\n", cbp);
1.3 hpeyerl 857: if (ccddebug & CCDB_IO) {
1.53 thorpej 858: printf("ccdiodone: bp %p bcount %ld resid %ld\n",
859: bp, bp->b_bcount, bp->b_resid);
1.43 fair 860: printf(" dev 0x%x(u%d), cbp %p bn %d addr %p bcnt %ld\n",
1.6 cgd 861: cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
862: cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
863: cbp->cb_buf.b_bcount);
1.1 hpeyerl 864: }
865: #endif
866:
1.6 cgd 867: if (cbp->cb_buf.b_flags & B_ERROR) {
1.53 thorpej 868: bp->b_flags |= B_ERROR;
869: bp->b_error = cbp->cb_buf.b_error ?
870: cbp->cb_buf.b_error : EIO;
1.24 thorpej 871:
1.53 thorpej 872: printf("%s: error %d on component %d\n",
873: cs->sc_xname, bp->b_error, cbp->cb_comp);
1.1 hpeyerl 874: }
1.6 cgd 875: count = cbp->cb_buf.b_bcount;
1.63 thorpej 876: CCD_PUTBUF(cbp);
1.1 hpeyerl 877:
878: /*
879: * If all done, "interrupt".
1.53 thorpej 880: */
881: bp->b_resid -= count;
882: if (bp->b_resid < 0)
883: panic("ccdiodone: count");
884: if (bp->b_resid == 0)
1.59 thorpej 885: ccdintr(cs, bp);
1.1 hpeyerl 886: splx(s);
887: }
888:
1.11 thorpej 889: /* ARGSUSED */
1.10 mycroft 890: int
1.11 thorpej 891: ccdread(dev, uio, flags)
1.3 hpeyerl 892: dev_t dev;
893: struct uio *uio;
1.11 thorpej 894: int flags;
1.3 hpeyerl 895: {
1.11 thorpej 896: int unit = ccdunit(dev);
897: struct ccd_softc *cs;
1.3 hpeyerl 898:
899: #ifdef DEBUG
900: if (ccddebug & CCDB_FOLLOW)
1.43 fair 901: printf("ccdread(0x%x, %p)\n", dev, uio);
1.3 hpeyerl 902: #endif
1.11 thorpej 903: if (unit >= numccd)
904: return (ENXIO);
905: cs = &ccd_softc[unit];
906:
907: if ((cs->sc_flags & CCDF_INITED) == 0)
908: return (ENXIO);
909:
910: /*
911: * XXX: It's not clear that using minphys() is completely safe,
912: * in particular, for raw I/O. Underlying devices might have some
913: * non-obvious limits, because of the copy to user-space.
914: */
1.10 mycroft 915: return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
1.3 hpeyerl 916: }
917:
1.11 thorpej 918: /* ARGSUSED */
1.10 mycroft 919: int
1.11 thorpej 920: ccdwrite(dev, uio, flags)
1.3 hpeyerl 921: dev_t dev;
922: struct uio *uio;
1.11 thorpej 923: int flags;
1.3 hpeyerl 924: {
1.11 thorpej 925: int unit = ccdunit(dev);
926: struct ccd_softc *cs;
1.3 hpeyerl 927:
928: #ifdef DEBUG
929: if (ccddebug & CCDB_FOLLOW)
1.43 fair 930: printf("ccdwrite(0x%x, %p)\n", dev, uio);
1.3 hpeyerl 931: #endif
1.11 thorpej 932: if (unit >= numccd)
933: return (ENXIO);
934: cs = &ccd_softc[unit];
935:
936: if ((cs->sc_flags & CCDF_INITED) == 0)
937: return (ENXIO);
938:
939: /*
940: * XXX: It's not clear that using minphys() is completely safe,
941: * in particular, for raw I/O. Underlying devices might have some
942: * non-obvious limits, because of the copy to user-space.
943: */
1.10 mycroft 944: return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
1.3 hpeyerl 945: }
946:
1.11 thorpej 947: int
948: ccdioctl(dev, cmd, data, flag, p)
1.1 hpeyerl 949: dev_t dev;
1.5 cgd 950: u_long cmd;
1.1 hpeyerl 951: caddr_t data;
952: int flag;
1.11 thorpej 953: struct proc *p;
1.1 hpeyerl 954: {
1.11 thorpej 955: int unit = ccdunit(dev);
1.57 thorpej 956: int i, j, lookedup = 0, error;
1.39 mycroft 957: int part, pmask;
1.11 thorpej 958: struct ccd_softc *cs;
959: struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
960: char **cpp;
961: struct vnode **vpp;
1.70 fvdl 962: #ifdef __HAVE_OLD_DISKLABEL
963: struct disklabel newlabel;
964: #endif
1.11 thorpej 965:
966: if (unit >= numccd)
967: return (ENXIO);
968: cs = &ccd_softc[unit];
969:
1.41 thorpej 970: /* Must be open for writes for these commands... */
971: switch (cmd) {
972: case CCDIOCSET:
973: case CCDIOCCLR:
974: case DIOCSDINFO:
975: case DIOCWDINFO:
1.70 fvdl 976: #ifdef __HAVE_OLD_DISKLABEL
977: case ODIOCSDINFO:
978: case ODIOCWDINFO:
979: #endif
1.41 thorpej 980: case DIOCWLABEL:
981: if ((flag & FWRITE) == 0)
982: return (EBADF);
983: }
984:
1.57 thorpej 985: if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
986: return (error);
987:
1.41 thorpej 988: /* Must be initialized for these... */
989: switch (cmd) {
990: case CCDIOCCLR:
1.42 kleink 991: case DIOCGDINFO:
992: case DIOCSDINFO:
993: case DIOCWDINFO:
994: case DIOCGPART:
1.41 thorpej 995: case DIOCWLABEL:
1.44 thorpej 996: case DIOCGDEFLABEL:
1.70 fvdl 997: #ifdef __HAVE_OLD_DISKLABEL
998: case ODIOCGDINFO:
999: case ODIOCSDINFO:
1000: case ODIOCWDINFO:
1001: case ODIOCGDEFLABEL:
1002: #endif
1.57 thorpej 1003: if ((cs->sc_flags & CCDF_INITED) == 0) {
1004: error = ENXIO;
1005: goto out;
1006: }
1.41 thorpej 1007: }
1008:
1.11 thorpej 1009: switch (cmd) {
1010: case CCDIOCSET:
1.57 thorpej 1011: if (cs->sc_flags & CCDF_INITED) {
1012: error = EBUSY;
1013: goto out;
1014: }
1.54 thorpej 1015:
1016: /* Validate the flags. */
1.57 thorpej 1017: if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) {
1018: error = EINVAL;
1019: goto out;
1020: }
1.15 thorpej 1021:
1.72.2.1 thorpej 1022: if (ccio->ccio_ndisks > CCD_MAXNDISKS) {
1023: error = EINVAL;
1024: goto out;
1025: }
1026:
1.11 thorpej 1027: /* Fill in some important bits. */
1.57 thorpej 1028: cs->sc_ileave = ccio->ccio_ileave;
1029: cs->sc_nccdisks = ccio->ccio_ndisks;
1030: cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK;
1.11 thorpej 1031:
1032: /*
1033: * Allocate space for and copy in the array of
1034: * componet pathnames and device numbers.
1035: */
1036: cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1037: M_DEVBUF, M_WAITOK);
1038: vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1039: M_DEVBUF, M_WAITOK);
1040:
1041: error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1042: ccio->ccio_ndisks * sizeof(char **));
1043: if (error) {
1044: free(vpp, M_DEVBUF);
1045: free(cpp, M_DEVBUF);
1.57 thorpej 1046: goto out;
1.11 thorpej 1047: }
1048:
1049: #ifdef DEBUG
1050: if (ccddebug & CCDB_INIT)
1051: for (i = 0; i < ccio->ccio_ndisks; ++i)
1.35 christos 1052: printf("ccdioctl: component %d: 0x%p\n",
1.11 thorpej 1053: i, cpp[i]);
1054: #endif
1055:
1056: for (i = 0; i < ccio->ccio_ndisks; ++i) {
1057: #ifdef DEBUG
1058: if (ccddebug & CCDB_INIT)
1.35 christos 1059: printf("ccdioctl: lookedup = %d\n", lookedup);
1.11 thorpej 1060: #endif
1.29 christos 1061: if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1.11 thorpej 1062: for (j = 0; j < lookedup; ++j)
1.12 thorpej 1063: (void)vn_close(vpp[j], FREAD|FWRITE,
1.11 thorpej 1064: p->p_ucred, p);
1065: free(vpp, M_DEVBUF);
1066: free(cpp, M_DEVBUF);
1.57 thorpej 1067: goto out;
1.11 thorpej 1068: }
1069: ++lookedup;
1070: }
1071:
1072: /*
1073: * Initialize the ccd. Fills in the softc for us.
1074: */
1.57 thorpej 1075: if ((error = ccdinit(cs, cpp, vpp, p)) != 0) {
1.11 thorpej 1076: for (j = 0; j < lookedup; ++j)
1.18 thorpej 1077: (void)vn_close(vpp[j], FREAD|FWRITE,
1.11 thorpej 1078: p->p_ucred, p);
1079: free(vpp, M_DEVBUF);
1080: free(cpp, M_DEVBUF);
1.57 thorpej 1081: goto out;
1.11 thorpej 1082: }
1083:
1.57 thorpej 1084: /* We can free the temporary variables now. */
1085: free(vpp, M_DEVBUF);
1086: free(cpp, M_DEVBUF);
1087:
1.11 thorpej 1088: /*
1089: * The ccd has been successfully initialized, so
1.23 thorpej 1090: * we can place it into the array. Don't try to
1091: * read the disklabel until the disk has been attached,
1092: * because space for the disklabel is allocated
1093: * in disk_attach();
1.11 thorpej 1094: */
1095: ccio->ccio_unit = unit;
1096: ccio->ccio_size = cs->sc_size;
1.23 thorpej 1097:
1098: /* Attach the disk. */
1099: disk_attach(&cs->sc_dkdev);
1100:
1101: /* Try and read the disklabel. */
1.11 thorpej 1102: ccdgetdisklabel(dev);
1103: break;
1104:
1105: case CCDIOCCLR:
1106: /*
1107: * Don't unconfigure if any other partitions are open
1108: * or if both the character and block flavors of this
1109: * partition are open.
1110: */
1111: part = DISKPART(dev);
1112: pmask = (1 << part);
1113: if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1114: ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1.15 thorpej 1115: (cs->sc_dkdev.dk_copenmask & pmask))) {
1.57 thorpej 1116: error = EBUSY;
1117: goto out;
1.15 thorpej 1118: }
1.11 thorpej 1119:
1120: /*
1121: * Free ccd_softc information and clear entry.
1122: */
1.22 thorpej 1123:
1124: /* Close the components and free their pathnames. */
1.11 thorpej 1125: for (i = 0; i < cs->sc_nccdisks; ++i) {
1126: /*
1127: * XXX: this close could potentially fail and
1128: * cause Bad Things. Maybe we need to force
1129: * the close to happen?
1130: */
1131: #ifdef DEBUG
1132: if (ccddebug & CCDB_VNODE)
1133: vprint("CCDIOCCLR: vnode info",
1134: cs->sc_cinfo[i].ci_vp);
1135: #endif
1136: (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1137: p->p_ucred, p);
1138: free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1.38 thorpej 1139: }
1140:
1.22 thorpej 1141: /* Free interleave index. */
1142: for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1.19 thorpej 1143: free(cs->sc_itable[i].ii_index, M_DEVBUF);
1.22 thorpej 1144:
1145: /* Free component info and interleave table. */
1.11 thorpej 1146: free(cs->sc_cinfo, M_DEVBUF);
1147: free(cs->sc_itable, M_DEVBUF);
1.21 thorpej 1148: cs->sc_flags &= ~CCDF_INITED;
1.15 thorpej 1149:
1.23 thorpej 1150: /* Detatch the disk. */
1.26 hpeyerl 1151: disk_detach(&cs->sc_dkdev);
1.11 thorpej 1152: break;
1153:
1154: case DIOCGDINFO:
1.23 thorpej 1155: *(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
1.11 thorpej 1156: break;
1.70 fvdl 1157: #ifdef __HAVE_OLD_DISKLABEL
1158: case ODIOCGDINFO:
1159: newlabel = *(cs->sc_dkdev.dk_label);
1160: if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1.71 fvdl 1161: return ENOTTY;
1.70 fvdl 1162: memcpy(data, &newlabel, sizeof (struct olddisklabel));
1163: break;
1164: #endif
1.11 thorpej 1165:
1166: case DIOCGPART:
1.23 thorpej 1167: ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
1.11 thorpej 1168: ((struct partinfo *)data)->part =
1.23 thorpej 1169: &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
1.11 thorpej 1170: break;
1171:
1172: case DIOCWDINFO:
1173: case DIOCSDINFO:
1.70 fvdl 1174: #ifdef __HAVE_OLD_DISKLABEL
1175: case ODIOCWDINFO:
1176: case ODIOCSDINFO:
1177: #endif
1178: {
1179: struct disklabel *lp;
1180: #ifdef __HAVE_OLD_DISKLABEL
1181: if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1182: memset(&newlabel, 0, sizeof newlabel);
1183: memcpy(&newlabel, data, sizeof (struct olddisklabel));
1184: lp = &newlabel;
1185: } else
1186: #endif
1187: lp = (struct disklabel *)data;
1188:
1.11 thorpej 1189: cs->sc_flags |= CCDF_LABELLING;
1190:
1.23 thorpej 1191: error = setdisklabel(cs->sc_dkdev.dk_label,
1.70 fvdl 1192: lp, 0, cs->sc_dkdev.dk_cpulabel);
1.11 thorpej 1193: if (error == 0) {
1.70 fvdl 1194: if (cmd == DIOCWDINFO
1195: #ifdef __HAVE_OLD_DISKLABEL
1196: || cmd == ODIOCWDINFO
1197: #endif
1198: )
1.11 thorpej 1199: error = writedisklabel(CCDLABELDEV(dev),
1.23 thorpej 1200: ccdstrategy, cs->sc_dkdev.dk_label,
1201: cs->sc_dkdev.dk_cpulabel);
1.11 thorpej 1202: }
1203:
1204: cs->sc_flags &= ~CCDF_LABELLING;
1205: break;
1.70 fvdl 1206: }
1.11 thorpej 1207:
1208: case DIOCWLABEL:
1209: if (*(int *)data != 0)
1210: cs->sc_flags |= CCDF_WLABEL;
1211: else
1212: cs->sc_flags &= ~CCDF_WLABEL;
1213: break;
1214:
1.44 thorpej 1215: case DIOCGDEFLABEL:
1216: ccdgetdefaultlabel(cs, (struct disklabel *)data);
1217: break;
1.70 fvdl 1218:
1219: #ifdef __HAVE_OLD_DISKLABEL
1220: case ODIOCGDEFLABEL:
1221: ccdgetdefaultlabel(cs, &newlabel);
1222: if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1.71 fvdl 1223: return ENOTTY;
1.70 fvdl 1224: memcpy(data, &newlabel, sizeof (struct olddisklabel));
1225: break;
1226: #endif
1.44 thorpej 1227:
1.11 thorpej 1228: default:
1.57 thorpej 1229: error = ENOTTY;
1.11 thorpej 1230: }
1231:
1.57 thorpej 1232: out:
1233: (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL);
1234: return (error);
1.1 hpeyerl 1235: }
1236:
1.11 thorpej 1237: int
1.1 hpeyerl 1238: ccdsize(dev)
1239: dev_t dev;
1240: {
1.11 thorpej 1241: struct ccd_softc *cs;
1.40 thorpej 1242: struct disklabel *lp;
1243: int part, unit, omask, size;
1244:
1245: unit = ccdunit(dev);
1246: if (unit >= numccd)
1247: return (-1);
1248: cs = &ccd_softc[unit];
1.11 thorpej 1249:
1.40 thorpej 1250: if ((cs->sc_flags & CCDF_INITED) == 0)
1.11 thorpej 1251: return (-1);
1252:
1253: part = DISKPART(dev);
1.40 thorpej 1254: omask = cs->sc_dkdev.dk_openmask & (1 << part);
1255: lp = cs->sc_dkdev.dk_label;
1.11 thorpej 1256:
1.40 thorpej 1257: if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc))
1.11 thorpej 1258: return (-1);
1259:
1.40 thorpej 1260: if (lp->d_partitions[part].p_fstype != FS_SWAP)
1.11 thorpej 1261: size = -1;
1262: else
1.40 thorpej 1263: size = lp->d_partitions[part].p_size *
1264: (lp->d_secsize / DEV_BSIZE);
1.11 thorpej 1265:
1.40 thorpej 1266: if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc))
1.11 thorpej 1267: return (-1);
1.1 hpeyerl 1268:
1.11 thorpej 1269: return (size);
1.1 hpeyerl 1270: }
1271:
1.9 cgd 1272: int
1273: ccddump(dev, blkno, va, size)
1274: dev_t dev;
1275: daddr_t blkno;
1276: caddr_t va;
1277: size_t size;
1.1 hpeyerl 1278: {
1.9 cgd 1279:
1280: /* Not implemented. */
1281: return ENXIO;
1.11 thorpej 1282: }
1283:
1284: /*
1285: * Lookup the provided name in the filesystem. If the file exists,
1286: * is a valid block device, and isn't being used by anyone else,
1287: * set *vpp to the file's vnode.
1288: */
1289: static int
1290: ccdlookup(path, p, vpp)
1291: char *path;
1292: struct proc *p;
1293: struct vnode **vpp; /* result */
1294: {
1295: struct nameidata nd;
1296: struct vnode *vp;
1297: struct vattr va;
1298: int error;
1299:
1300: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1.29 christos 1301: if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1.11 thorpej 1302: #ifdef DEBUG
1.29 christos 1303: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 1304: printf("ccdlookup: vn_open error = %d\n", error);
1.11 thorpej 1305: #endif
1306: return (error);
1307: }
1308: vp = nd.ni_vp;
1309:
1310: if (vp->v_usecount > 1) {
1.49 ross 1311: VOP_UNLOCK(vp, 0);
1.11 thorpej 1312: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1313: return (EBUSY);
1314: }
1315:
1.29 christos 1316: if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1.11 thorpej 1317: #ifdef DEBUG
1.29 christos 1318: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1.35 christos 1319: printf("ccdlookup: getattr error = %d\n", error);
1.11 thorpej 1320: #endif
1.49 ross 1321: VOP_UNLOCK(vp, 0);
1.11 thorpej 1322: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1323: return (error);
1324: }
1325:
1326: /* XXX: eventually we should handle VREG, too. */
1327: if (va.va_type != VBLK) {
1.49 ross 1328: VOP_UNLOCK(vp, 0);
1.11 thorpej 1329: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1330: return (ENOTBLK);
1331: }
1332:
1333: #ifdef DEBUG
1334: if (ccddebug & CCDB_VNODE)
1335: vprint("ccdlookup: vnode info", vp);
1336: #endif
1337:
1.49 ross 1338: VOP_UNLOCK(vp, 0);
1.11 thorpej 1339: *vpp = vp;
1340: return (0);
1341: }
1342:
1343: static void
1.44 thorpej 1344: ccdgetdefaultlabel(cs, lp)
1345: struct ccd_softc *cs;
1346: struct disklabel *lp;
1.11 thorpej 1347: {
1348: struct ccdgeom *ccg = &cs->sc_geom;
1349:
1.72 thorpej 1350: memset(lp, 0, sizeof(*lp));
1.11 thorpej 1351:
1352: lp->d_secperunit = cs->sc_size;
1353: lp->d_secsize = ccg->ccg_secsize;
1354: lp->d_nsectors = ccg->ccg_nsectors;
1355: lp->d_ntracks = ccg->ccg_ntracks;
1356: lp->d_ncylinders = ccg->ccg_ncylinders;
1.19 thorpej 1357: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1.11 thorpej 1358:
1359: strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1360: lp->d_type = DTYPE_CCD;
1361: strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1362: lp->d_rpm = 3600;
1363: lp->d_interleave = 1;
1364: lp->d_flags = 0;
1365:
1366: lp->d_partitions[RAW_PART].p_offset = 0;
1367: lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1368: lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1369: lp->d_npartitions = RAW_PART + 1;
1370:
1371: lp->d_magic = DISKMAGIC;
1372: lp->d_magic2 = DISKMAGIC;
1.23 thorpej 1373: lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
1.44 thorpej 1374: }
1375:
1376: /*
1377: * Read the disklabel from the ccd. If one is not present, fake one
1378: * up.
1379: */
1380: static void
1381: ccdgetdisklabel(dev)
1382: dev_t dev;
1383: {
1384: int unit = ccdunit(dev);
1385: struct ccd_softc *cs = &ccd_softc[unit];
1386: char *errstring;
1387: struct disklabel *lp = cs->sc_dkdev.dk_label;
1388: struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
1389:
1.72 thorpej 1390: memset(clp, 0, sizeof(*clp));
1.44 thorpej 1391:
1392: ccdgetdefaultlabel(cs, lp);
1.11 thorpej 1393:
1394: /*
1395: * Call the generic disklabel extraction routine.
1396: */
1.29 christos 1397: errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1398: cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
1399: if (errstring)
1.11 thorpej 1400: ccdmakedisklabel(cs);
1.47 enami 1401: else {
1402: int i;
1403: struct partition *pp;
1404:
1405: /*
1406: * Sanity check whether the found disklabel is valid.
1407: *
1408: * This is necessary since total size of ccd may vary
1409: * when an interleave is changed even though exactly
1410: * same componets are used, and old disklabel may used
1411: * if that is found.
1412: */
1413: if (lp->d_secperunit != cs->sc_size)
1414: printf("WARNING: %s: "
1415: "total sector size in disklabel (%d) != "
1.60 thorpej 1416: "the size of ccd (%lu)\n", cs->sc_xname,
1417: lp->d_secperunit, (u_long)cs->sc_size);
1.47 enami 1418: for (i = 0; i < lp->d_npartitions; i++) {
1419: pp = &lp->d_partitions[i];
1420: if (pp->p_offset + pp->p_size > cs->sc_size)
1.48 enami 1421: printf("WARNING: %s: end of partition `%c' "
1.60 thorpej 1422: "exceeds the size of ccd (%lu)\n",
1423: cs->sc_xname, 'a' + i, (u_long)cs->sc_size);
1.47 enami 1424: }
1425: }
1.11 thorpej 1426:
1427: #ifdef DEBUG
1428: /* It's actually extremely common to have unlabeled ccds. */
1429: if (ccddebug & CCDB_LABEL)
1430: if (errstring != NULL)
1.35 christos 1431: printf("%s: %s\n", cs->sc_xname, errstring);
1.11 thorpej 1432: #endif
1433: }
1434:
1435: /*
1436: * Take care of things one might want to take care of in the event
1437: * that a disklabel isn't present.
1438: */
1439: static void
1440: ccdmakedisklabel(cs)
1441: struct ccd_softc *cs;
1442: {
1.23 thorpej 1443: struct disklabel *lp = cs->sc_dkdev.dk_label;
1.11 thorpej 1444:
1445: /*
1446: * For historical reasons, if there's no disklabel present
1447: * the raw partition must be marked FS_BSDFFS.
1448: */
1449: lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1450:
1451: strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1.44 thorpej 1452:
1453: lp->d_checksum = dkcksum(lp);
1.11 thorpej 1454: }
1455:
1456: #ifdef DEBUG
1457: static void
1458: printiinfo(ii)
1459: struct ccdiinfo *ii;
1460: {
1.68 augustss 1461: int ix, i;
1.11 thorpej 1462:
1463: for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1.35 christos 1464: printf(" itab[%d]: #dk %d sblk %d soff %d",
1.34 christos 1465: ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1.11 thorpej 1466: for (i = 0; i < ii->ii_ndisk; i++)
1.35 christos 1467: printf(" %d", ii->ii_index[i]);
1468: printf("\n");
1.11 thorpej 1469: }
1.1 hpeyerl 1470: }
1471: #endif
CVSweb <webmaster@jp.NetBSD.org>