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