[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

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