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