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

Cache object: 671823b23d38380232c5c792d892471c


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