]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/geom_ccd.c
This commit was generated by cvs2svn to compensate for changes in r56915,
[FreeBSD/FreeBSD.git] / sys / geom / geom_ccd.c
1 /* $FreeBSD$ */
2
3 /*      $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */
4
5 /*
6  * Copyright (c) 1995 Jason R. Thorpe.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project
20  *      by Jason R. Thorpe.
21  * 4. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 /*
38  * Copyright (c) 1988 University of Utah.
39  * Copyright (c) 1990, 1993
40  *      The Regents of the University of California.  All rights reserved.
41  *
42  * This code is derived from software contributed to Berkeley by
43  * the Systems Programming Group of the University of Utah Computer
44  * Science Department.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *      This product includes software developed by the University of
57  *      California, Berkeley and its contributors.
58  * 4. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  * from: Utah $Hdr: cd.c 1.6 90/11/28$
75  *
76  *      @(#)cd.c        8.2 (Berkeley) 11/16/93
77  */
78
79 /*
80  * "Concatenated" disk driver.
81  *
82  * Dynamic configuration and disklabel support by:
83  *      Jason R. Thorpe <thorpej@nas.nasa.gov>
84  *      Numerical Aerodynamic Simulation Facility
85  *      Mail Stop 258-6
86  *      NASA Ames Research Center
87  *      Moffett Field, CA 94035
88  */
89
90 #include "ccd.h"
91
92 #include <sys/param.h>
93 #include <sys/systm.h>
94 #include <sys/kernel.h>
95 #include <sys/module.h>
96 #include <sys/proc.h>
97 #include <sys/buf.h>
98 #include <sys/malloc.h>
99 #include <sys/namei.h>
100 #include <sys/conf.h>
101 #include <sys/stat.h>
102 #include <sys/sysctl.h>
103 #include <sys/disklabel.h>
104 #include <ufs/ffs/fs.h> 
105 #include <sys/devicestat.h>
106 #include <sys/fcntl.h>
107 #include <sys/vnode.h>
108
109 #include <sys/ccdvar.h>
110
111 #include <vm/vm_zone.h>
112
113 #if defined(CCDDEBUG) && !defined(DEBUG)
114 #define DEBUG
115 #endif
116
117 #ifdef DEBUG
118 #define CCDB_FOLLOW     0x01
119 #define CCDB_INIT       0x02
120 #define CCDB_IO         0x04
121 #define CCDB_LABEL      0x08
122 #define CCDB_VNODE      0x10
123 static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
124     CCDB_VNODE;
125 SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
126 #undef DEBUG
127 #endif
128
129 #define ccdunit(x)      dkunit(x)
130 #define ccdpart(x)      dkpart(x)
131
132 /*
133    This is how mirroring works (only writes are special):
134
135    When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
136    linked together by the cb_mirror field.  "cb_pflags &
137    CCDPF_MIRROR_DONE" is set to 0 on both of them.
138
139    When a component returns to ccdiodone(), it checks if "cb_pflags &
140    CCDPF_MIRROR_DONE" is set or not.  If not, it sets the partner's
141    flag and returns.  If it is, it means its partner has already
142    returned, so it will go to the regular cleanup.
143
144  */
145
146 struct ccdbuf {
147         struct buf      cb_buf;         /* new I/O buf */
148         struct buf      *cb_obp;        /* ptr. to original I/O buf */
149         struct ccdbuf   *cb_freenext;   /* free list link */
150         int             cb_unit;        /* target unit */
151         int             cb_comp;        /* target component */
152         int             cb_pflags;      /* mirror/parity status flag */
153         struct ccdbuf   *cb_mirror;     /* mirror counterpart */
154 };
155
156 /* bits in cb_pflags */
157 #define CCDPF_MIRROR_DONE 1     /* if set, mirror counterpart is done */
158
159 #define CCDLABELDEV(dev)        \
160         (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
161
162 static d_open_t ccdopen;
163 static d_close_t ccdclose;
164 static d_strategy_t ccdstrategy;
165 static d_ioctl_t ccdioctl;
166 static d_dump_t ccddump;
167 static d_psize_t ccdsize;
168
169 #define NCCDFREEHIWAT   16
170
171 #define CDEV_MAJOR 74
172 #define BDEV_MAJOR 21
173
174 static struct cdevsw ccd_cdevsw = {
175         /* open */      ccdopen,
176         /* close */     ccdclose,
177         /* read */      physread,
178         /* write */     physwrite,
179         /* ioctl */     ccdioctl,
180         /* poll */      nopoll,
181         /* mmap */      nommap,
182         /* strategy */  ccdstrategy,
183         /* name */      "ccd",
184         /* maj */       CDEV_MAJOR,
185         /* dump */      ccddump,
186         /* psize */     ccdsize,
187         /* flags */     D_DISK,
188         /* bmaj */      BDEV_MAJOR
189 };
190
191 /* called during module initialization */
192 static  void ccdattach __P((void));
193 static  int ccd_modevent __P((module_t, int, void *));
194
195 /* called by biodone() at interrupt time */
196 static  void ccdiodone __P((struct ccdbuf *cbp));
197
198 static  void ccdstart __P((struct ccd_softc *, struct buf *));
199 static  void ccdinterleave __P((struct ccd_softc *, int));
200 static  void ccdintr __P((struct ccd_softc *, struct buf *));
201 static  int ccdinit __P((struct ccddevice *, char **, struct proc *));
202 static  int ccdlookup __P((char *, struct proc *p, struct vnode **));
203 static  void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *,
204                 struct buf *, daddr_t, caddr_t, long));
205 static  void ccdgetdisklabel __P((dev_t));
206 static  void ccdmakedisklabel __P((struct ccd_softc *));
207 static  int ccdlock __P((struct ccd_softc *));
208 static  void ccdunlock __P((struct ccd_softc *));
209
210 #ifdef DEBUG
211 static  void printiinfo __P((struct ccdiinfo *));
212 #endif
213
214 /* Non-private for the benefit of libkvm. */
215 struct  ccd_softc *ccd_softc;
216 struct  ccddevice *ccddevs;
217 struct  ccdbuf *ccdfreebufs;
218 static  int numccdfreebufs;
219 static  int numccd = 0;
220
221 /*
222  * getccdbuf() -        Allocate and zero a ccd buffer.
223  *
224  *      This routine is called at splbio().
225  */
226
227 static __inline
228 struct ccdbuf *
229 getccdbuf(struct ccdbuf *cpy)
230 {
231         struct ccdbuf *cbp;
232
233         /*
234          * Allocate from freelist or malloc as necessary
235          */
236         if ((cbp = ccdfreebufs) != NULL) {
237                 ccdfreebufs = cbp->cb_freenext;
238                 --numccdfreebufs;
239         } else {
240                 cbp = malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK);
241         }
242
243         /*
244          * Used by mirroring code
245          */
246         if (cpy)
247                 bcopy(cpy, cbp, sizeof(struct ccdbuf));
248         else
249                 bzero(cbp, sizeof(struct ccdbuf));
250
251         /*
252          * independant struct buf initialization
253          */
254         LIST_INIT(&cbp->cb_buf.b_dep);
255         BUF_LOCKINIT(&cbp->cb_buf);
256         BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
257         BUF_KERNPROC(&cbp->cb_buf);
258
259         return(cbp);
260 }
261
262 /*
263  * putccdbuf() -        Free a ccd buffer.
264  *
265  *      This routine is called at splbio().
266  */
267
268 static __inline
269 void
270 putccdbuf(struct ccdbuf *cbp)
271 {
272         BUF_UNLOCK(&cbp->cb_buf);
273         BUF_LOCKFREE(&cbp->cb_buf);
274
275         if (numccdfreebufs < NCCDFREEHIWAT) {
276                 cbp->cb_freenext = ccdfreebufs;
277                 ccdfreebufs = cbp;
278                 ++numccdfreebufs;
279         } else {
280                 free((caddr_t)cbp, M_DEVBUF);
281         }
282 }
283
284
285 /*
286  * Number of blocks to untouched in front of a component partition.
287  * This is to avoid violating its disklabel area when it starts at the
288  * beginning of the slice.
289  */
290 #if !defined(CCD_OFFSET)
291 #define CCD_OFFSET 16
292 #endif
293
294 /*
295  * Called by main() during pseudo-device attachment.  All we need
296  * to do is allocate enough space for devices to be configured later, and
297  * add devsw entries.
298  */
299 static void
300 ccdattach()
301 {
302         int i;
303         int num = NCCD;
304
305         if (num > 1)
306                 printf("ccd0-%d: Concatenated disk drivers\n", num-1);
307         else
308                 printf("ccd0: Concatenated disk driver\n");
309
310         ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
311             M_DEVBUF, M_NOWAIT);
312         ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
313             M_DEVBUF, M_NOWAIT);
314         if ((ccd_softc == NULL) || (ccddevs == NULL)) {
315                 printf("WARNING: no memory for concatenated disks\n");
316                 if (ccd_softc != NULL)
317                         free(ccd_softc, M_DEVBUF);
318                 if (ccddevs != NULL)
319                         free(ccddevs, M_DEVBUF);
320                 return;
321         }
322         numccd = num;
323         bzero(ccd_softc, num * sizeof(struct ccd_softc));
324         bzero(ccddevs, num * sizeof(struct ccddevice));
325
326         cdevsw_add(&ccd_cdevsw);
327         /* XXX: is this necessary? */
328         for (i = 0; i < numccd; ++i)
329                 ccddevs[i].ccd_dk = -1;
330 }
331
332 static int
333 ccd_modevent(mod, type, data)
334         module_t mod;
335         int type;
336         void *data;
337 {
338         int error = 0;
339
340         switch (type) {
341         case MOD_LOAD:
342                 ccdattach();
343                 break;
344
345         case MOD_UNLOAD:
346                 printf("ccd0: Unload not supported!\n");
347                 error = EOPNOTSUPP;
348                 break;
349
350         default:        /* MOD_SHUTDOWN etc */
351                 break;
352         }
353         return (error);
354 }
355
356 DEV_MODULE(ccd, ccd_modevent, NULL);
357
358 static int
359 ccdinit(ccd, cpaths, p)
360         struct ccddevice *ccd;
361         char **cpaths;
362         struct proc *p;
363 {
364         struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
365         struct ccdcinfo *ci = NULL;     /* XXX */
366         size_t size;
367         int ix;
368         struct vnode *vp;
369         size_t minsize;
370         int maxsecsize;
371         struct partinfo dpart;
372         struct ccdgeom *ccg = &cs->sc_geom;
373         char tmppath[MAXPATHLEN];
374         int error = 0;
375
376 #ifdef DEBUG
377         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
378                 printf("ccdinit: unit %d\n", ccd->ccd_unit);
379 #endif
380
381         cs->sc_size = 0;
382         cs->sc_ileave = ccd->ccd_interleave;
383         cs->sc_nccdisks = ccd->ccd_ndev;
384
385         /* Allocate space for the component info. */
386         cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
387             M_DEVBUF, M_WAITOK);
388
389         /*
390          * Verify that each component piece exists and record
391          * relevant information about it.
392          */
393         maxsecsize = 0;
394         minsize = 0;
395         for (ix = 0; ix < cs->sc_nccdisks; ix++) {
396                 vp = ccd->ccd_vpp[ix];
397                 ci = &cs->sc_cinfo[ix];
398                 ci->ci_vp = vp;
399
400                 /*
401                  * Copy in the pathname of the component.
402                  */
403                 bzero(tmppath, sizeof(tmppath));        /* sanity */
404                 if ((error = copyinstr(cpaths[ix], tmppath,
405                     MAXPATHLEN, &ci->ci_pathlen)) != 0) {
406 #ifdef DEBUG
407                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
408                                 printf("ccd%d: can't copy path, error = %d\n",
409                                     ccd->ccd_unit, error);
410 #endif
411                         goto fail;
412                 }
413                 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
414                 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
415
416                 ci->ci_dev = vn_todev(vp);
417
418                 /*
419                  * Get partition information for the component.
420                  */
421                 if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
422                     FREAD, p->p_ucred, p)) != 0) {
423 #ifdef DEBUG
424                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
425                                  printf("ccd%d: %s: ioctl failed, error = %d\n",
426                                      ccd->ccd_unit, ci->ci_path, error);
427 #endif
428                         goto fail;
429                 }
430                 if (dpart.part->p_fstype == FS_BSDFFS) {
431                         maxsecsize =
432                             ((dpart.disklab->d_secsize > maxsecsize) ?
433                             dpart.disklab->d_secsize : maxsecsize);
434                         size = dpart.part->p_size - CCD_OFFSET;
435                 } else {
436 #ifdef DEBUG
437                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
438                                 printf("ccd%d: %s: incorrect partition type\n",
439                                     ccd->ccd_unit, ci->ci_path);
440 #endif
441                         error = EFTYPE;
442                         goto fail;
443                 }
444
445                 /*
446                  * Calculate the size, truncating to an interleave
447                  * boundary if necessary.
448                  */
449
450                 if (cs->sc_ileave > 1)
451                         size -= size % cs->sc_ileave;
452
453                 if (size == 0) {
454 #ifdef DEBUG
455                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
456                                 printf("ccd%d: %s: size == 0\n",
457                                     ccd->ccd_unit, ci->ci_path);
458 #endif
459                         error = ENODEV;
460                         goto fail;
461                 }
462
463                 if (minsize == 0 || size < minsize)
464                         minsize = size;
465                 ci->ci_size = size;
466                 cs->sc_size += size;
467         }
468
469         /*
470          * Don't allow the interleave to be smaller than
471          * the biggest component sector.
472          */
473         if ((cs->sc_ileave > 0) &&
474             (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
475 #ifdef DEBUG
476                 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
477                         printf("ccd%d: interleave must be at least %d\n",
478                             ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
479 #endif
480                 error = EINVAL;
481                 goto fail;
482         }
483
484         /*
485          * If uniform interleave is desired set all sizes to that of
486          * the smallest component.  This will guarentee that a single
487          * interleave table is generated.
488          *
489          * Lost space must be taken into account when calculating the
490          * overall size.  Half the space is lost when CCDF_MIRROR is
491          * specified.  One disk is lost when CCDF_PARITY is specified.
492          */
493         if (ccd->ccd_flags & CCDF_UNIFORM) {
494                 for (ci = cs->sc_cinfo;
495                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
496                         ci->ci_size = minsize;
497                 }
498                 if (ccd->ccd_flags & CCDF_MIRROR) {
499                         /*
500                          * Check to see if an even number of components
501                          * have been specified.  The interleave must also
502                          * be non-zero in order for us to be able to 
503                          * guarentee the topology.
504                          */
505                         if (cs->sc_nccdisks % 2) {
506                                 printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
507                                 error = EINVAL;
508                                 goto fail;
509                         }
510                         if (cs->sc_ileave == 0) {
511                                 printf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
512                                 error = EINVAL;
513                                 goto fail;
514                         }
515                         cs->sc_size = (cs->sc_nccdisks/2) * minsize;
516                 } else if (ccd->ccd_flags & CCDF_PARITY) {
517                         cs->sc_size = (cs->sc_nccdisks-1) * minsize;
518                 } else {
519                         if (cs->sc_ileave == 0) {
520                                 printf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
521                                 error = EINVAL;
522                                 goto fail;
523                         }
524                         cs->sc_size = cs->sc_nccdisks * minsize;
525                 }
526         }
527
528         /*
529          * Construct the interleave table.
530          */
531         ccdinterleave(cs, ccd->ccd_unit);
532
533         /*
534          * Create pseudo-geometry based on 1MB cylinders.  It's
535          * pretty close.
536          */
537         ccg->ccg_secsize = maxsecsize;
538         ccg->ccg_ntracks = 1;
539         ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
540         ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
541
542         /*
543          * Add an devstat entry for this device.
544          */
545         devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
546                           ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
547                           DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
548                           DEVSTAT_PRIORITY_ARRAY);
549
550         cs->sc_flags |= CCDF_INITED;
551         cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
552         cs->sc_unit = ccd->ccd_unit;
553         return (0);
554 fail:
555         while (ci > cs->sc_cinfo) {
556                 ci--;
557                 free(ci->ci_path, M_DEVBUF);
558         }
559         free(cs->sc_cinfo, M_DEVBUF);
560         return (error);
561 }
562
563 static void
564 ccdinterleave(cs, unit)
565         struct ccd_softc *cs;
566         int unit;
567 {
568         struct ccdcinfo *ci, *smallci;
569         struct ccdiinfo *ii;
570         daddr_t bn, lbn;
571         int ix;
572         u_long size;
573
574 #ifdef DEBUG
575         if (ccddebug & CCDB_INIT)
576                 printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
577 #endif
578
579         /*
580          * Allocate an interleave table.  The worst case occurs when each
581          * of N disks is of a different size, resulting in N interleave
582          * tables.
583          *
584          * Chances are this is too big, but we don't care.
585          */
586         size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
587         cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
588         bzero((caddr_t)cs->sc_itable, size);
589
590         /*
591          * Trivial case: no interleave (actually interleave of disk size).
592          * Each table entry represents a single component in its entirety.
593          *
594          * An interleave of 0 may not be used with a mirror or parity setup.
595          */
596         if (cs->sc_ileave == 0) {
597                 bn = 0;
598                 ii = cs->sc_itable;
599
600                 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
601                         /* Allocate space for ii_index. */
602                         ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
603                         ii->ii_ndisk = 1;
604                         ii->ii_startblk = bn;
605                         ii->ii_startoff = 0;
606                         ii->ii_index[0] = ix;
607                         bn += cs->sc_cinfo[ix].ci_size;
608                         ii++;
609                 }
610                 ii->ii_ndisk = 0;
611 #ifdef DEBUG
612                 if (ccddebug & CCDB_INIT)
613                         printiinfo(cs->sc_itable);
614 #endif
615                 return;
616         }
617
618         /*
619          * The following isn't fast or pretty; it doesn't have to be.
620          */
621         size = 0;
622         bn = lbn = 0;
623         for (ii = cs->sc_itable; ; ii++) {
624                 /*
625                  * Allocate space for ii_index.  We might allocate more then
626                  * we use.
627                  */
628                 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
629                     M_DEVBUF, M_WAITOK);
630
631                 /*
632                  * Locate the smallest of the remaining components
633                  */
634                 smallci = NULL;
635                 for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; 
636                     ci++) {
637                         if (ci->ci_size > size &&
638                             (smallci == NULL ||
639                              ci->ci_size < smallci->ci_size)) {
640                                 smallci = ci;
641                         }
642                 }
643
644                 /*
645                  * Nobody left, all done
646                  */
647                 if (smallci == NULL) {
648                         ii->ii_ndisk = 0;
649                         break;
650                 }
651
652                 /*
653                  * Record starting logical block using an sc_ileave blocksize.
654                  */
655                 ii->ii_startblk = bn / cs->sc_ileave;
656
657                 /*
658                  * Record starting comopnent block using an sc_ileave 
659                  * blocksize.  This value is relative to the beginning of
660                  * a component disk.
661                  */
662                 ii->ii_startoff = lbn;
663
664                 /*
665                  * Determine how many disks take part in this interleave
666                  * and record their indices.
667                  */
668                 ix = 0;
669                 for (ci = cs->sc_cinfo; 
670                     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
671                         if (ci->ci_size >= smallci->ci_size) {
672                                 ii->ii_index[ix++] = ci - cs->sc_cinfo;
673                         }
674                 }
675                 ii->ii_ndisk = ix;
676                 bn += ix * (smallci->ci_size - size);
677                 lbn = smallci->ci_size / cs->sc_ileave;
678                 size = smallci->ci_size;
679         }
680 #ifdef DEBUG
681         if (ccddebug & CCDB_INIT)
682                 printiinfo(cs->sc_itable);
683 #endif
684 }
685
686 /* ARGSUSED */
687 static int
688 ccdopen(dev, flags, fmt, p)
689         dev_t dev;
690         int flags, fmt;
691         struct proc *p;
692 {
693         int unit = ccdunit(dev);
694         struct ccd_softc *cs;
695         struct disklabel *lp;
696         int error = 0, part, pmask;
697
698 #ifdef DEBUG
699         if (ccddebug & CCDB_FOLLOW)
700                 printf("ccdopen(%x, %x)\n", dev, flags);
701 #endif
702         if (unit >= numccd)
703                 return (ENXIO);
704         cs = &ccd_softc[unit];
705
706         if ((error = ccdlock(cs)) != 0)
707                 return (error);
708
709         lp = &cs->sc_label;
710
711         part = ccdpart(dev);
712         pmask = (1 << part);
713
714         /*
715          * If we're initialized, check to see if there are any other
716          * open partitions.  If not, then it's safe to update
717          * the in-core disklabel.
718          */
719         if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
720                 ccdgetdisklabel(dev);
721
722         /* Check that the partition exists. */
723         if (part != RAW_PART && ((part >= lp->d_npartitions) ||
724             (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
725                 error = ENXIO;
726                 goto done;
727         }
728
729         cs->sc_openmask |= pmask;
730  done:
731         ccdunlock(cs);
732         return (0);
733 }
734
735 /* ARGSUSED */
736 static int
737 ccdclose(dev, flags, fmt, p)
738         dev_t dev;
739         int flags, fmt;
740         struct proc *p;
741 {
742         int unit = ccdunit(dev);
743         struct ccd_softc *cs;
744         int error = 0, part;
745
746 #ifdef DEBUG
747         if (ccddebug & CCDB_FOLLOW)
748                 printf("ccdclose(%x, %x)\n", dev, flags);
749 #endif
750
751         if (unit >= numccd)
752                 return (ENXIO);
753         cs = &ccd_softc[unit];
754
755         if ((error = ccdlock(cs)) != 0)
756                 return (error);
757
758         part = ccdpart(dev);
759
760         /* ...that much closer to allowing unconfiguration... */
761         cs->sc_openmask &= ~(1 << part);
762         ccdunlock(cs);
763         return (0);
764 }
765
766 static void
767 ccdstrategy(bp)
768         struct buf *bp;
769 {
770         int unit = ccdunit(bp->b_dev);
771         struct ccd_softc *cs = &ccd_softc[unit];
772         int s;
773         int wlabel;
774         struct disklabel *lp;
775
776 #ifdef DEBUG
777         if (ccddebug & CCDB_FOLLOW)
778                 printf("ccdstrategy(%x): unit %d\n", bp, unit);
779 #endif
780         if ((cs->sc_flags & CCDF_INITED) == 0) {
781                 bp->b_error = ENXIO;
782                 bp->b_flags |= B_ERROR;
783                 goto done;
784         }
785
786         /* If it's a nil transfer, wake up the top half now. */
787         if (bp->b_bcount == 0)
788                 goto done;
789
790         lp = &cs->sc_label;
791
792         /*
793          * Do bounds checking and adjust transfer.  If there's an
794          * error, the bounds check will flag that for us.
795          */
796         wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
797         if (ccdpart(bp->b_dev) != RAW_PART) {
798                 if (bounds_check_with_label(bp, lp, wlabel) <= 0)
799                         goto done;
800         } else {
801                 int pbn;        /* in sc_secsize chunks */
802                 long sz;        /* in sc_secsize chunks */
803
804                 pbn = bp->b_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
805                 sz = howmany(bp->b_bcount, cs->sc_geom.ccg_secsize);
806
807                 /*
808                  * If out of bounds return an error. If at the EOF point,
809                  * simply read or write less.
810                  */
811
812                 if (pbn < 0 || pbn >= cs->sc_size) {
813                         bp->b_resid = bp->b_bcount;
814                         if (pbn != cs->sc_size) {
815                                 bp->b_error = EINVAL;
816                                 bp->b_flags |= B_ERROR | B_INVAL;
817                         }
818                         goto done;
819                 }
820
821                 /*
822                  * If the request crosses EOF, truncate the request.
823                  */
824                 if (pbn + sz > cs->sc_size) {
825                         bp->b_bcount = (cs->sc_size - pbn) * 
826                             cs->sc_geom.ccg_secsize;
827                 }
828         }
829
830         bp->b_resid = bp->b_bcount;
831
832         /*
833          * "Start" the unit.
834          */
835         s = splbio();
836         ccdstart(cs, bp);
837         splx(s);
838         return;
839 done:
840         biodone(bp);
841 }
842
843 static void
844 ccdstart(cs, bp)
845         struct ccd_softc *cs;
846         struct buf *bp;
847 {
848         long bcount, rcount;
849         struct ccdbuf *cbp[4];
850         /* XXX! : 2 reads and 2 writes for RAID 4/5 */
851         caddr_t addr;
852         daddr_t bn;
853         struct partition *pp;
854
855 #ifdef DEBUG
856         if (ccddebug & CCDB_FOLLOW)
857                 printf("ccdstart(%x, %x)\n", cs, bp);
858 #endif
859
860         /* Record the transaction start  */
861         devstat_start_transaction(&cs->device_stats);
862
863         /*
864          * Translate the partition-relative block number to an absolute.
865          */
866         bn = bp->b_blkno;
867         if (ccdpart(bp->b_dev) != RAW_PART) {
868                 pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)];
869                 bn += pp->p_offset;
870         }
871
872         /*
873          * Allocate component buffers and fire off the requests
874          */
875         addr = bp->b_data;
876         for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
877                 ccdbuffer(cbp, cs, bp, bn, addr, bcount);
878                 rcount = cbp[0]->cb_buf.b_bcount;
879
880                 if (cs->sc_cflags & CCDF_MIRROR) {
881                         /*
882                          * Mirroring.  Writes go to both disks, reads are
883                          * taken from whichever disk seems most appropriate.
884                          *
885                          * We attempt to localize reads to the disk whos arm
886                          * is nearest the read request.  We ignore seeks due
887                          * to writes when making this determination and we
888                          * also try to avoid hogging.
889                          */
890                         if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) {
891                                 cbp[0]->cb_buf.b_vp->v_numoutput++;
892                                 cbp[1]->cb_buf.b_vp->v_numoutput++;
893                                 VOP_STRATEGY(cbp[0]->cb_buf.b_vp, 
894                                     &cbp[0]->cb_buf);
895                                 VOP_STRATEGY(cbp[1]->cb_buf.b_vp, 
896                                     &cbp[1]->cb_buf);
897                         } else {
898                                 int pick = cs->sc_pick;
899                                 daddr_t range = cs->sc_size / 16;
900
901                                 if (bn < cs->sc_blk[pick] - range ||
902                                     bn > cs->sc_blk[pick] + range
903                                 ) {
904                                         cs->sc_pick = pick = 1 - pick;
905                                 }
906                                 cs->sc_blk[pick] = bn + btodb(rcount);
907                                 VOP_STRATEGY(cbp[pick]->cb_buf.b_vp, 
908                                     &cbp[pick]->cb_buf);
909                         }
910                 } else {
911                         /*
912                          * Not mirroring
913                          */
914                         if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
915                                 cbp[0]->cb_buf.b_vp->v_numoutput++;
916                         VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf);
917                 }
918                 bn += btodb(rcount);
919                 addr += rcount;
920         }
921 }
922
923 /*
924  * Build a component buffer header.
925  */
926 static void
927 ccdbuffer(cb, cs, bp, bn, addr, bcount)
928         struct ccdbuf **cb;
929         struct ccd_softc *cs;
930         struct buf *bp;
931         daddr_t bn;
932         caddr_t addr;
933         long bcount;
934 {
935         struct ccdcinfo *ci, *ci2 = NULL;       /* XXX */
936         struct ccdbuf *cbp;
937         daddr_t cbn, cboff;
938         off_t cbc;
939
940 #ifdef DEBUG
941         if (ccddebug & CCDB_IO)
942                 printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
943                        cs, bp, bn, addr, bcount);
944 #endif
945         /*
946          * Determine which component bn falls in.
947          */
948         cbn = bn;
949         cboff = 0;
950
951         if (cs->sc_ileave == 0) {
952                 /*
953                  * Serially concatenated and neither a mirror nor a parity
954                  * config.  This is a special case.
955                  */
956                 daddr_t sblk;
957
958                 sblk = 0;
959                 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
960                         sblk += ci->ci_size;
961                 cbn -= sblk;
962         } else {
963                 struct ccdiinfo *ii;
964                 int ccdisk, off;
965
966                 /*
967                  * Calculate cbn, the logical superblock (sc_ileave chunks),
968                  * and cboff, a normal block offset (DEV_BSIZE chunks) relative
969                  * to cbn.
970                  */
971                 cboff = cbn % cs->sc_ileave;    /* DEV_BSIZE gran */
972                 cbn = cbn / cs->sc_ileave;      /* DEV_BSIZE * ileave gran */
973
974                 /*
975                  * Figure out which interleave table to use.
976                  */
977                 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
978                         if (ii->ii_startblk > cbn)
979                                 break;
980                 }
981                 ii--;
982
983                 /*
984                  * off is the logical superblock relative to the beginning 
985                  * of this interleave block.  
986                  */
987                 off = cbn - ii->ii_startblk;
988
989                 /*
990                  * We must calculate which disk component to use (ccdisk),
991                  * and recalculate cbn to be the superblock relative to
992                  * the beginning of the component.  This is typically done by
993                  * adding 'off' and ii->ii_startoff together.  However, 'off'
994                  * must typically be divided by the number of components in
995                  * this interleave array to be properly convert it from a
996                  * CCD-relative logical superblock number to a 
997                  * component-relative superblock number.
998                  */
999                 if (ii->ii_ndisk == 1) {
1000                         /*
1001                          * When we have just one disk, it can't be a mirror
1002                          * or a parity config.
1003                          */
1004                         ccdisk = ii->ii_index[0];
1005                         cbn = ii->ii_startoff + off;
1006                 } else {
1007                         if (cs->sc_cflags & CCDF_MIRROR) {
1008                                 /*
1009                                  * We have forced a uniform mapping, resulting
1010                                  * in a single interleave array.  We double
1011                                  * up on the first half of the available
1012                                  * components and our mirror is in the second
1013                                  * half.  This only works with a single 
1014                                  * interleave array because doubling up
1015                                  * doubles the number of sectors, so there
1016                                  * cannot be another interleave array because
1017                                  * the next interleave array's calculations
1018                                  * would be off.
1019                                  */
1020                                 int ndisk2 = ii->ii_ndisk / 2;
1021                                 ccdisk = ii->ii_index[off % ndisk2];
1022                                 cbn = ii->ii_startoff + off / ndisk2;
1023                                 ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
1024                         } else if (cs->sc_cflags & CCDF_PARITY) {
1025                                 /* 
1026                                  * XXX not implemented yet
1027                                  */
1028                                 int ndisk2 = ii->ii_ndisk - 1;
1029                                 ccdisk = ii->ii_index[off % ndisk2];
1030                                 cbn = ii->ii_startoff + off / ndisk2;
1031                                 if (cbn % ii->ii_ndisk <= ccdisk)
1032                                         ccdisk++;
1033                         } else {
1034                                 ccdisk = ii->ii_index[off % ii->ii_ndisk];
1035                                 cbn = ii->ii_startoff + off / ii->ii_ndisk;
1036                         }
1037                 }
1038
1039                 ci = &cs->sc_cinfo[ccdisk];
1040
1041                 /*
1042                  * Convert cbn from a superblock to a normal block so it
1043                  * can be used to calculate (along with cboff) the normal
1044                  * block index into this particular disk.
1045                  */
1046                 cbn *= cs->sc_ileave;
1047         }
1048
1049         /*
1050          * Fill in the component buf structure.
1051          */
1052         cbp = getccdbuf(NULL);
1053         cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
1054         cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone;
1055         cbp->cb_buf.b_dev = ci->ci_dev;         /* XXX */
1056         cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET;
1057         cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET);
1058         cbp->cb_buf.b_data = addr;
1059         cbp->cb_buf.b_vp = ci->ci_vp;
1060         if (cs->sc_ileave == 0)
1061               cbc = dbtob((off_t)(ci->ci_size - cbn));
1062         else
1063               cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1064         cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1065         cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1066
1067         /*
1068          * context for ccdiodone
1069          */
1070         cbp->cb_obp = bp;
1071         cbp->cb_unit = cs - ccd_softc;
1072         cbp->cb_comp = ci - cs->sc_cinfo;
1073
1074 #ifdef DEBUG
1075         if (ccddebug & CCDB_IO)
1076                 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
1077                        ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
1078                        cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1079 #endif
1080         cb[0] = cbp;
1081
1082         /*
1083          * Note: both I/O's setup when reading from mirror, but only one
1084          * will be executed.
1085          */
1086         if (cs->sc_cflags & CCDF_MIRROR) {
1087                 /* mirror, setup second I/O */
1088                 cbp = getccdbuf(cb[0]);
1089                 cbp->cb_buf.b_dev = ci2->ci_dev;
1090                 cbp->cb_buf.b_vp = ci2->ci_vp;
1091                 cbp->cb_comp = ci2 - cs->sc_cinfo;
1092                 cb[1] = cbp;
1093                 /* link together the ccdbuf's and clear "mirror done" flag */
1094                 cb[0]->cb_mirror = cb[1];
1095                 cb[1]->cb_mirror = cb[0];
1096                 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1097                 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1098         }
1099 }
1100
1101 static void
1102 ccdintr(cs, bp)
1103         struct ccd_softc *cs;
1104         struct buf *bp;
1105 {
1106 #ifdef DEBUG
1107         if (ccddebug & CCDB_FOLLOW)
1108                 printf("ccdintr(%x, %x)\n", cs, bp);
1109 #endif
1110         /*
1111          * Request is done for better or worse, wakeup the top half.
1112          */
1113         if (bp->b_flags & B_ERROR)
1114                 bp->b_resid = bp->b_bcount;
1115         devstat_end_transaction_buf(&cs->device_stats, bp);
1116         biodone(bp);
1117 }
1118
1119 /*
1120  * Called at interrupt time.
1121  * Mark the component as done and if all components are done,
1122  * take a ccd interrupt.
1123  */
1124 static void
1125 ccdiodone(cbp)
1126         struct ccdbuf *cbp;
1127 {
1128         struct buf *bp = cbp->cb_obp;
1129         int unit = cbp->cb_unit;
1130         int count, s;
1131
1132         s = splbio();
1133 #ifdef DEBUG
1134         if (ccddebug & CCDB_FOLLOW)
1135                 printf("ccdiodone(%x)\n", cbp);
1136         if (ccddebug & CCDB_IO) {
1137                 printf("ccdiodone: bp %x bcount %d resid %d\n",
1138                        bp, bp->b_bcount, bp->b_resid);
1139                 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1140                        cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1141                        cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1142                        cbp->cb_buf.b_bcount);
1143         }
1144 #endif
1145         /*
1146          * If an error occured, report it.  If this is a mirrored 
1147          * configuration and the first of two possible reads, do not
1148          * set the error in the bp yet because the second read may
1149          * succeed.
1150          */
1151
1152         if (cbp->cb_buf.b_flags & B_ERROR) {
1153                 const char *msg = "";
1154
1155                 if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
1156                     (cbp->cb_buf.b_flags & B_READ) &&
1157                     (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1158                         /*
1159                          * We will try our read on the other disk down
1160                          * below, also reverse the default pick so if we 
1161                          * are doing a scan we do not keep hitting the
1162                          * bad disk first.
1163                          */
1164                         struct ccd_softc *cs = &ccd_softc[unit];
1165
1166                         msg = ", trying other disk";
1167                         cs->sc_pick = 1 - cs->sc_pick;
1168                         cs->sc_blk[cs->sc_pick] = bp->b_blkno;
1169                 } else {
1170                         bp->b_flags |= B_ERROR;
1171                         bp->b_error = cbp->cb_buf.b_error ? 
1172                             cbp->cb_buf.b_error : EIO;
1173                 }
1174                 printf("ccd%d: error %d on component %d block %d (ccd block %d)%s\n",
1175                        unit, bp->b_error, cbp->cb_comp, 
1176                        (int)cbp->cb_buf.b_blkno, bp->b_blkno, msg);
1177         }
1178
1179         /*
1180          * Process mirror.  If we are writing, I/O has been initiated on both
1181          * buffers and we fall through only after both are finished.
1182          *
1183          * If we are reading only one I/O is initiated at a time.  If an
1184          * error occurs we initiate the second I/O and return, otherwise 
1185          * we free the second I/O without initiating it.
1186          */
1187
1188         if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
1189                 if ((cbp->cb_buf.b_flags & B_READ) == 0) {
1190                         /*
1191                          * When writing, handshake with the second buffer
1192                          * to determine when both are done.  If both are not
1193                          * done, return here.
1194                          */
1195                         if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1196                                 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1197                                 putccdbuf(cbp);
1198                                 splx(s);
1199                                 return;
1200                         }
1201                 } else {
1202                         /*
1203                          * When reading, either dispose of the second buffer
1204                          * or initiate I/O on the second buffer if an error 
1205                          * occured with this one.
1206                          */
1207                         if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1208                                 if (cbp->cb_buf.b_flags & B_ERROR) {
1209                                         cbp->cb_mirror->cb_pflags |= 
1210                                             CCDPF_MIRROR_DONE;
1211                                         VOP_STRATEGY(
1212                                             cbp->cb_mirror->cb_buf.b_vp, 
1213                                             &cbp->cb_mirror->cb_buf
1214                                         );
1215                                         putccdbuf(cbp);
1216                                         splx(s);
1217                                         return;
1218                                 } else {
1219                                         putccdbuf(cbp->cb_mirror);
1220                                         /* fall through */
1221                                 }
1222                         }
1223                 }
1224         }
1225
1226         /*
1227          * use b_bufsize to determine how big the original request was rather
1228          * then b_bcount, because b_bcount may have been truncated for EOF.
1229          *
1230          * XXX We check for an error, but we do not test the resid for an
1231          * aligned EOF condition.  This may result in character & block
1232          * device access not recognizing EOF properly when read or written 
1233          * sequentially, but will not effect filesystems.
1234          */
1235         count = cbp->cb_buf.b_bufsize;
1236         putccdbuf(cbp);
1237
1238         /*
1239          * If all done, "interrupt".
1240          */
1241         bp->b_resid -= count;
1242         if (bp->b_resid < 0)
1243                 panic("ccdiodone: count");
1244         if (bp->b_resid == 0)
1245                 ccdintr(&ccd_softc[unit], bp);
1246         splx(s);
1247 }
1248
1249 static int
1250 ccdioctl(dev, cmd, data, flag, p)
1251         dev_t dev;
1252         u_long cmd;
1253         caddr_t data;
1254         int flag;
1255         struct proc *p;
1256 {
1257         int unit = ccdunit(dev);
1258         int i, j, lookedup = 0, error = 0;
1259         int part, pmask, s;
1260         struct ccd_softc *cs;
1261         struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1262         struct ccddevice ccd;
1263         char **cpp;
1264         struct vnode **vpp;
1265
1266         if (unit >= numccd)
1267                 return (ENXIO);
1268         cs = &ccd_softc[unit];
1269
1270         bzero(&ccd, sizeof(ccd));
1271
1272         switch (cmd) {
1273         case CCDIOCSET:
1274                 if (cs->sc_flags & CCDF_INITED)
1275                         return (EBUSY);
1276
1277                 if ((flag & FWRITE) == 0)
1278                         return (EBADF);
1279
1280                 if ((error = ccdlock(cs)) != 0)
1281                         return (error);
1282
1283                 /* Fill in some important bits. */
1284                 ccd.ccd_unit = unit;
1285                 ccd.ccd_interleave = ccio->ccio_ileave;
1286                 if (ccd.ccd_interleave == 0 &&
1287                     ((ccio->ccio_flags & CCDF_MIRROR) ||
1288                      (ccio->ccio_flags & CCDF_PARITY))) {
1289                         printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1290                         ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1291                 }
1292                 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1293                     (ccio->ccio_flags & CCDF_PARITY)) {
1294                         printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1295                         ccio->ccio_flags &= ~CCDF_PARITY;
1296                 }
1297                 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1298                     !(ccio->ccio_flags & CCDF_UNIFORM)) {
1299                         printf("ccd%d: mirror/parity forces uniform flag\n",
1300                                unit);
1301                         ccio->ccio_flags |= CCDF_UNIFORM;
1302                 }
1303                 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1304
1305                 /*
1306                  * Allocate space for and copy in the array of
1307                  * componet pathnames and device numbers.
1308                  */
1309                 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1310                     M_DEVBUF, M_WAITOK);
1311                 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1312                     M_DEVBUF, M_WAITOK);
1313
1314                 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1315                     ccio->ccio_ndisks * sizeof(char **));
1316                 if (error) {
1317                         free(vpp, M_DEVBUF);
1318                         free(cpp, M_DEVBUF);
1319                         ccdunlock(cs);
1320                         return (error);
1321                 }
1322
1323 #ifdef DEBUG
1324                 if (ccddebug & CCDB_INIT)
1325                         for (i = 0; i < ccio->ccio_ndisks; ++i)
1326                                 printf("ccdioctl: component %d: 0x%x\n",
1327                                     i, cpp[i]);
1328 #endif
1329
1330                 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1331 #ifdef DEBUG
1332                         if (ccddebug & CCDB_INIT)
1333                                 printf("ccdioctl: lookedup = %d\n", lookedup);
1334 #endif
1335                         if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1336                                 for (j = 0; j < lookedup; ++j)
1337                                         (void)vn_close(vpp[j], FREAD|FWRITE,
1338                                             p->p_ucred, p);
1339                                 free(vpp, M_DEVBUF);
1340                                 free(cpp, M_DEVBUF);
1341                                 ccdunlock(cs);
1342                                 return (error);
1343                         }
1344                         ++lookedup;
1345                 }
1346                 ccd.ccd_cpp = cpp;
1347                 ccd.ccd_vpp = vpp;
1348                 ccd.ccd_ndev = ccio->ccio_ndisks;
1349
1350                 /*
1351                  * Initialize the ccd.  Fills in the softc for us.
1352                  */
1353                 if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1354                         for (j = 0; j < lookedup; ++j)
1355                                 (void)vn_close(vpp[j], FREAD|FWRITE,
1356                                     p->p_ucred, p);
1357                         bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1358                         free(vpp, M_DEVBUF);
1359                         free(cpp, M_DEVBUF);
1360                         ccdunlock(cs);
1361                         return (error);
1362                 }
1363
1364                 /*
1365                  * The ccd has been successfully initialized, so
1366                  * we can place it into the array and read the disklabel.
1367                  */
1368                 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1369                 ccio->ccio_unit = unit;
1370                 ccio->ccio_size = cs->sc_size;
1371                 ccdgetdisklabel(dev);
1372
1373                 ccdunlock(cs);
1374
1375                 break;
1376
1377         case CCDIOCCLR:
1378                 if ((cs->sc_flags & CCDF_INITED) == 0)
1379                         return (ENXIO);
1380
1381                 if ((flag & FWRITE) == 0)
1382                         return (EBADF);
1383
1384                 if ((error = ccdlock(cs)) != 0)
1385                         return (error);
1386
1387                 /* Don't unconfigure if any other partitions are open */
1388                 part = ccdpart(dev);
1389                 pmask = (1 << part);
1390                 if ((cs->sc_openmask & ~pmask)) {
1391                         ccdunlock(cs);
1392                         return (EBUSY);
1393                 }
1394
1395                 /*
1396                  * Free ccd_softc information and clear entry.
1397                  */
1398
1399                 /* Close the components and free their pathnames. */
1400                 for (i = 0; i < cs->sc_nccdisks; ++i) {
1401                         /*
1402                          * XXX: this close could potentially fail and
1403                          * cause Bad Things.  Maybe we need to force
1404                          * the close to happen?
1405                          */
1406 #ifdef DEBUG
1407                         if (ccddebug & CCDB_VNODE)
1408                                 vprint("CCDIOCCLR: vnode info",
1409                                     cs->sc_cinfo[i].ci_vp);
1410 #endif
1411                         (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1412                             p->p_ucred, p);
1413                         free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1414                 }
1415
1416                 /* Free interleave index. */
1417                 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1418                         free(cs->sc_itable[i].ii_index, M_DEVBUF);
1419
1420                 /* Free component info and interleave table. */
1421                 free(cs->sc_cinfo, M_DEVBUF);
1422                 free(cs->sc_itable, M_DEVBUF);
1423                 cs->sc_flags &= ~CCDF_INITED;
1424
1425                 /*
1426                  * Free ccddevice information and clear entry.
1427                  */
1428                 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1429                 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1430                 ccd.ccd_dk = -1;
1431                 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1432
1433                 /*
1434                  * And remove the devstat entry.
1435                  */
1436                 devstat_remove_entry(&cs->device_stats);
1437
1438                 /* This must be atomic. */
1439                 s = splhigh();
1440                 ccdunlock(cs);
1441                 bzero(cs, sizeof(struct ccd_softc));
1442                 splx(s);
1443
1444                 break;
1445
1446         case DIOCGDINFO:
1447                 if ((cs->sc_flags & CCDF_INITED) == 0)
1448                         return (ENXIO);
1449
1450                 *(struct disklabel *)data = cs->sc_label;
1451                 break;
1452
1453         case DIOCGPART:
1454                 if ((cs->sc_flags & CCDF_INITED) == 0)
1455                         return (ENXIO);
1456
1457                 ((struct partinfo *)data)->disklab = &cs->sc_label;
1458                 ((struct partinfo *)data)->part =
1459                     &cs->sc_label.d_partitions[ccdpart(dev)];
1460                 break;
1461
1462         case DIOCWDINFO:
1463         case DIOCSDINFO:
1464                 if ((cs->sc_flags & CCDF_INITED) == 0)
1465                         return (ENXIO);
1466
1467                 if ((flag & FWRITE) == 0)
1468                         return (EBADF);
1469
1470                 if ((error = ccdlock(cs)) != 0)
1471                         return (error);
1472
1473                 cs->sc_flags |= CCDF_LABELLING;
1474
1475                 error = setdisklabel(&cs->sc_label,
1476                     (struct disklabel *)data, 0);
1477                 if (error == 0) {
1478                         if (cmd == DIOCWDINFO)
1479                                 error = writedisklabel(CCDLABELDEV(dev),
1480                                     &cs->sc_label);
1481                 }
1482
1483                 cs->sc_flags &= ~CCDF_LABELLING;
1484
1485                 ccdunlock(cs);
1486
1487                 if (error)
1488                         return (error);
1489                 break;
1490
1491         case DIOCWLABEL:
1492                 if ((cs->sc_flags & CCDF_INITED) == 0)
1493                         return (ENXIO);
1494
1495                 if ((flag & FWRITE) == 0)
1496                         return (EBADF);
1497                 if (*(int *)data != 0)
1498                         cs->sc_flags |= CCDF_WLABEL;
1499                 else
1500                         cs->sc_flags &= ~CCDF_WLABEL;
1501                 break;
1502
1503         default:
1504                 return (ENOTTY);
1505         }
1506
1507         return (0);
1508 }
1509
1510 static int
1511 ccdsize(dev)
1512         dev_t dev;
1513 {
1514         struct ccd_softc *cs;
1515         int part, size;
1516
1517         if (ccdopen(dev, 0, S_IFCHR, curproc))
1518                 return (-1);
1519
1520         cs = &ccd_softc[ccdunit(dev)];
1521         part = ccdpart(dev);
1522
1523         if ((cs->sc_flags & CCDF_INITED) == 0)
1524                 return (-1);
1525
1526         if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1527                 size = -1;
1528         else
1529                 size = cs->sc_label.d_partitions[part].p_size;
1530
1531         if (ccdclose(dev, 0, S_IFCHR, curproc))
1532                 return (-1);
1533
1534         return (size);
1535 }
1536
1537 static int
1538 ccddump(dev)
1539         dev_t dev;
1540 {
1541
1542         /* Not implemented. */
1543         return ENXIO;
1544 }
1545
1546 /*
1547  * Lookup the provided name in the filesystem.  If the file exists,
1548  * is a valid block device, and isn't being used by anyone else,
1549  * set *vpp to the file's vnode.
1550  */
1551 static int
1552 ccdlookup(path, p, vpp)
1553         char *path;
1554         struct proc *p;
1555         struct vnode **vpp;     /* result */
1556 {
1557         struct nameidata nd;
1558         struct vnode *vp;
1559         int error;
1560
1561         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1562         if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1563 #ifdef DEBUG
1564                 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1565                         printf("ccdlookup: vn_open error = %d\n", error);
1566 #endif
1567                 return (error);
1568         }
1569         vp = nd.ni_vp;
1570
1571         if (vp->v_usecount > 1) {
1572                 error = EBUSY;
1573                 goto bad;
1574         }
1575
1576         if (!vn_isdisk(vp, &error)) 
1577                 goto bad;
1578
1579 #ifdef DEBUG
1580         if (ccddebug & CCDB_VNODE)
1581                 vprint("ccdlookup: vnode info", vp);
1582 #endif
1583
1584         VOP_UNLOCK(vp, 0, p);
1585         NDFREE(&nd, NDF_ONLY_PNBUF);
1586         *vpp = vp;
1587         return (0);
1588 bad:
1589         VOP_UNLOCK(vp, 0, p);
1590         NDFREE(&nd, NDF_ONLY_PNBUF);
1591         /* vn_close does vrele() for vp */
1592         (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1593         return (error);
1594 }
1595
1596 /*
1597  * Read the disklabel from the ccd.  If one is not present, fake one
1598  * up.
1599  */
1600 static void
1601 ccdgetdisklabel(dev)
1602         dev_t dev;
1603 {
1604         int unit = ccdunit(dev);
1605         struct ccd_softc *cs = &ccd_softc[unit];
1606         char *errstring;
1607         struct disklabel *lp = &cs->sc_label;
1608         struct ccdgeom *ccg = &cs->sc_geom;
1609
1610         bzero(lp, sizeof(*lp));
1611
1612         lp->d_secperunit = cs->sc_size;
1613         lp->d_secsize = ccg->ccg_secsize;
1614         lp->d_nsectors = ccg->ccg_nsectors;
1615         lp->d_ntracks = ccg->ccg_ntracks;
1616         lp->d_ncylinders = ccg->ccg_ncylinders;
1617         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1618
1619         strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1620         lp->d_type = DTYPE_CCD;
1621         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1622         lp->d_rpm = 3600;
1623         lp->d_interleave = 1;
1624         lp->d_flags = 0;
1625
1626         lp->d_partitions[RAW_PART].p_offset = 0;
1627         lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1628         lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1629         lp->d_npartitions = RAW_PART + 1;
1630
1631         lp->d_bbsize = BBSIZE;                          /* XXX */
1632         lp->d_sbsize = SBSIZE;                          /* XXX */
1633
1634         lp->d_magic = DISKMAGIC;
1635         lp->d_magic2 = DISKMAGIC;
1636         lp->d_checksum = dkcksum(&cs->sc_label);
1637
1638         /*
1639          * Call the generic disklabel extraction routine.
1640          */
1641         errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label);
1642         if (errstring != NULL)
1643                 ccdmakedisklabel(cs);
1644
1645 #ifdef DEBUG
1646         /* It's actually extremely common to have unlabeled ccds. */
1647         if (ccddebug & CCDB_LABEL)
1648                 if (errstring != NULL)
1649                         printf("ccd%d: %s\n", unit, errstring);
1650 #endif
1651 }
1652
1653 /*
1654  * Take care of things one might want to take care of in the event
1655  * that a disklabel isn't present.
1656  */
1657 static void
1658 ccdmakedisklabel(cs)
1659         struct ccd_softc *cs;
1660 {
1661         struct disklabel *lp = &cs->sc_label;
1662
1663         /*
1664          * For historical reasons, if there's no disklabel present
1665          * the raw partition must be marked FS_BSDFFS.
1666          */
1667         lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1668
1669         strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1670 }
1671
1672 /*
1673  * Wait interruptibly for an exclusive lock.
1674  *
1675  * XXX
1676  * Several drivers do this; it should be abstracted and made MP-safe.
1677  */
1678 static int
1679 ccdlock(cs)
1680         struct ccd_softc *cs;
1681 {
1682         int error;
1683
1684         while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1685                 cs->sc_flags |= CCDF_WANTED;
1686                 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1687                         return (error);
1688         }
1689         cs->sc_flags |= CCDF_LOCKED;
1690         return (0);
1691 }
1692
1693 /*
1694  * Unlock and wake up any waiters.
1695  */
1696 static void
1697 ccdunlock(cs)
1698         struct ccd_softc *cs;
1699 {
1700
1701         cs->sc_flags &= ~CCDF_LOCKED;
1702         if ((cs->sc_flags & CCDF_WANTED) != 0) {
1703                 cs->sc_flags &= ~CCDF_WANTED;
1704                 wakeup(cs);
1705         }
1706 }
1707
1708 #ifdef DEBUG
1709 static void
1710 printiinfo(ii)
1711         struct ccdiinfo *ii;
1712 {
1713         int ix, i;
1714
1715         for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1716                 printf(" itab[%d]: #dk %d sblk %d soff %d",
1717                        ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1718                 for (i = 0; i < ii->ii_ndisk; i++)
1719                         printf(" %d", ii->ii_index[i]);
1720                 printf("\n");
1721         }
1722 }
1723 #endif
1724
1725 \f
1726 /* Local Variables: */
1727 /* c-argdecl-indent: 8 */
1728 /* c-continued-statement-offset: 8 */
1729 /* c-indent-level: 8 */
1730 /* End: */