The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ccd.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: e31da2e03d1f4ce030227cd485a83336


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.