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