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