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