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