]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/geom_ccd.c
This commit was generated by cvs2svn to compensate for changes in r48114,
[FreeBSD/FreeBSD.git] / sys / geom / geom_ccd.c
1 /* $Id: ccd.c,v 1.47 1999/05/11 19:54:00 phk 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 #if NCCD > 0
92
93 #include <sys/param.h>
94 #include <sys/systm.h>
95 #include <sys/kernel.h>
96 #include <sys/module.h>
97 #include <sys/proc.h>
98 #include <sys/buf.h>
99 #include <sys/malloc.h>
100 #include <sys/namei.h>
101 #include <sys/conf.h>
102 #include <sys/stat.h>
103 #include <sys/sysctl.h>
104 #include <sys/disklabel.h>
105 #include <ufs/ffs/fs.h> 
106 #include <sys/device.h>
107 #include <sys/devicestat.h>
108 #include <sys/fcntl.h>
109 #include <sys/vnode.h>
110
111 #include <sys/ccdvar.h>
112
113 #if defined(CCDDEBUG) && !defined(DEBUG)
114 #define DEBUG
115 #endif
116
117 #ifdef DEBUG
118 #define CCDB_FOLLOW     0x01
119 #define CCDB_INIT       0x02
120 #define CCDB_IO         0x04
121 #define CCDB_LABEL      0x08
122 #define CCDB_VNODE      0x10
123 static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
124     CCDB_VNODE;
125 SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
126 #undef DEBUG
127 #endif
128
129 #define ccdunit(x)      dkunit(x)
130 #define ccdpart(x)      dkpart(x)
131
132 /*
133    This is how mirroring works (only writes are special):
134
135    When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
136    linked together by the cb_mirror field.  "cb_pflags &
137    CCDPF_MIRROR_DONE" is set to 0 on both of them.
138
139    When a component returns to ccdiodone(), it checks if "cb_pflags &
140    CCDPF_MIRROR_DONE" is set or not.  If not, it sets the partner's
141    flag and returns.  If it is, it means its partner has already
142    returned, so it will go to the regular cleanup.
143
144  */
145
146 struct ccdbuf {
147         struct buf      cb_buf;         /* new I/O buf */
148         struct buf      *cb_obp;        /* ptr. to original I/O buf */
149         int             cb_unit;        /* target unit */
150         int             cb_comp;        /* target component */
151         int             cb_pflags;      /* mirror/parity status flag */
152         struct ccdbuf   *cb_mirror;     /* mirror counterpart */
153 };
154
155 /* bits in cb_pflags */
156 #define CCDPF_MIRROR_DONE 1     /* if set, mirror counterpart is done */
157
158 #define getccdbuf()             \
159         ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK))
160 #define putccdbuf(cbp)          \
161         free((caddr_t)(cbp), M_DEVBUF)
162
163 #define CCDLABELDEV(dev)        \
164         (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
165
166 static d_open_t ccdopen;
167 static d_close_t ccdclose;
168 static d_strategy_t ccdstrategy;
169 static d_ioctl_t ccdioctl;
170 static d_dump_t ccddump;
171 static d_psize_t ccdsize;
172
173 #define CDEV_MAJOR 74
174 #define BDEV_MAJOR 21
175
176 static struct cdevsw ccd_cdevsw = {
177         /* open */      ccdopen,
178         /* close */     ccdclose,
179         /* read */      physread,
180         /* write */     physwrite,
181         /* ioctl */     ccdioctl,
182         /* stop */      nostop,
183         /* reset */     noreset,
184         /* devtotty */  nodevtotty,
185         /* poll */      nopoll,
186         /* mmap */      nommap,
187         /* strategy */  ccdstrategy,
188         /* name */      "ccd",
189         /* parms */     noparms,
190         /* maj */       CDEV_MAJOR,
191         /* dump */      ccddump,
192         /* psize */     ccdsize,
193         /* flags */     D_DISK,
194         /* maxio */     0,
195         /* bmaj */      BDEV_MAJOR
196 };
197
198 /* called during module initialization */
199 static  void ccdattach __P((void));
200 static  int ccd_modevent __P((module_t, int, void *));
201
202 /* called by biodone() at interrupt time */
203 static  void ccdiodone __P((struct ccdbuf *cbp));
204
205 static  void ccdstart __P((struct ccd_softc *, struct buf *));
206 static  void ccdinterleave __P((struct ccd_softc *, int));
207 static  void ccdintr __P((struct ccd_softc *, struct buf *));
208 static  int ccdinit __P((struct ccddevice *, char **, struct proc *));
209 static  int ccdlookup __P((char *, struct proc *p, struct vnode **));
210 static  void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *,
211                 struct buf *, daddr_t, caddr_t, long));
212 static  void ccdgetdisklabel __P((dev_t));
213 static  void ccdmakedisklabel __P((struct ccd_softc *));
214 static  int ccdlock __P((struct ccd_softc *));
215 static  void ccdunlock __P((struct ccd_softc *));
216
217 #ifdef DEBUG
218 static  void printiinfo __P((struct ccdiinfo *));
219 #endif
220
221 /* Non-private for the benefit of libkvm. */
222 struct  ccd_softc *ccd_softc;
223 struct  ccddevice *ccddevs;
224 static  int numccd = 0;
225
226 /*
227  * Number of blocks to untouched in front of a component partition.
228  * This is to avoid violating its disklabel area when it starts at the
229  * beginning of the slice.
230  */
231 #if !defined(CCD_OFFSET)
232 #define CCD_OFFSET 16
233 #endif
234
235 /*
236  * Called by main() during pseudo-device attachment.  All we need
237  * to do is allocate enough space for devices to be configured later, and
238  * add devsw entries.
239  */
240 static void
241 ccdattach()
242 {
243         int i;
244         int num = NCCD;
245
246         if (num > 1)
247                 printf("ccd0-%d: Concatenated disk drivers\n", num-1);
248         else
249                 printf("ccd0: Concatenated disk driver\n");
250
251         ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
252             M_DEVBUF, M_NOWAIT);
253         ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
254             M_DEVBUF, M_NOWAIT);
255         if ((ccd_softc == NULL) || (ccddevs == NULL)) {
256                 printf("WARNING: no memory for concatenated disks\n");
257                 if (ccd_softc != NULL)
258                         free(ccd_softc, M_DEVBUF);
259                 if (ccddevs != NULL)
260                         free(ccddevs, M_DEVBUF);
261                 return;
262         }
263         numccd = num;
264         bzero(ccd_softc, num * sizeof(struct ccd_softc));
265         bzero(ccddevs, num * sizeof(struct ccddevice));
266
267         /* XXX: is this necessary? */
268         for (i = 0; i < numccd; ++i)
269                 ccddevs[i].ccd_dk = -1;
270 }
271
272 static int
273 ccd_modevent(mod, type, data)
274         module_t mod;
275         int type;
276         void *data;
277 {
278         int error = 0;
279
280         switch (type) {
281         case MOD_LOAD:
282                 ccdattach();
283                 break;
284
285         case MOD_UNLOAD:
286                 printf("ccd0: Unload not supported!\n");
287                 error = EOPNOTSUPP;
288                 break;
289
290         default:        /* MOD_SHUTDOWN etc */
291                 break;
292         }
293         return (error);
294 }
295
296 DEV_MODULE(ccd, CDEV_MAJOR, BDEV_MAJOR, ccd_cdevsw, ccd_modevent, NULL);
297
298 static int
299 ccdinit(ccd, cpaths, p)
300         struct ccddevice *ccd;
301         char **cpaths;
302         struct proc *p;
303 {
304         register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
305         register struct ccdcinfo *ci = NULL;    /* XXX */
306         register size_t size;
307         register int ix;
308         struct vnode *vp;
309         struct vattr va;
310         size_t minsize;
311         int maxsecsize;
312         struct partinfo dpart;
313         struct ccdgeom *ccg = &cs->sc_geom;
314         char tmppath[MAXPATHLEN];
315         int error;
316
317 #ifdef DEBUG
318         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
319                 printf("ccdinit: unit %d\n", ccd->ccd_unit);
320 #endif
321
322         cs->sc_size = 0;
323         cs->sc_ileave = ccd->ccd_interleave;
324         cs->sc_nccdisks = ccd->ccd_ndev;
325
326         /* Allocate space for the component info. */
327         cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
328             M_DEVBUF, M_WAITOK);
329
330         /*
331          * Verify that each component piece exists and record
332          * relevant information about it.
333          */
334         maxsecsize = 0;
335         minsize = 0;
336         for (ix = 0; ix < cs->sc_nccdisks; ix++) {
337                 vp = ccd->ccd_vpp[ix];
338                 ci = &cs->sc_cinfo[ix];
339                 ci->ci_vp = vp;
340
341                 /*
342                  * Copy in the pathname of the component.
343                  */
344                 bzero(tmppath, sizeof(tmppath));        /* sanity */
345                 if ((error = copyinstr(cpaths[ix], tmppath,
346                     MAXPATHLEN, &ci->ci_pathlen)) != 0) {
347 #ifdef DEBUG
348                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
349                                 printf("ccd%d: can't copy path, error = %d\n",
350                                     ccd->ccd_unit, error);
351 #endif
352                         while (ci > cs->sc_cinfo) {
353                                 ci--;
354                                 free(ci->ci_path, M_DEVBUF);
355                         }
356                         free(cs->sc_cinfo, M_DEVBUF);
357                         return (error);
358                 }
359                 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
360                 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
361
362                 /*
363                  * XXX: Cache the component's dev_t.
364                  */
365                 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
366 #ifdef DEBUG
367                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
368                                 printf("ccd%d: %s: getattr failed %s = %d\n",
369                                     ccd->ccd_unit, ci->ci_path,
370                                     "error", error);
371 #endif
372                         while (ci >= cs->sc_cinfo) {
373                                 free(ci->ci_path, M_DEVBUF);
374                                 ci--;
375                         }
376                         free(cs->sc_cinfo, M_DEVBUF);
377                         return (error);
378                 }
379                 ci->ci_dev = udev2dev(va.va_rdev, 2);
380
381                 /*
382                  * Get partition information for the component.
383                  */
384                 if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
385                     FREAD, p->p_ucred, p)) != 0) {
386 #ifdef DEBUG
387                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
388                                  printf("ccd%d: %s: ioctl failed, error = %d\n",
389                                      ccd->ccd_unit, ci->ci_path, error);
390 #endif
391                         while (ci >= cs->sc_cinfo) {
392                                 free(ci->ci_path, M_DEVBUF);
393                                 ci--;
394                         }
395                         free(cs->sc_cinfo, M_DEVBUF);
396                         return (error);
397                 }
398                 if (dpart.part->p_fstype == FS_BSDFFS) {
399                         maxsecsize =
400                             ((dpart.disklab->d_secsize > maxsecsize) ?
401                             dpart.disklab->d_secsize : maxsecsize);
402                         size = dpart.part->p_size - CCD_OFFSET;
403                 } else {
404 #ifdef DEBUG
405                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
406                                 printf("ccd%d: %s: incorrect partition type\n",
407                                     ccd->ccd_unit, ci->ci_path);
408 #endif
409                         while (ci >= cs->sc_cinfo) {
410                                 free(ci->ci_path, M_DEVBUF);
411                                 ci--;
412                         }
413                         free(cs->sc_cinfo, M_DEVBUF);
414                         return (EFTYPE);
415                 }
416
417                 /*
418                  * Calculate the size, truncating to an interleave
419                  * boundary if necessary.
420                  */
421
422                 if (cs->sc_ileave > 1)
423                         size -= size % cs->sc_ileave;
424
425                 if (size == 0) {
426 #ifdef DEBUG
427                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
428                                 printf("ccd%d: %s: size == 0\n",
429                                     ccd->ccd_unit, ci->ci_path);
430 #endif
431                         while (ci >= cs->sc_cinfo) {
432                                 free(ci->ci_path, M_DEVBUF);
433                                 ci--;
434                         }
435                         free(cs->sc_cinfo, M_DEVBUF);
436                         return (ENODEV);
437                 }
438
439                 if (minsize == 0 || size < minsize)
440                         minsize = size;
441                 ci->ci_size = size;
442                 cs->sc_size += size;
443         }
444
445         /*
446          * Don't allow the interleave to be smaller than
447          * the biggest component sector.
448          */
449         if ((cs->sc_ileave > 0) &&
450             (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
451 #ifdef DEBUG
452                 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
453                         printf("ccd%d: interleave must be at least %d\n",
454                             ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
455 #endif
456                 while (ci >= cs->sc_cinfo) {
457                         free(ci->ci_path, M_DEVBUF);
458                         ci--;
459                 }
460                 free(cs->sc_cinfo, M_DEVBUF);
461                 return (EINVAL);
462         }
463
464         /*
465          * If uniform interleave is desired set all sizes to that of
466          * the smallest component.
467          */
468         if (ccd->ccd_flags & CCDF_UNIFORM) {
469                 for (ci = cs->sc_cinfo;
470                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
471                         ci->ci_size = minsize;
472                 if (ccd->ccd_flags & CCDF_MIRROR) {
473                         /*
474                          * Check to see if an even number of components
475                          * have been specified.
476                          */
477                         if (cs->sc_nccdisks % 2) {
478                                 printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
479                                 while (ci > cs->sc_cinfo) {
480                                         ci--;
481                                         free(ci->ci_path, M_DEVBUF);
482                                 }
483                                 free(cs->sc_cinfo, M_DEVBUF);
484                                 return (EINVAL);
485                         }
486                         cs->sc_size = (cs->sc_nccdisks/2) * minsize;
487                 }
488                 else if (ccd->ccd_flags & CCDF_PARITY)
489                         cs->sc_size = (cs->sc_nccdisks-1) * minsize;
490                 else
491                         cs->sc_size = cs->sc_nccdisks * minsize;
492         }
493
494         /*
495          * Construct the interleave table.
496          */
497         ccdinterleave(cs, ccd->ccd_unit);
498
499         /*
500          * Create pseudo-geometry based on 1MB cylinders.  It's
501          * pretty close.
502          */
503         ccg->ccg_secsize = maxsecsize;
504         ccg->ccg_ntracks = 1;
505         ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
506         ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
507
508         /*
509          * Add an devstat entry for this device.
510          */
511         devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
512                           ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
513                           DEVSTAT_TYPE_ASC0 |DEVSTAT_TYPE_IF_OTHER,
514                           DEVSTAT_PRIORITY_CCD);
515
516         cs->sc_flags |= CCDF_INITED;
517         cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
518         cs->sc_unit = ccd->ccd_unit;
519         return (0);
520 }
521
522 static void
523 ccdinterleave(cs, unit)
524         register struct ccd_softc *cs;
525         int unit;
526 {
527         register struct ccdcinfo *ci, *smallci;
528         register struct ccdiinfo *ii;
529         register daddr_t bn, lbn;
530         register int ix;
531         u_long size;
532
533 #ifdef DEBUG
534         if (ccddebug & CCDB_INIT)
535                 printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
536 #endif
537         /*
538          * Allocate an interleave table.
539          * Chances are this is too big, but we don't care.
540          */
541         size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
542         cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
543         bzero((caddr_t)cs->sc_itable, size);
544
545         /*
546          * Trivial case: no interleave (actually interleave of disk size).
547          * Each table entry represents a single component in its entirety.
548          */
549         if (cs->sc_ileave == 0) {
550                 bn = 0;
551                 ii = cs->sc_itable;
552
553                 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
554                         /* Allocate space for ii_index. */
555                         ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
556                         ii->ii_ndisk = 1;
557                         ii->ii_startblk = bn;
558                         ii->ii_startoff = 0;
559                         ii->ii_index[0] = ix;
560                         bn += cs->sc_cinfo[ix].ci_size;
561                         ii++;
562                 }
563                 ii->ii_ndisk = 0;
564 #ifdef DEBUG
565                 if (ccddebug & CCDB_INIT)
566                         printiinfo(cs->sc_itable);
567 #endif
568                 return;
569         }
570
571         /*
572          * The following isn't fast or pretty; it doesn't have to be.
573          */
574         size = 0;
575         bn = lbn = 0;
576         for (ii = cs->sc_itable; ; ii++) {
577                 /* Allocate space for ii_index. */
578                 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
579                     M_DEVBUF, M_WAITOK);
580
581                 /*
582                  * Locate the smallest of the remaining components
583                  */
584                 smallci = NULL;
585                 for (ci = cs->sc_cinfo;
586                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
587                         if (ci->ci_size > size &&
588                             (smallci == NULL ||
589                              ci->ci_size < smallci->ci_size))
590                                 smallci = ci;
591
592                 /*
593                  * Nobody left, all done
594                  */
595                 if (smallci == NULL) {
596                         ii->ii_ndisk = 0;
597                         break;
598                 }
599
600                 /*
601                  * Record starting logical block and component offset
602                  */
603                 ii->ii_startblk = bn / cs->sc_ileave;
604                 ii->ii_startoff = lbn;
605
606                 /*
607                  * Determine how many disks take part in this interleave
608                  * and record their indices.
609                  */
610                 ix = 0;
611                 for (ci = cs->sc_cinfo;
612                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
613                         if (ci->ci_size >= smallci->ci_size)
614                                 ii->ii_index[ix++] = ci - cs->sc_cinfo;
615                 ii->ii_ndisk = ix;
616                 bn += ix * (smallci->ci_size - size);
617                 lbn = smallci->ci_size / cs->sc_ileave;
618                 size = smallci->ci_size;
619         }
620 #ifdef DEBUG
621         if (ccddebug & CCDB_INIT)
622                 printiinfo(cs->sc_itable);
623 #endif
624 }
625
626 /* ARGSUSED */
627 static int
628 ccdopen(dev, flags, fmt, p)
629         dev_t dev;
630         int flags, fmt;
631         struct proc *p;
632 {
633         int unit = ccdunit(dev);
634         struct ccd_softc *cs;
635         struct disklabel *lp;
636         int error = 0, part, pmask;
637
638 #ifdef DEBUG
639         if (ccddebug & CCDB_FOLLOW)
640                 printf("ccdopen(%x, %x)\n", dev, flags);
641 #endif
642         if (unit >= numccd)
643                 return (ENXIO);
644         cs = &ccd_softc[unit];
645
646         if ((error = ccdlock(cs)) != 0)
647                 return (error);
648
649         lp = &cs->sc_label;
650
651         part = ccdpart(dev);
652         pmask = (1 << part);
653
654         /*
655          * If we're initialized, check to see if there are any other
656          * open partitions.  If not, then it's safe to update
657          * the in-core disklabel.
658          */
659         if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
660                 ccdgetdisklabel(dev);
661
662         /* Check that the partition exists. */
663         if (part != RAW_PART && ((part >= lp->d_npartitions) ||
664             (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
665                 error = ENXIO;
666                 goto done;
667         }
668
669         /* Prevent our unit from being unconfigured while open. */
670         switch (fmt) {
671         case S_IFCHR:
672                 cs->sc_copenmask |= pmask;
673                 break;
674
675         case S_IFBLK:
676                 cs->sc_bopenmask |= pmask;
677                 break;
678         }
679         cs->sc_openmask =
680             cs->sc_copenmask | cs->sc_bopenmask;
681
682  done:
683         ccdunlock(cs);
684         return (0);
685 }
686
687 /* ARGSUSED */
688 static int
689 ccdclose(dev, flags, fmt, p)
690         dev_t dev;
691         int flags, fmt;
692         struct proc *p;
693 {
694         int unit = ccdunit(dev);
695         struct ccd_softc *cs;
696         int error = 0, part;
697
698 #ifdef DEBUG
699         if (ccddebug & CCDB_FOLLOW)
700                 printf("ccdclose(%x, %x)\n", dev, flags);
701 #endif
702
703         if (unit >= numccd)
704                 return (ENXIO);
705         cs = &ccd_softc[unit];
706
707         if ((error = ccdlock(cs)) != 0)
708                 return (error);
709
710         part = ccdpart(dev);
711
712         /* ...that much closer to allowing unconfiguration... */
713         switch (fmt) {
714         case S_IFCHR:
715                 cs->sc_copenmask &= ~(1 << part);
716                 break;
717
718         case S_IFBLK:
719                 cs->sc_bopenmask &= ~(1 << part);
720                 break;
721         }
722         cs->sc_openmask =
723             cs->sc_copenmask | cs->sc_bopenmask;
724
725         ccdunlock(cs);
726         return (0);
727 }
728
729 static void
730 ccdstrategy(bp)
731         register struct buf *bp;
732 {
733         register int unit = ccdunit(bp->b_dev);
734         register struct ccd_softc *cs = &ccd_softc[unit];
735         register int s;
736         int wlabel;
737         struct disklabel *lp;
738
739 #ifdef DEBUG
740         if (ccddebug & CCDB_FOLLOW)
741                 printf("ccdstrategy(%x): unit %d\n", bp, unit);
742 #endif
743         if ((cs->sc_flags & CCDF_INITED) == 0) {
744                 bp->b_error = ENXIO;
745                 bp->b_flags |= B_ERROR;
746                 goto done;
747         }
748
749         /* If it's a nil transfer, wake up the top half now. */
750         if (bp->b_bcount == 0)
751                 goto done;
752
753         lp = &cs->sc_label;
754
755         /*
756          * Do bounds checking and adjust transfer.  If there's an
757          * error, the bounds check will flag that for us.
758          */
759         wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
760         if (ccdpart(bp->b_dev) != RAW_PART)
761                 if (bounds_check_with_label(bp, lp, wlabel) <= 0)
762                         goto done;
763
764         bp->b_resid = bp->b_bcount;
765
766         /*
767          * "Start" the unit.
768          */
769         s = splbio();
770         ccdstart(cs, bp);
771         splx(s);
772         return;
773 done:
774         biodone(bp);
775 }
776
777 static void
778 ccdstart(cs, bp)
779         register struct ccd_softc *cs;
780         register struct buf *bp;
781 {
782         register long bcount, rcount;
783         struct ccdbuf *cbp[4];
784         /* XXX! : 2 reads and 2 writes for RAID 4/5 */
785         caddr_t addr;
786         daddr_t bn;
787         struct partition *pp;
788
789 #ifdef DEBUG
790         if (ccddebug & CCDB_FOLLOW)
791                 printf("ccdstart(%x, %x)\n", cs, bp);
792 #endif
793
794         /* Record the transaction start  */
795         devstat_start_transaction(&cs->device_stats);
796
797         /*
798          * Translate the partition-relative block number to an absolute.
799          */
800         bn = bp->b_blkno;
801         if (ccdpart(bp->b_dev) != RAW_PART) {
802                 pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)];
803                 bn += pp->p_offset;
804         }
805
806         /*
807          * Allocate component buffers and fire off the requests
808          */
809         addr = bp->b_data;
810         for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
811                 ccdbuffer(cbp, cs, bp, bn, addr, bcount);
812                 rcount = cbp[0]->cb_buf.b_bcount;
813                 if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
814                         cbp[0]->cb_buf.b_vp->v_numoutput++;
815                 VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf);
816                 if (cs->sc_cflags & CCDF_MIRROR &&
817                     (cbp[0]->cb_buf.b_flags & B_READ) == 0) {
818                         /* mirror, start another write */
819                         cbp[1]->cb_buf.b_vp->v_numoutput++;
820                         VOP_STRATEGY(cbp[1]->cb_buf.b_vp, &cbp[1]->cb_buf);
821                 }
822                 bn += btodb(rcount);
823                 addr += rcount;
824         }
825 }
826
827 /*
828  * Build a component buffer header.
829  */
830 static void
831 ccdbuffer(cb, cs, bp, bn, addr, bcount)
832         register struct ccdbuf **cb;
833         register struct ccd_softc *cs;
834         struct buf *bp;
835         daddr_t bn;
836         caddr_t addr;
837         long bcount;
838 {
839         register struct ccdcinfo *ci, *ci2 = NULL;      /* XXX */
840         register struct ccdbuf *cbp;
841         register daddr_t cbn, cboff;
842       register off_t cbc;
843
844 #ifdef DEBUG
845         if (ccddebug & CCDB_IO)
846                 printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
847                        cs, bp, bn, addr, bcount);
848 #endif
849         /*
850          * Determine which component bn falls in.
851          */
852         cbn = bn;
853         cboff = 0;
854
855         /*
856          * Serially concatenated
857          */
858         if (cs->sc_ileave == 0) {
859                 register daddr_t sblk;
860
861                 sblk = 0;
862                 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
863                         sblk += ci->ci_size;
864                 cbn -= sblk;
865         }
866         /*
867          * Interleaved
868          */
869         else {
870                 register struct ccdiinfo *ii;
871                 int ccdisk, off;
872
873                 cboff = cbn % cs->sc_ileave;
874                 cbn /= cs->sc_ileave;
875                 for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
876                         if (ii->ii_startblk > cbn)
877                                 break;
878                 ii--;
879                 off = cbn - ii->ii_startblk;
880                 if (ii->ii_ndisk == 1) {
881                         ccdisk = ii->ii_index[0];
882                         cbn = ii->ii_startoff + off;
883                 } else {
884                         if (cs->sc_cflags & CCDF_MIRROR) {
885                                 ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)];
886                                 cbn = ii->ii_startoff + off / (ii->ii_ndisk/2);
887                                 /* mirrored data */
888                                 ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2];
889                         }
890                         else if (cs->sc_cflags & CCDF_PARITY) {
891                                 ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)];
892                                 cbn = ii->ii_startoff + off / (ii->ii_ndisk-1);
893                                 if (cbn % ii->ii_ndisk <= ccdisk)
894                                         ccdisk++;
895                         }
896                         else {
897                                 ccdisk = ii->ii_index[off % ii->ii_ndisk];
898                                 cbn = ii->ii_startoff + off / ii->ii_ndisk;
899                         }
900                 }
901                 cbn *= cs->sc_ileave;
902                 ci = &cs->sc_cinfo[ccdisk];
903         }
904
905         /*
906          * Fill in the component buf structure.
907          */
908         cbp = getccdbuf();
909         bzero(cbp, sizeof (struct ccdbuf));
910         cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
911         cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone;
912         cbp->cb_buf.b_dev = ci->ci_dev;         /* XXX */
913         cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET;
914         cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET);
915         cbp->cb_buf.b_data = addr;
916         cbp->cb_buf.b_vp = ci->ci_vp;
917         LIST_INIT(&cbp->cb_buf.b_dep);
918         cbp->cb_buf.b_resid = 0;
919         if (cs->sc_ileave == 0)
920               cbc = dbtob((off_t)(ci->ci_size - cbn));
921         else
922               cbc = dbtob((off_t)(cs->sc_ileave - cboff));
923       cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
924
925         cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
926
927         /*
928          * context for ccdiodone
929          */
930         cbp->cb_obp = bp;
931         cbp->cb_unit = cs - ccd_softc;
932         cbp->cb_comp = ci - cs->sc_cinfo;
933
934 #ifdef DEBUG
935         if (ccddebug & CCDB_IO)
936                 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
937                        ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
938                        cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
939 #endif
940         cb[0] = cbp;
941         if (cs->sc_cflags & CCDF_MIRROR &&
942             (cbp->cb_buf.b_flags & B_READ) == 0) {
943                 /* mirror, start one more write */
944                 cbp = getccdbuf();
945                 bzero(cbp, sizeof (struct ccdbuf));
946                 *cbp = *cb[0];
947                 cbp->cb_buf.b_dev = ci2->ci_dev;
948                 cbp->cb_buf.b_vp = ci2->ci_vp;
949                 LIST_INIT(&cbp->cb_buf.b_dep);
950                 cbp->cb_comp = ci2 - cs->sc_cinfo;
951                 cb[1] = cbp;
952                 /* link together the ccdbuf's and clear "mirror done" flag */
953                 cb[0]->cb_mirror = cb[1];
954                 cb[1]->cb_mirror = cb[0];
955                 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
956                 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
957         }
958 }
959
960 static void
961 ccdintr(cs, bp)
962         register struct ccd_softc *cs;
963         register struct buf *bp;
964 {
965 #ifdef DEBUG
966         if (ccddebug & CCDB_FOLLOW)
967                 printf("ccdintr(%x, %x)\n", cs, bp);
968 #endif
969         /*
970          * Request is done for better or worse, wakeup the top half.
971          */
972         /* Record device statistics */
973         devstat_end_transaction(&cs->device_stats,
974                                 bp->b_bcount - bp->b_resid,
975                                 (bp->b_flags & B_ORDERED) ?
976                                 DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE,
977                                 (bp->b_flags & B_READ) ? DEVSTAT_READ :
978                                 DEVSTAT_WRITE);
979
980         if (bp->b_flags & B_ERROR)
981                 bp->b_resid = bp->b_bcount;
982         biodone(bp);
983 }
984
985 /*
986  * Called at interrupt time.
987  * Mark the component as done and if all components are done,
988  * take a ccd interrupt.
989  */
990 static void
991 ccdiodone(cbp)
992         struct ccdbuf *cbp;
993 {
994         register struct buf *bp = cbp->cb_obp;
995         register int unit = cbp->cb_unit;
996         int count, s;
997
998         s = splbio();
999 #ifdef DEBUG
1000         if (ccddebug & CCDB_FOLLOW)
1001                 printf("ccdiodone(%x)\n", cbp);
1002         if (ccddebug & CCDB_IO) {
1003                 printf("ccdiodone: bp %x bcount %d resid %d\n",
1004                        bp, bp->b_bcount, bp->b_resid);
1005                 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1006                        cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1007                        cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1008                        cbp->cb_buf.b_bcount);
1009         }
1010 #endif
1011
1012         if (cbp->cb_buf.b_flags & B_ERROR) {
1013                 bp->b_flags |= B_ERROR;
1014                 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1015 #ifdef DEBUG
1016                 printf("ccd%d: error %d on component %d\n",
1017                        unit, bp->b_error, cbp->cb_comp);
1018 #endif
1019         }
1020
1021         if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1022             (cbp->cb_buf.b_flags & B_READ) == 0)
1023                 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1024                         /* I'm done before my counterpart, so just set
1025                            partner's flag and return */
1026                         cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1027                         putccdbuf(cbp);
1028                         splx(s);
1029                         return;
1030                 }
1031                 
1032         count = cbp->cb_buf.b_bcount;
1033         putccdbuf(cbp);
1034
1035         /*
1036          * If all done, "interrupt".
1037          */
1038         bp->b_resid -= count;
1039         if (bp->b_resid < 0)
1040                 panic("ccdiodone: count");
1041         if (bp->b_resid == 0)
1042                 ccdintr(&ccd_softc[unit], bp);
1043         splx(s);
1044 }
1045
1046 static int
1047 ccdioctl(dev, cmd, data, flag, p)
1048         dev_t dev;
1049         u_long cmd;
1050         caddr_t data;
1051         int flag;
1052         struct proc *p;
1053 {
1054         int unit = ccdunit(dev);
1055         int i, j, lookedup = 0, error = 0;
1056         int part, pmask, s;
1057         struct ccd_softc *cs;
1058         struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1059         struct ccddevice ccd;
1060         char **cpp;
1061         struct vnode **vpp;
1062
1063         if (unit >= numccd)
1064                 return (ENXIO);
1065         cs = &ccd_softc[unit];
1066
1067         bzero(&ccd, sizeof(ccd));
1068
1069         switch (cmd) {
1070         case CCDIOCSET:
1071                 if (cs->sc_flags & CCDF_INITED)
1072                         return (EBUSY);
1073
1074                 if ((flag & FWRITE) == 0)
1075                         return (EBADF);
1076
1077                 if ((error = ccdlock(cs)) != 0)
1078                         return (error);
1079
1080                 /* Fill in some important bits. */
1081                 ccd.ccd_unit = unit;
1082                 ccd.ccd_interleave = ccio->ccio_ileave;
1083                 if (ccd.ccd_interleave == 0 &&
1084                     ((ccio->ccio_flags & CCDF_MIRROR) ||
1085                      (ccio->ccio_flags & CCDF_PARITY))) {
1086                         printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1087                         ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1088                 }
1089                 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1090                     (ccio->ccio_flags & CCDF_PARITY)) {
1091                         printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1092                         ccio->ccio_flags &= ~CCDF_PARITY;
1093                 }
1094                 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1095                     !(ccio->ccio_flags & CCDF_UNIFORM)) {
1096                         printf("ccd%d: mirror/parity forces uniform flag\n",
1097                                unit);
1098                         ccio->ccio_flags |= CCDF_UNIFORM;
1099                 }
1100                 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1101
1102                 /*
1103                  * Allocate space for and copy in the array of
1104                  * componet pathnames and device numbers.
1105                  */
1106                 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1107                     M_DEVBUF, M_WAITOK);
1108                 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1109                     M_DEVBUF, M_WAITOK);
1110
1111                 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1112                     ccio->ccio_ndisks * sizeof(char **));
1113                 if (error) {
1114                         free(vpp, M_DEVBUF);
1115                         free(cpp, M_DEVBUF);
1116                         ccdunlock(cs);
1117                         return (error);
1118                 }
1119
1120 #ifdef DEBUG
1121                 if (ccddebug & CCDB_INIT)
1122                         for (i = 0; i < ccio->ccio_ndisks; ++i)
1123                                 printf("ccdioctl: component %d: 0x%x\n",
1124                                     i, cpp[i]);
1125 #endif
1126
1127                 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1128 #ifdef DEBUG
1129                         if (ccddebug & CCDB_INIT)
1130                                 printf("ccdioctl: lookedup = %d\n", lookedup);
1131 #endif
1132                         if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1133                                 for (j = 0; j < lookedup; ++j)
1134                                         (void)vn_close(vpp[j], FREAD|FWRITE,
1135                                             p->p_ucred, p);
1136                                 free(vpp, M_DEVBUF);
1137                                 free(cpp, M_DEVBUF);
1138                                 ccdunlock(cs);
1139                                 return (error);
1140                         }
1141                         ++lookedup;
1142                 }
1143                 ccd.ccd_cpp = cpp;
1144                 ccd.ccd_vpp = vpp;
1145                 ccd.ccd_ndev = ccio->ccio_ndisks;
1146
1147                 /*
1148                  * Initialize the ccd.  Fills in the softc for us.
1149                  */
1150                 if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1151                         for (j = 0; j < lookedup; ++j)
1152                                 (void)vn_close(vpp[j], FREAD|FWRITE,
1153                                     p->p_ucred, p);
1154                         bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1155                         free(vpp, M_DEVBUF);
1156                         free(cpp, M_DEVBUF);
1157                         ccdunlock(cs);
1158                         return (error);
1159                 }
1160
1161                 /*
1162                  * The ccd has been successfully initialized, so
1163                  * we can place it into the array and read the disklabel.
1164                  */
1165                 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1166                 ccio->ccio_unit = unit;
1167                 ccio->ccio_size = cs->sc_size;
1168                 ccdgetdisklabel(dev);
1169
1170                 ccdunlock(cs);
1171
1172                 break;
1173
1174         case CCDIOCCLR:
1175                 if ((cs->sc_flags & CCDF_INITED) == 0)
1176                         return (ENXIO);
1177
1178                 if ((flag & FWRITE) == 0)
1179                         return (EBADF);
1180
1181                 if ((error = ccdlock(cs)) != 0)
1182                         return (error);
1183
1184                 /*
1185                  * Don't unconfigure if any other partitions are open
1186                  * or if both the character and block flavors of this
1187                  * partition are open.
1188                  */
1189                 part = ccdpart(dev);
1190                 pmask = (1 << part);
1191                 if ((cs->sc_openmask & ~pmask) ||
1192                     ((cs->sc_bopenmask & pmask) &&
1193                     (cs->sc_copenmask & pmask))) {
1194                         ccdunlock(cs);
1195                         return (EBUSY);
1196                 }
1197
1198                 /*
1199                  * Free ccd_softc information and clear entry.
1200                  */
1201
1202                 /* Close the components and free their pathnames. */
1203                 for (i = 0; i < cs->sc_nccdisks; ++i) {
1204                         /*
1205                          * XXX: this close could potentially fail and
1206                          * cause Bad Things.  Maybe we need to force
1207                          * the close to happen?
1208                          */
1209 #ifdef DEBUG
1210                         if (ccddebug & CCDB_VNODE)
1211                                 vprint("CCDIOCCLR: vnode info",
1212                                     cs->sc_cinfo[i].ci_vp);
1213 #endif
1214                         (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1215                             p->p_ucred, p);
1216                         free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1217                 }
1218
1219                 /* Free interleave index. */
1220                 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1221                         free(cs->sc_itable[i].ii_index, M_DEVBUF);
1222
1223                 /* Free component info and interleave table. */
1224                 free(cs->sc_cinfo, M_DEVBUF);
1225                 free(cs->sc_itable, M_DEVBUF);
1226                 cs->sc_flags &= ~CCDF_INITED;
1227
1228                 /*
1229                  * Free ccddevice information and clear entry.
1230                  */
1231                 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1232                 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1233                 ccd.ccd_dk = -1;
1234                 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1235
1236                 /*
1237                  * And remove the devstat entry.
1238                  */
1239                 devstat_remove_entry(&cs->device_stats);
1240
1241                 /* This must be atomic. */
1242                 s = splhigh();
1243                 ccdunlock(cs);
1244                 bzero(cs, sizeof(struct ccd_softc));
1245                 splx(s);
1246
1247                 break;
1248
1249         case DIOCGDINFO:
1250                 if ((cs->sc_flags & CCDF_INITED) == 0)
1251                         return (ENXIO);
1252
1253                 *(struct disklabel *)data = cs->sc_label;
1254                 break;
1255
1256         case DIOCGPART:
1257                 if ((cs->sc_flags & CCDF_INITED) == 0)
1258                         return (ENXIO);
1259
1260                 ((struct partinfo *)data)->disklab = &cs->sc_label;
1261                 ((struct partinfo *)data)->part =
1262                     &cs->sc_label.d_partitions[ccdpart(dev)];
1263                 break;
1264
1265         case DIOCWDINFO:
1266         case DIOCSDINFO:
1267                 if ((cs->sc_flags & CCDF_INITED) == 0)
1268                         return (ENXIO);
1269
1270                 if ((flag & FWRITE) == 0)
1271                         return (EBADF);
1272
1273                 if ((error = ccdlock(cs)) != 0)
1274                         return (error);
1275
1276                 cs->sc_flags |= CCDF_LABELLING;
1277
1278                 error = setdisklabel(&cs->sc_label,
1279                     (struct disklabel *)data, 0);
1280                 if (error == 0) {
1281                         if (cmd == DIOCWDINFO)
1282                                 error = writedisklabel(CCDLABELDEV(dev),
1283                                     ccdstrategy, &cs->sc_label);
1284                 }
1285
1286                 cs->sc_flags &= ~CCDF_LABELLING;
1287
1288                 ccdunlock(cs);
1289
1290                 if (error)
1291                         return (error);
1292                 break;
1293
1294         case DIOCWLABEL:
1295                 if ((cs->sc_flags & CCDF_INITED) == 0)
1296                         return (ENXIO);
1297
1298                 if ((flag & FWRITE) == 0)
1299                         return (EBADF);
1300                 if (*(int *)data != 0)
1301                         cs->sc_flags |= CCDF_WLABEL;
1302                 else
1303                         cs->sc_flags &= ~CCDF_WLABEL;
1304                 break;
1305
1306         default:
1307                 return (ENOTTY);
1308         }
1309
1310         return (0);
1311 }
1312
1313 static int
1314 ccdsize(dev)
1315         dev_t dev;
1316 {
1317         struct ccd_softc *cs;
1318         int part, size;
1319
1320         if (ccdopen(dev, 0, S_IFBLK, curproc))
1321                 return (-1);
1322
1323         cs = &ccd_softc[ccdunit(dev)];
1324         part = ccdpart(dev);
1325
1326         if ((cs->sc_flags & CCDF_INITED) == 0)
1327                 return (-1);
1328
1329         if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1330                 size = -1;
1331         else
1332                 size = cs->sc_label.d_partitions[part].p_size;
1333
1334         if (ccdclose(dev, 0, S_IFBLK, curproc))
1335                 return (-1);
1336
1337         return (size);
1338 }
1339
1340 static int
1341 ccddump(dev)
1342         dev_t dev;
1343 {
1344
1345         /* Not implemented. */
1346         return ENXIO;
1347 }
1348
1349 /*
1350  * Lookup the provided name in the filesystem.  If the file exists,
1351  * is a valid block device, and isn't being used by anyone else,
1352  * set *vpp to the file's vnode.
1353  */
1354 static int
1355 ccdlookup(path, p, vpp)
1356         char *path;
1357         struct proc *p;
1358         struct vnode **vpp;     /* result */
1359 {
1360         struct nameidata nd;
1361         struct vnode *vp;
1362         struct vattr va;
1363         int error;
1364
1365         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1366         if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1367 #ifdef DEBUG
1368                 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1369                         printf("ccdlookup: vn_open error = %d\n", error);
1370 #endif
1371                 return (error);
1372         }
1373         vp = nd.ni_vp;
1374
1375         if (vp->v_usecount > 1) {
1376                 VOP_UNLOCK(vp, 0, p);
1377                 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1378                 return (EBUSY);
1379         }
1380
1381         if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1382 #ifdef DEBUG
1383                 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1384                         printf("ccdlookup: getattr error = %d\n", error);
1385 #endif
1386                 VOP_UNLOCK(vp, 0, p);
1387                 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1388                 return (error);
1389         }
1390
1391         /* XXX: eventually we should handle VREG, too. */
1392         if (va.va_type != VBLK) {
1393                 VOP_UNLOCK(vp, 0, p);
1394                 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1395                 return (ENOTBLK);
1396         }
1397
1398 #ifdef DEBUG
1399         if (ccddebug & CCDB_VNODE)
1400                 vprint("ccdlookup: vnode info", vp);
1401 #endif
1402
1403         VOP_UNLOCK(vp, 0, p);
1404         *vpp = vp;
1405         return (0);
1406 }
1407
1408 /*
1409  * Read the disklabel from the ccd.  If one is not present, fake one
1410  * up.
1411  */
1412 static void
1413 ccdgetdisklabel(dev)
1414         dev_t dev;
1415 {
1416         int unit = ccdunit(dev);
1417         struct ccd_softc *cs = &ccd_softc[unit];
1418         char *errstring;
1419         struct disklabel *lp = &cs->sc_label;
1420         struct ccdgeom *ccg = &cs->sc_geom;
1421
1422         bzero(lp, sizeof(*lp));
1423
1424         lp->d_secperunit = cs->sc_size;
1425         lp->d_secsize = ccg->ccg_secsize;
1426         lp->d_nsectors = ccg->ccg_nsectors;
1427         lp->d_ntracks = ccg->ccg_ntracks;
1428         lp->d_ncylinders = ccg->ccg_ncylinders;
1429         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1430
1431         strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1432         lp->d_type = DTYPE_CCD;
1433         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1434         lp->d_rpm = 3600;
1435         lp->d_interleave = 1;
1436         lp->d_flags = 0;
1437
1438         lp->d_partitions[RAW_PART].p_offset = 0;
1439         lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1440         lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1441         lp->d_npartitions = RAW_PART + 1;
1442
1443         lp->d_bbsize = BBSIZE;                          /* XXX */
1444         lp->d_sbsize = SBSIZE;                          /* XXX */
1445
1446         lp->d_magic = DISKMAGIC;
1447         lp->d_magic2 = DISKMAGIC;
1448         lp->d_checksum = dkcksum(&cs->sc_label);
1449
1450         /*
1451          * Call the generic disklabel extraction routine.
1452          */
1453         if ((errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1454             &cs->sc_label)) != NULL)
1455                 ccdmakedisklabel(cs);
1456
1457 #ifdef DEBUG
1458         /* It's actually extremely common to have unlabeled ccds. */
1459         if (ccddebug & CCDB_LABEL)
1460                 if (errstring != NULL)
1461                         printf("ccd%d: %s\n", unit, errstring);
1462 #endif
1463 }
1464
1465 /*
1466  * Take care of things one might want to take care of in the event
1467  * that a disklabel isn't present.
1468  */
1469 static void
1470 ccdmakedisklabel(cs)
1471         struct ccd_softc *cs;
1472 {
1473         struct disklabel *lp = &cs->sc_label;
1474
1475         /*
1476          * For historical reasons, if there's no disklabel present
1477          * the raw partition must be marked FS_BSDFFS.
1478          */
1479         lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1480
1481         strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1482 }
1483
1484 /*
1485  * Wait interruptibly for an exclusive lock.
1486  *
1487  * XXX
1488  * Several drivers do this; it should be abstracted and made MP-safe.
1489  */
1490 static int
1491 ccdlock(cs)
1492         struct ccd_softc *cs;
1493 {
1494         int error;
1495
1496         while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1497                 cs->sc_flags |= CCDF_WANTED;
1498                 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1499                         return (error);
1500         }
1501         cs->sc_flags |= CCDF_LOCKED;
1502         return (0);
1503 }
1504
1505 /*
1506  * Unlock and wake up any waiters.
1507  */
1508 static void
1509 ccdunlock(cs)
1510         struct ccd_softc *cs;
1511 {
1512
1513         cs->sc_flags &= ~CCDF_LOCKED;
1514         if ((cs->sc_flags & CCDF_WANTED) != 0) {
1515                 cs->sc_flags &= ~CCDF_WANTED;
1516                 wakeup(cs);
1517         }
1518 }
1519
1520 #ifdef DEBUG
1521 static void
1522 printiinfo(ii)
1523         struct ccdiinfo *ii;
1524 {
1525         register int ix, i;
1526
1527         for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1528                 printf(" itab[%d]: #dk %d sblk %d soff %d",
1529                        ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1530                 for (i = 0; i < ii->ii_ndisk; i++)
1531                         printf(" %d", ii->ii_index[i]);
1532                 printf("\n");
1533         }
1534 }
1535 #endif
1536
1537 #endif /* NCCD > 0 */
1538 \f
1539 /* Local Variables: */
1540 /* c-argdecl-indent: 8 */
1541 /* c-continued-statement-offset: 8 */
1542 /* c-indent-level: 8 */
1543 /* End: */