root/dev/ccd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. getccdbuf
  2. putccdbuf
  3. ccdattach
  4. ccdinit
  5. ccdinterleave
  6. ccdopen
  7. ccdclose
  8. ccdstrategy
  9. ccdstart
  10. ccdbuffer
  11. ccdintr
  12. ccdiodone
  13. ccdread
  14. ccdwrite
  15. ccdioctl
  16. ccdsize
  17. ccddump
  18. ccdlookup
  19. ccdgetdisklabel
  20. printiinfo

    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

/* [<][>][^][v][top][bottom][index][help] */