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