[BACK]Return to ccd.c CVS log [TXT][DIR] Up to [local] / sys / dev

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