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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d914f44b14340aa841d2658bff368ad9


[ 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.