Remove unused define.
[dragonfly/vkernel-mp.git] / sys / dev / disk / ccd / ccd.c
blob4eabcdc1cd3ac873a64105dcf736b93567b24a42
1 /*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.44 2007/05/22 21:28:56 dillon Exp $
37 * Copyright (c) 1995 Jason R. Thorpe.
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed for the NetBSD Project
51 * by Jason R. Thorpe.
52 * 4. The name of the author may not be used to endorse or promote products
53 * derived from this software without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
56 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
57 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
58 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
59 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
60 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
62 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
63 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
69 * Copyright (c) 1988 University of Utah.
70 * Copyright (c) 1990, 1993
71 * The Regents of the University of California. All rights reserved.
73 * This code is derived from software contributed to Berkeley by
74 * the Systems Programming Group of the University of Utah Computer
75 * Science Department.
77 * Redistribution and use in source and binary forms, with or without
78 * modification, are permitted provided that the following conditions
79 * are met:
80 * 1. Redistributions of source code must retain the above copyright
81 * notice, this list of conditions and the following disclaimer.
82 * 2. Redistributions in binary form must reproduce the above copyright
83 * notice, this list of conditions and the following disclaimer in the
84 * documentation and/or other materials provided with the distribution.
85 * 3. All advertising materials mentioning features or use of this software
86 * must display the following acknowledgement:
87 * This product includes software developed by the University of
88 * California, Berkeley and its contributors.
89 * 4. Neither the name of the University nor the names of its contributors
90 * may be used to endorse or promote products derived from this software
91 * without specific prior written permission.
93 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
94 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
95 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
96 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
97 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
98 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
99 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
101 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
102 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
103 * SUCH DAMAGE.
105 * from: Utah $Hdr: cd.c 1.6 90/11/28$
108 * @(#)cd.c 8.2 (Berkeley) 11/16/93
109 * $FreeBSD: src/sys/dev/ccd/ccd.c,v 1.73.2.1 2001/09/11 09:49:52 kris Exp $
110 * $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $
111 * $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.44 2007/05/22 21:28:56 dillon Exp $
115 * "Concatenated" disk driver.
117 * Original dynamic configuration support by:
118 * Jason R. Thorpe <thorpej@nas.nasa.gov>
119 * Numerical Aerodynamic Simulation Facility
120 * Mail Stop 258-6
121 * NASA Ames Research Center
122 * Moffett Field, CA 94035
125 #include "use_ccd.h"
127 #include <sys/param.h>
128 #include <sys/systm.h>
129 #include <sys/kernel.h>
130 #include <sys/module.h>
131 #include <sys/proc.h>
132 #include <sys/buf.h>
133 #include <sys/malloc.h>
134 #include <sys/nlookup.h>
135 #include <sys/conf.h>
136 #include <sys/stat.h>
137 #include <sys/sysctl.h>
138 #include <sys/disk.h>
139 #include <sys/diskslice.h>
140 #include <sys/devicestat.h>
141 #include <sys/fcntl.h>
142 #include <sys/vnode.h>
143 #include <sys/buf2.h>
144 #include <sys/ccdvar.h>
146 #include <vm/vm_zone.h>
148 #include <vfs/ufs/dinode.h> /* XXX Used only for fs.h */
149 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE and SBSIZE */
151 #include <sys/thread2.h>
153 #if defined(CCDDEBUG) && !defined(DEBUG)
154 #define DEBUG
155 #endif
157 #ifdef DEBUG
158 #define CCDB_FOLLOW 0x01
159 #define CCDB_INIT 0x02
160 #define CCDB_IO 0x04
161 #define CCDB_LABEL 0x08
162 #define CCDB_VNODE 0x10
163 static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
164 CCDB_VNODE;
165 SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
166 #undef DEBUG
167 #endif
169 #define ccdunit(x) dkunit(x)
170 #define ccdpart(x) dkpart(x)
173 This is how mirroring works (only writes are special):
175 When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
176 linked together by the cb_mirror field. "cb_pflags &
177 CCDPF_MIRROR_DONE" is set to 0 on both of them.
179 When a component returns to ccdiodone(), it checks if "cb_pflags &
180 CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's
181 flag and returns. If it is, it means its partner has already
182 returned, so it will go to the regular cleanup.
186 struct ccdbuf {
187 struct buf cb_buf; /* new I/O buf */
188 struct vnode *cb_vp; /* related vnode */
189 struct bio *cb_obio; /* ptr. to original I/O buf */
190 struct ccdbuf *cb_freenext; /* free list link */
191 int cb_unit; /* target unit */
192 int cb_comp; /* target component */
193 int cb_pflags; /* mirror/parity status flag */
194 struct ccdbuf *cb_mirror; /* mirror counterpart */
197 /* bits in cb_pflags */
198 #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */
200 static d_open_t ccdopen;
201 static d_close_t ccdclose;
202 static d_strategy_t ccdstrategy;
203 static d_ioctl_t ccdioctl;
204 static d_dump_t ccddump;
206 #define NCCDFREEHIWAT 16
208 #define CDEV_MAJOR 74
210 static struct dev_ops ccd_ops = {
211 { "ccd", CDEV_MAJOR, D_DISK },
212 .d_open = ccdopen,
213 .d_close = ccdclose,
214 .d_read = physread,
215 .d_write = physwrite,
216 .d_ioctl = ccdioctl,
217 .d_strategy = ccdstrategy,
218 .d_dump = ccddump
221 /* called during module initialization */
222 static void ccdattach (void);
223 static int ccd_modevent (module_t, int, void *);
225 /* called by biodone() at interrupt time */
226 static void ccdiodone (struct bio *bio);
228 static void ccdstart (struct ccd_softc *, struct bio *);
229 static void ccdinterleave (struct ccd_softc *, int);
230 static void ccdintr (struct ccd_softc *, struct bio *);
231 static int ccdinit (struct ccddevice *, char **, struct ucred *);
232 static int ccdlookup (char *, struct vnode **);
233 static void ccdbuffer (struct ccdbuf **ret, struct ccd_softc *,
234 struct bio *, off_t, caddr_t, long);
235 static int ccdlock (struct ccd_softc *);
236 static void ccdunlock (struct ccd_softc *);
238 #ifdef DEBUG
239 static void printiinfo (struct ccdiinfo *);
240 #endif
242 /* Non-private for the benefit of libkvm. */
243 struct ccd_softc *ccd_softc;
244 struct ccddevice *ccddevs;
245 struct ccdbuf *ccdfreebufs;
246 static int numccdfreebufs;
247 static int numccd = 0;
250 * getccdbuf() - Allocate and zero a ccd buffer.
252 * This routine is called at splbio().
255 static __inline
256 struct ccdbuf *
257 getccdbuf(void)
259 struct ccdbuf *cbp;
262 * Allocate from freelist or malloc as necessary
264 if ((cbp = ccdfreebufs) != NULL) {
265 ccdfreebufs = cbp->cb_freenext;
266 --numccdfreebufs;
267 reinitbufbio(&cbp->cb_buf);
268 } else {
269 cbp = kmalloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK|M_ZERO);
270 initbufbio(&cbp->cb_buf);
274 * independant struct buf initialization
276 LIST_INIT(&cbp->cb_buf.b_dep);
277 BUF_LOCKINIT(&cbp->cb_buf);
278 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
279 BUF_KERNPROC(&cbp->cb_buf);
280 cbp->cb_buf.b_flags = B_PAGING | B_BNOCLIP;
282 return(cbp);
286 * putccdbuf() - Free a ccd buffer.
288 * This routine is called at splbio().
291 static __inline
292 void
293 putccdbuf(struct ccdbuf *cbp)
295 BUF_UNLOCK(&cbp->cb_buf);
296 BUF_LOCKFREE(&cbp->cb_buf);
298 if (numccdfreebufs < NCCDFREEHIWAT) {
299 cbp->cb_freenext = ccdfreebufs;
300 ccdfreebufs = cbp;
301 ++numccdfreebufs;
302 } else {
303 kfree((caddr_t)cbp, M_DEVBUF);
308 * Called by main() during pseudo-device attachment. All we need
309 * to do is allocate enough space for devices to be configured later, and
310 * add devsw entries.
312 static void
313 ccdattach(void)
315 struct disk_info info;
316 struct ccd_softc *cs;
317 int i;
318 int num = NCCD;
320 if (num > 1)
321 kprintf("ccd0-%d: Concatenated disk drivers\n", num-1);
322 else
323 kprintf("ccd0: Concatenated disk driver\n");
325 ccd_softc = kmalloc(num * sizeof(struct ccd_softc), M_DEVBUF,
326 M_WAITOK | M_ZERO);
327 ccddevs = kmalloc(num * sizeof(struct ccddevice), M_DEVBUF,
328 M_WAITOK | M_ZERO);
329 numccd = num;
332 * With normal disk devices the open simply fails if the media
333 * is not present. With CCD we have to be able to open the
334 * raw disk to use the ioctl's to set it up, so create a dummy
335 * disk info structure so dscheck() doesn't blow up.
337 bzero(&info, sizeof(info));
338 info.d_media_blksize = DEV_BSIZE;
340 for (i = 0; i < numccd; ++i) {
341 cs = &ccd_softc[i];
342 cs->sc_dev = disk_create(i, &cs->sc_disk, &ccd_ops);
343 cs->sc_dev->si_drv1 = cs;
344 cs->sc_dev->si_iosize_max = 256 * 512; /* XXX */
345 disk_setdiskinfo(&cs->sc_disk, &info);
349 static int
350 ccd_modevent(module_t mod, int type, void *data)
352 int error = 0;
354 switch (type) {
355 case MOD_LOAD:
356 ccdattach();
357 break;
359 case MOD_UNLOAD:
360 kprintf("ccd0: Unload not supported!\n");
361 error = EOPNOTSUPP;
362 break;
364 default: /* MOD_SHUTDOWN etc */
365 break;
367 return (error);
370 DEV_MODULE(ccd, ccd_modevent, NULL);
372 static int
373 ccdinit(struct ccddevice *ccd, char **cpaths, struct ucred *cred)
375 struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
376 struct ccdcinfo *ci = NULL; /* XXX */
377 int ix;
378 struct vnode *vp;
379 u_int64_t skip;
380 u_int64_t size;
381 u_int64_t minsize;
382 int maxsecsize;
383 struct partinfo dpart;
384 struct ccdgeom *ccg = &cs->sc_geom;
385 char tmppath[MAXPATHLEN];
386 int error = 0;
388 #ifdef DEBUG
389 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
390 kprintf("ccdinit: unit %d\n", ccd->ccd_unit);
391 #endif
393 cs->sc_size = 0;
394 cs->sc_ileave = ccd->ccd_interleave;
395 cs->sc_nccdisks = ccd->ccd_ndev;
397 /* Allocate space for the component info. */
398 cs->sc_cinfo = kmalloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
399 M_DEVBUF, M_WAITOK);
402 * Verify that each component piece exists and record
403 * relevant information about it.
405 maxsecsize = 0;
406 minsize = 0;
407 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
408 vp = ccd->ccd_vpp[ix];
409 ci = &cs->sc_cinfo[ix];
410 ci->ci_vp = vp;
413 * Copy in the pathname of the component.
415 bzero(tmppath, sizeof(tmppath)); /* sanity */
416 if ((error = copyinstr(cpaths[ix], tmppath,
417 MAXPATHLEN, &ci->ci_pathlen)) != 0) {
418 #ifdef DEBUG
419 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
420 kprintf("ccd%d: can't copy path, error = %d\n",
421 ccd->ccd_unit, error);
422 #endif
423 goto fail;
425 ci->ci_path = kmalloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
426 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
428 ci->ci_dev = vn_todev(vp);
431 * Get partition information for the component.
433 error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, FREAD, cred);
434 if (error) {
435 #ifdef DEBUG
436 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
437 kprintf("ccd%d: %s: ioctl failed, error = %d\n",
438 ccd->ccd_unit, ci->ci_path, error);
439 #endif
440 goto fail;
442 if (dpart.fstype != FS_CCD &&
443 strcmp(dpart.fstypestr, "ccd") != 0) {
444 kprintf("ccd%d: %s: filesystem type must be 'ccd'\n",
445 ccd->ccd_unit, ci->ci_path);
446 error = EFTYPE;
447 goto fail;
449 if (maxsecsize < dpart.media_blksize)
450 maxsecsize = dpart.media_blksize;
453 * Skip a certain amount of storage at the beginning of
454 * the component to make sure we don't infringe on any
455 * reserved sectors. This is handled entirely by
456 * dpart.skip_bsdlabel but we also impose a minimum
457 * of 16 sectors for backwards compatibility.
459 skip = 16;
460 if (skip < dpart.skip_bsdlabel)
461 skip = dpart.skip_bsdlabel;
462 size = dpart.media_blocks - skip;
465 * Calculate the size, truncating to an interleave
466 * boundary if necessary.
468 if (cs->sc_ileave > 1)
469 size -= size % cs->sc_ileave;
471 if ((int64_t)size <= 0) {
472 #ifdef DEBUG
473 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
474 kprintf("ccd%d: %s: size == 0\n",
475 ccd->ccd_unit, ci->ci_path);
476 #endif
477 error = ENODEV;
478 goto fail;
482 * Calculate the smallest uniform component, used
483 * elsewhere.
485 if (minsize == 0 || minsize > size)
486 minsize = size;
487 ci->ci_skip = skip;
488 ci->ci_size = size;
489 cs->sc_size += size;
493 * Don't allow the interleave to be smaller than
494 * the biggest component sector.
496 if ((cs->sc_ileave > 0) &&
497 (cs->sc_ileave % (maxsecsize / DEV_BSIZE))) {
498 #ifdef DEBUG
499 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
500 kprintf("ccd%d: interleave must be at least %d\n",
501 ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
502 #endif
503 error = EINVAL;
504 goto fail;
508 * If uniform interleave is desired set all sizes to that of
509 * the smallest component. This will guarentee that a single
510 * interleave table is generated.
512 * Lost space must be taken into account when calculating the
513 * overall size. Half the space is lost when CCDF_MIRROR is
514 * specified. One disk is lost when CCDF_PARITY is specified.
516 if (ccd->ccd_flags & CCDF_UNIFORM) {
517 for (ci = cs->sc_cinfo;
518 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
519 ci->ci_size = minsize;
521 if (ccd->ccd_flags & CCDF_MIRROR) {
523 * Check to see if an even number of components
524 * have been specified. The interleave must also
525 * be non-zero in order for us to be able to
526 * guarentee the topology.
528 if (cs->sc_nccdisks % 2) {
529 kprintf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
530 error = EINVAL;
531 goto fail;
533 if (cs->sc_ileave == 0) {
534 kprintf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
535 error = EINVAL;
536 goto fail;
538 cs->sc_size = (cs->sc_nccdisks/2) * minsize;
539 } else if (ccd->ccd_flags & CCDF_PARITY) {
540 cs->sc_size = (cs->sc_nccdisks-1) * minsize;
541 } else {
542 if (cs->sc_ileave == 0) {
543 kprintf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
544 error = EINVAL;
545 goto fail;
547 cs->sc_size = cs->sc_nccdisks * minsize;
552 * Construct the interleave table.
554 ccdinterleave(cs, ccd->ccd_unit);
557 * Create pseudo-geometry based on 1MB cylinders. It's
558 * pretty close.
560 ccg->ccg_secsize = maxsecsize;
561 ccg->ccg_ntracks = 1;
562 ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
563 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
566 * Add an devstat entry for this device.
568 devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
569 ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
570 DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
571 DEVSTAT_PRIORITY_ARRAY);
573 cs->sc_flags |= CCDF_INITED;
574 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
575 cs->sc_unit = ccd->ccd_unit;
576 return (0);
577 fail:
578 while (ci > cs->sc_cinfo) {
579 ci--;
580 kfree(ci->ci_path, M_DEVBUF);
582 kfree(cs->sc_cinfo, M_DEVBUF);
583 cs->sc_cinfo = NULL;
584 return (error);
587 static void
588 ccdinterleave(struct ccd_softc *cs, int unit)
590 struct ccdcinfo *ci, *smallci;
591 struct ccdiinfo *ii;
592 u_int64_t bn;
593 u_int64_t lbn;
594 int ix;
595 u_long size;
597 #ifdef DEBUG
598 if (ccddebug & CCDB_INIT)
599 kprintf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
600 #endif
603 * Allocate an interleave table. The worst case occurs when each
604 * of N disks is of a different size, resulting in N interleave
605 * tables.
607 * Chances are this is too big, but we don't care.
609 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
610 cs->sc_itable = kmalloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
613 * Trivial case: no interleave (actually interleave of disk size).
614 * Each table entry represents a single component in its entirety.
616 * An interleave of 0 may not be used with a mirror or parity setup.
618 if (cs->sc_ileave == 0) {
619 bn = 0;
620 ii = cs->sc_itable;
622 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
623 /* Allocate space for ii_index. */
624 ii->ii_index = kmalloc(sizeof(int), M_DEVBUF, M_WAITOK);
625 ii->ii_ndisk = 1;
626 ii->ii_startblk = bn;
627 ii->ii_startoff = 0;
628 ii->ii_index[0] = ix;
629 bn += cs->sc_cinfo[ix].ci_size;
630 ii++;
632 ii->ii_ndisk = 0;
633 #ifdef DEBUG
634 if (ccddebug & CCDB_INIT)
635 printiinfo(cs->sc_itable);
636 #endif
637 return;
641 * The following isn't fast or pretty; it doesn't have to be.
643 size = 0;
644 bn = lbn = 0;
645 for (ii = cs->sc_itable; ; ii++) {
647 * Allocate space for ii_index. We might allocate more then
648 * we use.
650 ii->ii_index = kmalloc((sizeof(int) * cs->sc_nccdisks),
651 M_DEVBUF, M_WAITOK);
654 * Locate the smallest of the remaining components
656 smallci = NULL;
657 ci = cs->sc_cinfo;
658 while (ci < &cs->sc_cinfo[cs->sc_nccdisks]) {
659 if (ci->ci_size > size &&
660 (smallci == NULL ||
661 ci->ci_size < smallci->ci_size)) {
662 smallci = ci;
664 ++ci;
668 * Nobody left, all done
670 if (smallci == NULL) {
671 ii->ii_ndisk = 0;
672 break;
676 * Record starting logical block using an sc_ileave blocksize.
678 ii->ii_startblk = bn / cs->sc_ileave;
681 * Record starting comopnent block using an sc_ileave
682 * blocksize. This value is relative to the beginning of
683 * a component disk.
685 ii->ii_startoff = lbn;
688 * Determine how many disks take part in this interleave
689 * and record their indices.
691 ix = 0;
692 for (ci = cs->sc_cinfo;
693 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
694 if (ci->ci_size >= smallci->ci_size) {
695 ii->ii_index[ix++] = ci - cs->sc_cinfo;
698 ii->ii_ndisk = ix;
699 bn += ix * (smallci->ci_size - size);
700 lbn = smallci->ci_size / cs->sc_ileave;
701 size = smallci->ci_size;
703 #ifdef DEBUG
704 if (ccddebug & CCDB_INIT)
705 printiinfo(cs->sc_itable);
706 #endif
709 /* ARGSUSED */
710 static int
711 ccdopen(struct dev_open_args *ap)
713 cdev_t dev = ap->a_head.a_dev;
714 int unit = ccdunit(dev);
715 struct ccd_softc *cs;
716 int error = 0;
718 #ifdef DEBUG
719 if (ccddebug & CCDB_FOLLOW)
720 kprintf("ccdopen(%x, %x)\n", dev, flags);
721 #endif
722 if (unit >= numccd)
723 return (ENXIO);
724 cs = &ccd_softc[unit];
726 if ((error = ccdlock(cs)) == 0) {
727 ccdunlock(cs);
729 return (error);
732 /* ARGSUSED */
733 static int
734 ccdclose(struct dev_close_args *ap)
736 cdev_t dev = ap->a_head.a_dev;
737 int unit = ccdunit(dev);
738 struct ccd_softc *cs;
739 int error = 0;
741 #ifdef DEBUG
742 if (ccddebug & CCDB_FOLLOW)
743 kprintf("ccdclose(%x, %x)\n", dev, flags);
744 #endif
746 if (unit >= numccd)
747 return (ENXIO);
748 cs = &ccd_softc[unit];
749 if ((error = ccdlock(cs)) == 0) {
750 ccdunlock(cs);
752 return (error);
755 static int
756 ccdstrategy(struct dev_strategy_args *ap)
758 cdev_t dev = ap->a_head.a_dev;
759 struct bio *bio = ap->a_bio;
760 int unit = ccdunit(dev);
761 struct bio *nbio;
762 struct buf *bp = bio->bio_buf;
763 struct ccd_softc *cs = &ccd_softc[unit];
764 u_int64_t pbn; /* in sc_secsize chunks */
765 u_int32_t sz; /* in sc_secsize chunks */
767 #ifdef DEBUG
768 if (ccddebug & CCDB_FOLLOW)
769 kprintf("ccdstrategy(%x): unit %d\n", bp, unit);
770 #endif
771 if ((cs->sc_flags & CCDF_INITED) == 0) {
772 bp->b_error = ENXIO;
773 goto error;
776 /* If it's a nil transfer, wake up the top half now. */
777 if (bp->b_bcount == 0) {
778 bp->b_resid = 0;
779 goto done;
783 * Do bounds checking and adjust transfer. If there's an
784 * error, the bounds check will flag that for us.
787 pbn = bio->bio_offset / cs->sc_geom.ccg_secsize;
788 sz = howmany(bp->b_bcount, cs->sc_geom.ccg_secsize);
791 * If out of bounds return an error. If the request goes
792 * past EOF, clip the request as appropriate. If exactly
793 * at EOF, return success (don't clip), but with 0 bytes
794 * of I/O.
796 * Mark EOF B_INVAL (just like bad), indicating that the
797 * contents of the buffer, if any, is invalid.
799 if ((int64_t)pbn < 0)
800 goto bad;
801 if (pbn + sz > cs->sc_size) {
802 if (pbn > cs->sc_size || (bp->b_flags & B_BNOCLIP))
803 goto bad;
804 if (pbn == cs->sc_size) {
805 bp->b_resid = bp->b_bcount;
806 bp->b_flags |= B_INVAL;
807 goto done;
809 sz = (long)(cs->sc_size - pbn);
810 bp->b_bcount = sz * cs->sc_geom.ccg_secsize;
812 nbio = bio;
814 bp->b_resid = bp->b_bcount;
815 nbio->bio_driver_info = dev;
818 * "Start" the unit.
820 crit_enter();
821 ccdstart(cs, nbio);
822 crit_exit();
823 return(0);
826 * note: bio, not nbio, is valid at the done label.
828 bad:
829 bp->b_error = EINVAL;
830 error:
831 bp->b_resid = bp->b_bcount;
832 bp->b_flags |= B_ERROR | B_INVAL;
833 done:
834 biodone(bio);
835 return(0);
838 static void
839 ccdstart(struct ccd_softc *cs, struct bio *bio)
841 long bcount, rcount;
842 struct ccdbuf *cbp[4];
843 struct buf *bp = bio->bio_buf;
844 /* XXX! : 2 reads and 2 writes for RAID 4/5 */
845 caddr_t addr;
846 off_t doffset;
848 #ifdef DEBUG
849 if (ccddebug & CCDB_FOLLOW)
850 kprintf("ccdstart(%x, %x)\n", cs, bp);
851 #endif
853 /* Record the transaction start */
854 devstat_start_transaction(&cs->device_stats);
857 * Allocate component buffers and fire off the requests
859 doffset = bio->bio_offset;
860 addr = bp->b_data;
862 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
863 ccdbuffer(cbp, cs, bio, doffset, addr, bcount);
864 rcount = cbp[0]->cb_buf.b_bcount;
866 if (cs->sc_cflags & CCDF_MIRROR) {
868 * Mirroring. Writes go to both disks, reads are
869 * taken from whichever disk seems most appropriate.
871 * We attempt to localize reads to the disk whos arm
872 * is nearest the read request. We ignore seeks due
873 * to writes when making this determination and we
874 * also try to avoid hogging.
876 if (cbp[0]->cb_buf.b_cmd != BUF_CMD_READ) {
877 vn_strategy(cbp[0]->cb_vp,
878 &cbp[0]->cb_buf.b_bio1);
879 vn_strategy(cbp[1]->cb_vp,
880 &cbp[1]->cb_buf.b_bio1);
881 } else {
882 int pick = cs->sc_pick;
883 daddr_t range = cs->sc_size / 16 * cs->sc_geom.ccg_secsize;
884 if (doffset < cs->sc_blk[pick] - range ||
885 doffset > cs->sc_blk[pick] + range
887 cs->sc_pick = pick = 1 - pick;
889 cs->sc_blk[pick] = doffset + rcount;
890 vn_strategy(cbp[pick]->cb_vp,
891 &cbp[pick]->cb_buf.b_bio1);
893 } else {
895 * Not mirroring
897 vn_strategy(cbp[0]->cb_vp,
898 &cbp[0]->cb_buf.b_bio1);
900 doffset += rcount;
901 addr += rcount;
906 * Build a component buffer header.
908 static void
909 ccdbuffer(struct ccdbuf **cb, struct ccd_softc *cs, struct bio *bio,
910 off_t doffset, caddr_t addr, long bcount)
912 struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
913 struct ccdbuf *cbp;
914 u_int64_t bn;
915 u_int64_t cbn;
916 u_int64_t cboff;
917 off_t cbc;
919 #ifdef DEBUG
920 if (ccddebug & CCDB_IO)
921 kprintf("ccdbuffer(%x, %x, %d, %x, %d)\n",
922 cs, bp, bn, addr, bcount);
923 #endif
925 * Determine which component bn falls in.
927 bn = doffset / cs->sc_geom.ccg_secsize;
928 cbn = bn;
929 cboff = 0;
931 if (cs->sc_ileave == 0) {
933 * Serially concatenated and neither a mirror nor a parity
934 * config. This is a special case.
936 daddr_t sblk;
938 sblk = 0;
939 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
940 sblk += ci->ci_size;
941 cbn -= sblk;
942 } else {
943 struct ccdiinfo *ii;
944 int ccdisk, off;
947 * Calculate cbn, the logical superblock (sc_ileave chunks),
948 * and cboff, a normal block offset (DEV_BSIZE chunks) relative
949 * to cbn.
951 cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */
952 cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */
955 * Figure out which interleave table to use.
957 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
958 if (ii->ii_startblk > cbn)
959 break;
961 ii--;
964 * off is the logical superblock relative to the beginning
965 * of this interleave block.
967 off = cbn - ii->ii_startblk;
970 * We must calculate which disk component to use (ccdisk),
971 * and recalculate cbn to be the superblock relative to
972 * the beginning of the component. This is typically done by
973 * adding 'off' and ii->ii_startoff together. However, 'off'
974 * must typically be divided by the number of components in
975 * this interleave array to be properly convert it from a
976 * CCD-relative logical superblock number to a
977 * component-relative superblock number.
979 if (ii->ii_ndisk == 1) {
981 * When we have just one disk, it can't be a mirror
982 * or a parity config.
984 ccdisk = ii->ii_index[0];
985 cbn = ii->ii_startoff + off;
986 } else {
987 if (cs->sc_cflags & CCDF_MIRROR) {
989 * We have forced a uniform mapping, resulting
990 * in a single interleave array. We double
991 * up on the first half of the available
992 * components and our mirror is in the second
993 * half. This only works with a single
994 * interleave array because doubling up
995 * doubles the number of sectors, so there
996 * cannot be another interleave array because
997 * the next interleave array's calculations
998 * would be off.
1000 int ndisk2 = ii->ii_ndisk / 2;
1001 ccdisk = ii->ii_index[off % ndisk2];
1002 cbn = ii->ii_startoff + off / ndisk2;
1003 ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
1004 } else if (cs->sc_cflags & CCDF_PARITY) {
1006 * XXX not implemented yet
1008 int ndisk2 = ii->ii_ndisk - 1;
1009 ccdisk = ii->ii_index[off % ndisk2];
1010 cbn = ii->ii_startoff + off / ndisk2;
1011 if (cbn % ii->ii_ndisk <= ccdisk)
1012 ccdisk++;
1013 } else {
1014 ccdisk = ii->ii_index[off % ii->ii_ndisk];
1015 cbn = ii->ii_startoff + off / ii->ii_ndisk;
1019 ci = &cs->sc_cinfo[ccdisk];
1022 * Convert cbn from a superblock to a normal block so it
1023 * can be used to calculate (along with cboff) the normal
1024 * block index into this particular disk.
1026 cbn *= cs->sc_ileave;
1030 * Fill in the component buf structure.
1032 * NOTE: devices do not use b_bufsize, only b_bcount, but b_bcount
1033 * will be truncated on device EOF so we use b_bufsize to detect
1034 * the case.
1036 cbp = getccdbuf();
1037 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1038 cbp->cb_buf.b_flags |= bio->bio_buf->b_flags;
1039 cbp->cb_buf.b_data = addr;
1040 cbp->cb_vp = ci->ci_vp;
1041 if (cs->sc_ileave == 0)
1042 cbc = dbtob((off_t)(ci->ci_size - cbn));
1043 else
1044 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1045 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1046 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1048 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1049 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1050 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + ci->ci_skip);
1053 * context for ccdiodone
1055 cbp->cb_obio = bio;
1056 cbp->cb_unit = cs - ccd_softc;
1057 cbp->cb_comp = ci - cs->sc_cinfo;
1059 #ifdef DEBUG
1060 if (ccddebug & CCDB_IO)
1061 kprintf(" dev %x(u%d): cbp %x off %lld addr %x bcnt %d\n",
1062 ci->ci_dev, ci-cs->sc_cinfo, cbp,
1063 cbp->cb_buf.b_bio1.bio_offset,
1064 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1065 #endif
1066 cb[0] = cbp;
1069 * Note: both I/O's setup when reading from mirror, but only one
1070 * will be executed.
1072 if (cs->sc_cflags & CCDF_MIRROR) {
1073 /* mirror, setup second I/O */
1074 cbp = getccdbuf();
1076 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1077 cbp->cb_buf.b_flags |= bio->bio_buf->b_flags;
1078 cbp->cb_buf.b_data = addr;
1079 cbp->cb_vp = ci2->ci_vp;
1080 if (cs->sc_ileave == 0)
1081 cbc = dbtob((off_t)(ci->ci_size - cbn));
1082 else
1083 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1084 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1085 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1087 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1088 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1089 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + ci2->ci_skip);
1092 * context for ccdiodone
1094 cbp->cb_obio = bio;
1095 cbp->cb_unit = cs - ccd_softc;
1096 cbp->cb_comp = ci2 - cs->sc_cinfo;
1097 cb[1] = cbp;
1098 /* link together the ccdbuf's and clear "mirror done" flag */
1099 cb[0]->cb_mirror = cb[1];
1100 cb[1]->cb_mirror = cb[0];
1101 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1102 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1106 static void
1107 ccdintr(struct ccd_softc *cs, struct bio *bio)
1109 struct buf *bp = bio->bio_buf;
1111 #ifdef DEBUG
1112 if (ccddebug & CCDB_FOLLOW)
1113 kprintf("ccdintr(%x, %x)\n", cs, bp);
1114 #endif
1116 * Request is done for better or worse, wakeup the top half.
1118 if (bp->b_flags & B_ERROR)
1119 bp->b_resid = bp->b_bcount;
1120 devstat_end_transaction_buf(&cs->device_stats, bp);
1121 biodone(bio);
1125 * Called at interrupt time.
1126 * Mark the component as done and if all components are done,
1127 * take a ccd interrupt.
1129 static void
1130 ccdiodone(struct bio *bio)
1132 struct ccdbuf *cbp = bio->bio_caller_info1.ptr;
1133 struct bio *obio = cbp->cb_obio;
1134 struct buf *obp = obio->bio_buf;
1135 int unit = cbp->cb_unit;
1136 int count;
1139 * Since we do not have exclusive access to underlying devices,
1140 * we can't keep cache translations around.
1142 clearbiocache(bio->bio_next);
1144 crit_enter();
1145 #ifdef DEBUG
1146 if (ccddebug & CCDB_FOLLOW)
1147 kprintf("ccdiodone(%x)\n", cbp);
1148 if (ccddebug & CCDB_IO) {
1149 kprintf("ccdiodone: bp %x bcount %d resid %d\n",
1150 obp, obp->b_bcount, obp->b_resid);
1151 kprintf(" dev %x(u%d), cbp %x off %lld addr %x bcnt %d\n",
1152 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1153 cbp->cb_buf.b_loffset, cbp->cb_buf.b_data,
1154 cbp->cb_buf.b_bcount);
1156 #endif
1159 * If an error occured, report it. If this is a mirrored
1160 * configuration and the first of two possible reads, do not
1161 * set the error in the bp yet because the second read may
1162 * succeed.
1164 if (cbp->cb_buf.b_flags & B_ERROR) {
1165 const char *msg = "";
1167 if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
1168 (cbp->cb_buf.b_cmd == BUF_CMD_READ) &&
1169 (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1171 * We will try our read on the other disk down
1172 * below, also reverse the default pick so if we
1173 * are doing a scan we do not keep hitting the
1174 * bad disk first.
1176 struct ccd_softc *cs = &ccd_softc[unit];
1178 msg = ", trying other disk";
1179 cs->sc_pick = 1 - cs->sc_pick;
1180 cs->sc_blk[cs->sc_pick] = obio->bio_offset;
1181 } else {
1182 obp->b_flags |= B_ERROR;
1183 obp->b_error = cbp->cb_buf.b_error ?
1184 cbp->cb_buf.b_error : EIO;
1186 kprintf("ccd%d: error %d on component %d offset %lld (ccd offset %lld)%s\n",
1187 unit, obp->b_error, cbp->cb_comp,
1188 cbp->cb_buf.b_bio2.bio_offset,
1189 obio->bio_offset, msg);
1193 * Process mirror. If we are writing, I/O has been initiated on both
1194 * buffers and we fall through only after both are finished.
1196 * If we are reading only one I/O is initiated at a time. If an
1197 * error occurs we initiate the second I/O and return, otherwise
1198 * we free the second I/O without initiating it.
1201 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
1202 if (cbp->cb_buf.b_cmd != BUF_CMD_READ) {
1204 * When writing, handshake with the second buffer
1205 * to determine when both are done. If both are not
1206 * done, return here.
1208 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1209 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1210 putccdbuf(cbp);
1211 crit_exit();
1212 return;
1214 } else {
1216 * When reading, either dispose of the second buffer
1217 * or initiate I/O on the second buffer if an error
1218 * occured with this one.
1220 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1221 if (cbp->cb_buf.b_flags & B_ERROR) {
1222 cbp->cb_mirror->cb_pflags |=
1223 CCDPF_MIRROR_DONE;
1224 vn_strategy(
1225 cbp->cb_mirror->cb_vp,
1226 &cbp->cb_mirror->cb_buf.b_bio1
1228 putccdbuf(cbp);
1229 crit_exit();
1230 return;
1231 } else {
1232 putccdbuf(cbp->cb_mirror);
1233 /* fall through */
1240 * Use our saved b_bufsize to determine if an unexpected EOF occured.
1242 count = cbp->cb_buf.b_bufsize;
1243 putccdbuf(cbp);
1246 * If all done, "interrupt".
1248 obp->b_resid -= count;
1249 if (obp->b_resid < 0)
1250 panic("ccdiodone: count");
1251 if (obp->b_resid == 0)
1252 ccdintr(&ccd_softc[unit], obio);
1253 crit_exit();
1256 static int
1257 ccdioctl(struct dev_ioctl_args *ap)
1259 cdev_t dev = ap->a_head.a_dev;
1260 int unit = ccdunit(dev);
1261 int i, j, lookedup = 0, error = 0;
1262 struct ccd_softc *cs;
1263 struct ccd_ioctl *ccio = (struct ccd_ioctl *)ap->a_data;
1264 struct ccddevice ccd;
1265 struct disk_info info;
1266 char **cpp;
1267 struct vnode **vpp;
1269 if (unit >= numccd)
1270 return (ENXIO);
1271 cs = &ccd_softc[unit];
1273 bzero(&ccd, sizeof(ccd));
1275 switch (ap->a_cmd) {
1276 case CCDIOCSET:
1277 if (cs->sc_flags & CCDF_INITED)
1278 return (EBUSY);
1280 if ((ap->a_fflag & FWRITE) == 0)
1281 return (EBADF);
1283 if ((error = ccdlock(cs)) != 0)
1284 return (error);
1286 if (ccio->ccio_ndisks > CCD_MAXNDISKS) {
1287 ccdunlock(cs);
1288 return (EINVAL);
1291 /* Fill in some important bits. */
1292 ccd.ccd_unit = unit;
1293 ccd.ccd_interleave = ccio->ccio_ileave;
1294 if (ccd.ccd_interleave == 0 &&
1295 ((ccio->ccio_flags & CCDF_MIRROR) ||
1296 (ccio->ccio_flags & CCDF_PARITY))) {
1297 kprintf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1298 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1300 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1301 (ccio->ccio_flags & CCDF_PARITY)) {
1302 kprintf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1303 ccio->ccio_flags &= ~CCDF_PARITY;
1305 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1306 !(ccio->ccio_flags & CCDF_UNIFORM)) {
1307 kprintf("ccd%d: mirror/parity forces uniform flag\n",
1308 unit);
1309 ccio->ccio_flags |= CCDF_UNIFORM;
1311 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1314 * Allocate space for and copy in the array of
1315 * componet pathnames and device numbers.
1317 cpp = kmalloc(ccio->ccio_ndisks * sizeof(char *),
1318 M_DEVBUF, M_WAITOK);
1319 vpp = kmalloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1320 M_DEVBUF, M_WAITOK);
1322 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1323 ccio->ccio_ndisks * sizeof(char **));
1324 if (error) {
1325 kfree(vpp, M_DEVBUF);
1326 kfree(cpp, M_DEVBUF);
1327 ccdunlock(cs);
1328 return (error);
1331 #ifdef DEBUG
1332 if (ccddebug & CCDB_INIT) {
1333 for (i = 0; i < ccio->ccio_ndisks; ++i)
1334 kprintf("ccdioctl: component %d: 0x%x\n",
1335 i, cpp[i]);
1337 #endif
1339 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1340 #ifdef DEBUG
1341 if (ccddebug & CCDB_INIT)
1342 kprintf("ccdioctl: lookedup = %d\n", lookedup);
1343 #endif
1344 if ((error = ccdlookup(cpp[i], &vpp[i])) != 0) {
1345 for (j = 0; j < lookedup; ++j)
1346 (void)vn_close(vpp[j], FREAD|FWRITE);
1347 kfree(vpp, M_DEVBUF);
1348 kfree(cpp, M_DEVBUF);
1349 ccdunlock(cs);
1350 return (error);
1352 ++lookedup;
1354 ccd.ccd_cpp = cpp;
1355 ccd.ccd_vpp = vpp;
1356 ccd.ccd_ndev = ccio->ccio_ndisks;
1359 * Initialize the ccd. Fills in the softc for us.
1361 if ((error = ccdinit(&ccd, cpp, ap->a_cred)) != 0) {
1362 for (j = 0; j < lookedup; ++j)
1363 (void)vn_close(vpp[j], FREAD|FWRITE);
1364 kfree(vpp, M_DEVBUF);
1365 kfree(cpp, M_DEVBUF);
1366 ccdunlock(cs);
1367 return (error);
1371 * The ccd has been successfully initialized, so
1372 * we can place it into the array and read the disklabel.
1374 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1375 ccio->ccio_unit = unit;
1376 ccio->ccio_size = cs->sc_size;
1378 bzero(&info, sizeof(info));
1379 info.d_media_blksize = cs->sc_geom.ccg_secsize;
1380 info.d_media_blocks = cs->sc_size;
1381 info.d_nheads = cs->sc_geom.ccg_ntracks;
1382 info.d_secpertrack = cs->sc_geom.ccg_nsectors;
1383 info.d_ncylinders = cs->sc_geom.ccg_ncylinders;
1384 info.d_secpercyl = info.d_nheads * info.d_secpertrack;
1387 * For cases where a label is directly applied to the ccd,
1388 * without slices, DSO_COMPATMBR forces one sector be
1389 * reserved for backwards compatibility.
1391 info.d_dsflags = DSO_COMPATMBR;
1392 disk_setdiskinfo(&cs->sc_disk, &info);
1394 ccdunlock(cs);
1396 break;
1398 case CCDIOCCLR:
1399 if ((cs->sc_flags & CCDF_INITED) == 0)
1400 return (ENXIO);
1402 if ((ap->a_fflag & FWRITE) == 0)
1403 return (EBADF);
1405 if ((error = ccdlock(cs)) != 0)
1406 return (error);
1408 if (dev_drefs(cs->sc_dev) > 1) {
1409 ccdunlock(cs);
1410 return (EBUSY);
1414 * Free ccd_softc information and clear entry.
1417 /* Close the components and free their pathnames. */
1418 for (i = 0; i < cs->sc_nccdisks; ++i) {
1420 * XXX: this close could potentially fail and
1421 * cause Bad Things. Maybe we need to force
1422 * the close to happen?
1424 #ifdef DEBUG
1425 if (ccddebug & CCDB_VNODE)
1426 vprint("CCDIOCCLR: vnode info",
1427 cs->sc_cinfo[i].ci_vp);
1428 #endif
1429 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE);
1430 kfree(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1433 /* Free interleave index. */
1434 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1435 kfree(cs->sc_itable[i].ii_index, M_DEVBUF);
1437 /* Free component info and interleave table. */
1438 kfree(cs->sc_cinfo, M_DEVBUF);
1439 kfree(cs->sc_itable, M_DEVBUF);
1440 cs->sc_cinfo = NULL;
1441 cs->sc_itable = NULL;
1442 cs->sc_flags &= ~CCDF_INITED;
1445 * Free ccddevice information and clear entry.
1447 kfree(ccddevs[unit].ccd_cpp, M_DEVBUF);
1448 kfree(ccddevs[unit].ccd_vpp, M_DEVBUF);
1449 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1452 * And remove the devstat entry.
1454 devstat_remove_entry(&cs->device_stats);
1456 /* This must be atomic. */
1457 crit_enter();
1458 ccdunlock(cs);
1459 crit_exit();
1461 break;
1463 default:
1464 return (ENOTTY);
1467 return (0);
1470 static int
1471 ccddump(struct dev_dump_args *ap)
1473 /* Not implemented. */
1474 return ENXIO;
1478 * Lookup the provided name in the filesystem. If the file exists,
1479 * is a valid block device, and isn't being used by anyone else,
1480 * set *vpp to the file's vnode.
1482 static int
1483 ccdlookup(char *path, struct vnode **vpp)
1485 struct nlookupdata nd;
1486 struct vnode *vp;
1487 int error;
1489 *vpp = NULL;
1491 error = nlookup_init(&nd, path, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
1492 if (error)
1493 return (error);
1494 if ((error = vn_open(&nd, NULL, FREAD|FWRITE, 0)) != 0) {
1495 #ifdef DEBUG
1496 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1497 kprintf("ccdlookup: vn_open error = %d\n", error);
1498 #endif
1499 goto done;
1501 vp = nd.nl_open_vp;
1503 if (vp->v_opencount > 1) {
1504 error = EBUSY;
1505 goto done;
1508 if (!vn_isdisk(vp, &error))
1509 goto done;
1511 #ifdef DEBUG
1512 if (ccddebug & CCDB_VNODE)
1513 vprint("ccdlookup: vnode info", vp);
1514 #endif
1516 vn_unlock(vp);
1517 nd.nl_open_vp = NULL;
1518 nlookup_done(&nd);
1519 *vpp = vp; /* leave ref intact */
1520 return (0);
1521 done:
1522 nlookup_done(&nd);
1523 return (error);
1527 * Wait interruptibly for an exclusive lock.
1529 * XXX
1530 * Several drivers do this; it should be abstracted and made MP-safe.
1532 static int
1533 ccdlock(struct ccd_softc *cs)
1535 int error;
1537 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1538 cs->sc_flags |= CCDF_WANTED;
1539 if ((error = tsleep(cs, PCATCH, "ccdlck", 0)) != 0)
1540 return (error);
1542 cs->sc_flags |= CCDF_LOCKED;
1543 return (0);
1547 * Unlock and wake up any waiters.
1549 static void
1550 ccdunlock(struct ccd_softc *cs)
1553 cs->sc_flags &= ~CCDF_LOCKED;
1554 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1555 cs->sc_flags &= ~CCDF_WANTED;
1556 wakeup(cs);
1560 #ifdef DEBUG
1561 static void
1562 printiinfo(struct ccdiinfo *ii)
1564 int ix, i;
1566 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1567 kprintf(" itab[%d]: #dk %d sblk %d soff %d",
1568 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1569 for (i = 0; i < ii->ii_ndisk; i++)
1570 kprintf(" %d", ii->ii_index[i]);
1571 kprintf("\n");
1574 #endif
1577 /* Local Variables: */
1578 /* c-argdecl-indent: 8 */
1579 /* c-continued-statement-offset: 8 */
1580 /* c-indent-level: 8 */
1581 /* End: */