]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/geom_ccd.c
Initialize and hold locks for ccd generated bufs..
[FreeBSD/FreeBSD.git] / sys / geom / geom_ccd.c
1 /* $Id: ccd.c,v 1.48 1999/05/30 16:51:18 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         BUF_LOCKINIT(&cbp->cb_buf);
919         BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
920         cbp->cb_buf.b_resid = 0;
921         if (cs->sc_ileave == 0)
922               cbc = dbtob((off_t)(ci->ci_size - cbn));
923         else
924               cbc = dbtob((off_t)(cs->sc_ileave - cboff));
925         cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
926         cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
927
928         /*
929          * context for ccdiodone
930          */
931         cbp->cb_obp = bp;
932         cbp->cb_unit = cs - ccd_softc;
933         cbp->cb_comp = ci - cs->sc_cinfo;
934
935 #ifdef DEBUG
936         if (ccddebug & CCDB_IO)
937                 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
938                        ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
939                        cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
940 #endif
941         cb[0] = cbp;
942         if (cs->sc_cflags & CCDF_MIRROR &&
943             (cbp->cb_buf.b_flags & B_READ) == 0) {
944                 /* mirror, start one more write */
945                 cbp = getccdbuf();
946                 bzero(cbp, sizeof (struct ccdbuf));
947                 *cbp = *cb[0];
948                 cbp->cb_buf.b_dev = ci2->ci_dev;
949                 cbp->cb_buf.b_vp = ci2->ci_vp;
950                 LIST_INIT(&cbp->cb_buf.b_dep);
951                 BUF_LOCKINIT(&cbp->cb_buf);
952                 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
953                 cbp->cb_comp = ci2 - cs->sc_cinfo;
954                 cb[1] = cbp;
955                 /* link together the ccdbuf's and clear "mirror done" flag */
956                 cb[0]->cb_mirror = cb[1];
957                 cb[1]->cb_mirror = cb[0];
958                 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
959                 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
960         }
961 }
962
963 static void
964 ccdintr(cs, bp)
965         register struct ccd_softc *cs;
966         register struct buf *bp;
967 {
968 #ifdef DEBUG
969         if (ccddebug & CCDB_FOLLOW)
970                 printf("ccdintr(%x, %x)\n", cs, bp);
971 #endif
972         /*
973          * Request is done for better or worse, wakeup the top half.
974          */
975         /* Record device statistics */
976         devstat_end_transaction(&cs->device_stats,
977                                 bp->b_bcount - bp->b_resid,
978                                 (bp->b_flags & B_ORDERED) ?
979                                 DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE,
980                                 (bp->b_flags & B_READ) ? DEVSTAT_READ :
981                                 DEVSTAT_WRITE);
982
983         if (bp->b_flags & B_ERROR)
984                 bp->b_resid = bp->b_bcount;
985         biodone(bp);
986 }
987
988 /*
989  * Called at interrupt time.
990  * Mark the component as done and if all components are done,
991  * take a ccd interrupt.
992  */
993 static void
994 ccdiodone(cbp)
995         struct ccdbuf *cbp;
996 {
997         register struct buf *bp = cbp->cb_obp;
998         register int unit = cbp->cb_unit;
999         int count, s;
1000
1001         s = splbio();
1002 #ifdef DEBUG
1003         if (ccddebug & CCDB_FOLLOW)
1004                 printf("ccdiodone(%x)\n", cbp);
1005         if (ccddebug & CCDB_IO) {
1006                 printf("ccdiodone: bp %x bcount %d resid %d\n",
1007                        bp, bp->b_bcount, bp->b_resid);
1008                 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1009                        cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1010                        cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1011                        cbp->cb_buf.b_bcount);
1012         }
1013 #endif
1014
1015         if (cbp->cb_buf.b_flags & B_ERROR) {
1016                 bp->b_flags |= B_ERROR;
1017                 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1018 #ifdef DEBUG
1019                 printf("ccd%d: error %d on component %d\n",
1020                        unit, bp->b_error, cbp->cb_comp);
1021 #endif
1022         }
1023
1024         if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1025             (cbp->cb_buf.b_flags & B_READ) == 0)
1026                 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1027                         /* I'm done before my counterpart, so just set
1028                            partner's flag and return */
1029                         cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1030                         putccdbuf(cbp);
1031                         splx(s);
1032                         return;
1033                 }
1034                 
1035         count = cbp->cb_buf.b_bcount;
1036         putccdbuf(cbp);
1037
1038         /*
1039          * If all done, "interrupt".
1040          */
1041         bp->b_resid -= count;
1042         if (bp->b_resid < 0)
1043                 panic("ccdiodone: count");
1044         if (bp->b_resid == 0)
1045                 ccdintr(&ccd_softc[unit], bp);
1046         splx(s);
1047 }
1048
1049 static int
1050 ccdioctl(dev, cmd, data, flag, p)
1051         dev_t dev;
1052         u_long cmd;
1053         caddr_t data;
1054         int flag;
1055         struct proc *p;
1056 {
1057         int unit = ccdunit(dev);
1058         int i, j, lookedup = 0, error = 0;
1059         int part, pmask, s;
1060         struct ccd_softc *cs;
1061         struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1062         struct ccddevice ccd;
1063         char **cpp;
1064         struct vnode **vpp;
1065
1066         if (unit >= numccd)
1067                 return (ENXIO);
1068         cs = &ccd_softc[unit];
1069
1070         bzero(&ccd, sizeof(ccd));
1071
1072         switch (cmd) {
1073         case CCDIOCSET:
1074                 if (cs->sc_flags & CCDF_INITED)
1075                         return (EBUSY);
1076
1077                 if ((flag & FWRITE) == 0)
1078                         return (EBADF);
1079
1080                 if ((error = ccdlock(cs)) != 0)
1081                         return (error);
1082
1083                 /* Fill in some important bits. */
1084                 ccd.ccd_unit = unit;
1085                 ccd.ccd_interleave = ccio->ccio_ileave;
1086                 if (ccd.ccd_interleave == 0 &&
1087                     ((ccio->ccio_flags & CCDF_MIRROR) ||
1088                      (ccio->ccio_flags & CCDF_PARITY))) {
1089                         printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1090                         ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1091                 }
1092                 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1093                     (ccio->ccio_flags & CCDF_PARITY)) {
1094                         printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1095                         ccio->ccio_flags &= ~CCDF_PARITY;
1096                 }
1097                 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1098                     !(ccio->ccio_flags & CCDF_UNIFORM)) {
1099                         printf("ccd%d: mirror/parity forces uniform flag\n",
1100                                unit);
1101                         ccio->ccio_flags |= CCDF_UNIFORM;
1102                 }
1103                 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1104
1105                 /*
1106                  * Allocate space for and copy in the array of
1107                  * componet pathnames and device numbers.
1108                  */
1109                 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1110                     M_DEVBUF, M_WAITOK);
1111                 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1112                     M_DEVBUF, M_WAITOK);
1113
1114                 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1115                     ccio->ccio_ndisks * sizeof(char **));
1116                 if (error) {
1117                         free(vpp, M_DEVBUF);
1118                         free(cpp, M_DEVBUF);
1119                         ccdunlock(cs);
1120                         return (error);
1121                 }
1122
1123 #ifdef DEBUG
1124                 if (ccddebug & CCDB_INIT)
1125                         for (i = 0; i < ccio->ccio_ndisks; ++i)
1126                                 printf("ccdioctl: component %d: 0x%x\n",
1127                                     i, cpp[i]);
1128 #endif
1129
1130                 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1131 #ifdef DEBUG
1132                         if (ccddebug & CCDB_INIT)
1133                                 printf("ccdioctl: lookedup = %d\n", lookedup);
1134 #endif
1135                         if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1136                                 for (j = 0; j < lookedup; ++j)
1137                                         (void)vn_close(vpp[j], FREAD|FWRITE,
1138                                             p->p_ucred, p);
1139                                 free(vpp, M_DEVBUF);
1140                                 free(cpp, M_DEVBUF);
1141                                 ccdunlock(cs);
1142                                 return (error);
1143                         }
1144                         ++lookedup;
1145                 }
1146                 ccd.ccd_cpp = cpp;
1147                 ccd.ccd_vpp = vpp;
1148                 ccd.ccd_ndev = ccio->ccio_ndisks;
1149
1150                 /*
1151                  * Initialize the ccd.  Fills in the softc for us.
1152                  */
1153                 if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1154                         for (j = 0; j < lookedup; ++j)
1155                                 (void)vn_close(vpp[j], FREAD|FWRITE,
1156                                     p->p_ucred, p);
1157                         bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1158                         free(vpp, M_DEVBUF);
1159                         free(cpp, M_DEVBUF);
1160                         ccdunlock(cs);
1161                         return (error);
1162                 }
1163
1164                 /*
1165                  * The ccd has been successfully initialized, so
1166                  * we can place it into the array and read the disklabel.
1167                  */
1168                 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1169                 ccio->ccio_unit = unit;
1170                 ccio->ccio_size = cs->sc_size;
1171                 ccdgetdisklabel(dev);
1172
1173                 ccdunlock(cs);
1174
1175                 break;
1176
1177         case CCDIOCCLR:
1178                 if ((cs->sc_flags & CCDF_INITED) == 0)
1179                         return (ENXIO);
1180
1181                 if ((flag & FWRITE) == 0)
1182                         return (EBADF);
1183
1184                 if ((error = ccdlock(cs)) != 0)
1185                         return (error);
1186
1187                 /*
1188                  * Don't unconfigure if any other partitions are open
1189                  * or if both the character and block flavors of this
1190                  * partition are open.
1191                  */
1192                 part = ccdpart(dev);
1193                 pmask = (1 << part);
1194                 if ((cs->sc_openmask & ~pmask) ||
1195                     ((cs->sc_bopenmask & pmask) &&
1196                     (cs->sc_copenmask & pmask))) {
1197                         ccdunlock(cs);
1198                         return (EBUSY);
1199                 }
1200
1201                 /*
1202                  * Free ccd_softc information and clear entry.
1203                  */
1204
1205                 /* Close the components and free their pathnames. */
1206                 for (i = 0; i < cs->sc_nccdisks; ++i) {
1207                         /*
1208                          * XXX: this close could potentially fail and
1209                          * cause Bad Things.  Maybe we need to force
1210                          * the close to happen?
1211                          */
1212 #ifdef DEBUG
1213                         if (ccddebug & CCDB_VNODE)
1214                                 vprint("CCDIOCCLR: vnode info",
1215                                     cs->sc_cinfo[i].ci_vp);
1216 #endif
1217                         (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1218                             p->p_ucred, p);
1219                         free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1220                 }
1221
1222                 /* Free interleave index. */
1223                 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1224                         free(cs->sc_itable[i].ii_index, M_DEVBUF);
1225
1226                 /* Free component info and interleave table. */
1227                 free(cs->sc_cinfo, M_DEVBUF);
1228                 free(cs->sc_itable, M_DEVBUF);
1229                 cs->sc_flags &= ~CCDF_INITED;
1230
1231                 /*
1232                  * Free ccddevice information and clear entry.
1233                  */
1234                 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1235                 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1236                 ccd.ccd_dk = -1;
1237                 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1238
1239                 /*
1240                  * And remove the devstat entry.
1241                  */
1242                 devstat_remove_entry(&cs->device_stats);
1243
1244                 /* This must be atomic. */
1245                 s = splhigh();
1246                 ccdunlock(cs);
1247                 bzero(cs, sizeof(struct ccd_softc));
1248                 splx(s);
1249
1250                 break;
1251
1252         case DIOCGDINFO:
1253                 if ((cs->sc_flags & CCDF_INITED) == 0)
1254                         return (ENXIO);
1255
1256                 *(struct disklabel *)data = cs->sc_label;
1257                 break;
1258
1259         case DIOCGPART:
1260                 if ((cs->sc_flags & CCDF_INITED) == 0)
1261                         return (ENXIO);
1262
1263                 ((struct partinfo *)data)->disklab = &cs->sc_label;
1264                 ((struct partinfo *)data)->part =
1265                     &cs->sc_label.d_partitions[ccdpart(dev)];
1266                 break;
1267
1268         case DIOCWDINFO:
1269         case DIOCSDINFO:
1270                 if ((cs->sc_flags & CCDF_INITED) == 0)
1271                         return (ENXIO);
1272
1273                 if ((flag & FWRITE) == 0)
1274                         return (EBADF);
1275
1276                 if ((error = ccdlock(cs)) != 0)
1277                         return (error);
1278
1279                 cs->sc_flags |= CCDF_LABELLING;
1280
1281                 error = setdisklabel(&cs->sc_label,
1282                     (struct disklabel *)data, 0);
1283                 if (error == 0) {
1284                         if (cmd == DIOCWDINFO)
1285                                 error = writedisklabel(CCDLABELDEV(dev),
1286                                     ccdstrategy, &cs->sc_label);
1287                 }
1288
1289                 cs->sc_flags &= ~CCDF_LABELLING;
1290
1291                 ccdunlock(cs);
1292
1293                 if (error)
1294                         return (error);
1295                 break;
1296
1297         case DIOCWLABEL:
1298                 if ((cs->sc_flags & CCDF_INITED) == 0)
1299                         return (ENXIO);
1300
1301                 if ((flag & FWRITE) == 0)
1302                         return (EBADF);
1303                 if (*(int *)data != 0)
1304                         cs->sc_flags |= CCDF_WLABEL;
1305                 else
1306                         cs->sc_flags &= ~CCDF_WLABEL;
1307                 break;
1308
1309         default:
1310                 return (ENOTTY);
1311         }
1312
1313         return (0);
1314 }
1315
1316 static int
1317 ccdsize(dev)
1318         dev_t dev;
1319 {
1320         struct ccd_softc *cs;
1321         int part, size;
1322
1323         if (ccdopen(dev, 0, S_IFBLK, curproc))
1324                 return (-1);
1325
1326         cs = &ccd_softc[ccdunit(dev)];
1327         part = ccdpart(dev);
1328
1329         if ((cs->sc_flags & CCDF_INITED) == 0)
1330                 return (-1);
1331
1332         if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1333                 size = -1;
1334         else
1335                 size = cs->sc_label.d_partitions[part].p_size;
1336
1337         if (ccdclose(dev, 0, S_IFBLK, curproc))
1338                 return (-1);
1339
1340         return (size);
1341 }
1342
1343 static int
1344 ccddump(dev)
1345         dev_t dev;
1346 {
1347
1348         /* Not implemented. */
1349         return ENXIO;
1350 }
1351
1352 /*
1353  * Lookup the provided name in the filesystem.  If the file exists,
1354  * is a valid block device, and isn't being used by anyone else,
1355  * set *vpp to the file's vnode.
1356  */
1357 static int
1358 ccdlookup(path, p, vpp)
1359         char *path;
1360         struct proc *p;
1361         struct vnode **vpp;     /* result */
1362 {
1363         struct nameidata nd;
1364         struct vnode *vp;
1365         struct vattr va;
1366         int error;
1367
1368         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1369         if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1370 #ifdef DEBUG
1371                 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1372                         printf("ccdlookup: vn_open error = %d\n", error);
1373 #endif
1374                 return (error);
1375         }
1376         vp = nd.ni_vp;
1377
1378         if (vp->v_usecount > 1) {
1379                 VOP_UNLOCK(vp, 0, p);
1380                 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1381                 return (EBUSY);
1382         }
1383
1384         if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1385 #ifdef DEBUG
1386                 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1387                         printf("ccdlookup: getattr error = %d\n", error);
1388 #endif
1389                 VOP_UNLOCK(vp, 0, p);
1390                 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1391                 return (error);
1392         }
1393
1394         /* XXX: eventually we should handle VREG, too. */
1395         if (va.va_type != VBLK) {
1396                 VOP_UNLOCK(vp, 0, p);
1397                 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1398                 return (ENOTBLK);
1399         }
1400
1401 #ifdef DEBUG
1402         if (ccddebug & CCDB_VNODE)
1403                 vprint("ccdlookup: vnode info", vp);
1404 #endif
1405
1406         VOP_UNLOCK(vp, 0, p);
1407         *vpp = vp;
1408         return (0);
1409 }
1410
1411 /*
1412  * Read the disklabel from the ccd.  If one is not present, fake one
1413  * up.
1414  */
1415 static void
1416 ccdgetdisklabel(dev)
1417         dev_t dev;
1418 {
1419         int unit = ccdunit(dev);
1420         struct ccd_softc *cs = &ccd_softc[unit];
1421         char *errstring;
1422         struct disklabel *lp = &cs->sc_label;
1423         struct ccdgeom *ccg = &cs->sc_geom;
1424
1425         bzero(lp, sizeof(*lp));
1426
1427         lp->d_secperunit = cs->sc_size;
1428         lp->d_secsize = ccg->ccg_secsize;
1429         lp->d_nsectors = ccg->ccg_nsectors;
1430         lp->d_ntracks = ccg->ccg_ntracks;
1431         lp->d_ncylinders = ccg->ccg_ncylinders;
1432         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1433
1434         strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1435         lp->d_type = DTYPE_CCD;
1436         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1437         lp->d_rpm = 3600;
1438         lp->d_interleave = 1;
1439         lp->d_flags = 0;
1440
1441         lp->d_partitions[RAW_PART].p_offset = 0;
1442         lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1443         lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1444         lp->d_npartitions = RAW_PART + 1;
1445
1446         lp->d_bbsize = BBSIZE;                          /* XXX */
1447         lp->d_sbsize = SBSIZE;                          /* XXX */
1448
1449         lp->d_magic = DISKMAGIC;
1450         lp->d_magic2 = DISKMAGIC;
1451         lp->d_checksum = dkcksum(&cs->sc_label);
1452
1453         /*
1454          * Call the generic disklabel extraction routine.
1455          */
1456         if ((errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1457             &cs->sc_label)) != NULL)
1458                 ccdmakedisklabel(cs);
1459
1460 #ifdef DEBUG
1461         /* It's actually extremely common to have unlabeled ccds. */
1462         if (ccddebug & CCDB_LABEL)
1463                 if (errstring != NULL)
1464                         printf("ccd%d: %s\n", unit, errstring);
1465 #endif
1466 }
1467
1468 /*
1469  * Take care of things one might want to take care of in the event
1470  * that a disklabel isn't present.
1471  */
1472 static void
1473 ccdmakedisklabel(cs)
1474         struct ccd_softc *cs;
1475 {
1476         struct disklabel *lp = &cs->sc_label;
1477
1478         /*
1479          * For historical reasons, if there's no disklabel present
1480          * the raw partition must be marked FS_BSDFFS.
1481          */
1482         lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1483
1484         strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1485 }
1486
1487 /*
1488  * Wait interruptibly for an exclusive lock.
1489  *
1490  * XXX
1491  * Several drivers do this; it should be abstracted and made MP-safe.
1492  */
1493 static int
1494 ccdlock(cs)
1495         struct ccd_softc *cs;
1496 {
1497         int error;
1498
1499         while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1500                 cs->sc_flags |= CCDF_WANTED;
1501                 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1502                         return (error);
1503         }
1504         cs->sc_flags |= CCDF_LOCKED;
1505         return (0);
1506 }
1507
1508 /*
1509  * Unlock and wake up any waiters.
1510  */
1511 static void
1512 ccdunlock(cs)
1513         struct ccd_softc *cs;
1514 {
1515
1516         cs->sc_flags &= ~CCDF_LOCKED;
1517         if ((cs->sc_flags & CCDF_WANTED) != 0) {
1518                 cs->sc_flags &= ~CCDF_WANTED;
1519                 wakeup(cs);
1520         }
1521 }
1522
1523 #ifdef DEBUG
1524 static void
1525 printiinfo(ii)
1526         struct ccdiinfo *ii;
1527 {
1528         register int ix, i;
1529
1530         for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1531                 printf(" itab[%d]: #dk %d sblk %d soff %d",
1532                        ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1533                 for (i = 0; i < ii->ii_ndisk; i++)
1534                         printf(" %d", ii->ii_index[i]);
1535                 printf("\n");
1536         }
1537 }
1538 #endif
1539
1540 #endif /* NCCD > 0 */
1541 \f
1542 /* Local Variables: */
1543 /* c-argdecl-indent: 8 */
1544 /* c-continued-statement-offset: 8 */
1545 /* c-indent-level: 8 */
1546 /* End: */