1 /* $FreeBSD: src/sys/dev/ccd/ccd.c,v 1.73.2.1 2001/09/11 09:49:52 kris Exp $ */
2 /* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.29 2006/05/04 08:00:59 y0netan1 Exp $ */
4 /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */
7 * Copyright (c) 1995 Jason R. Thorpe.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed for the NetBSD Project
22 * 4. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * Copyright (c) 1988 University of Utah.
40 * Copyright (c) 1990, 1993
41 * The Regents of the University of California. All rights reserved.
43 * This code is derived from software contributed to Berkeley by
44 * the Systems Programming Group of the University of Utah Computer
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. All advertising materials mentioning features or use of this software
56 * must display the following acknowledgement:
57 * This product includes software developed by the University of
58 * California, Berkeley and its contributors.
59 * 4. Neither the name of the University nor the names of its contributors
60 * may be used to endorse or promote products derived from this software
61 * without specific prior written permission.
63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75 * from: Utah $Hdr: cd.c 1.6 90/11/28$
77 * @(#)cd.c 8.2 (Berkeley) 11/16/93
81 * "Concatenated" disk driver.
83 * Dynamic configuration and disklabel support by:
84 * Jason R. Thorpe <thorpej@nas.nasa.gov>
85 * Numerical Aerodynamic Simulation Facility
87 * NASA Ames Research Center
88 * Moffett Field, CA 94035
93 #include <sys/param.h>
94 #include <sys/systm.h>
95 #include <sys/kernel.h>
96 #include <sys/module.h>
99 #include <sys/malloc.h>
100 #include <sys/nlookup.h>
101 #include <sys/conf.h>
102 #include <sys/stat.h>
103 #include <sys/sysctl.h>
104 #include <sys/disklabel.h>
105 #include <sys/devicestat.h>
106 #include <sys/fcntl.h>
107 #include <sys/vnode.h>
108 #include <sys/buf2.h>
109 #include <sys/ccdvar.h>
111 #include <vm/vm_zone.h>
113 #include <vfs/ufs/dinode.h> /* XXX Used only for fs.h */
114 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE and SBSIZE */
116 #include <sys/thread2.h>
118 #if defined(CCDDEBUG) && !defined(DEBUG)
123 #define CCDB_FOLLOW 0x01
124 #define CCDB_INIT 0x02
126 #define CCDB_LABEL 0x08
127 #define CCDB_VNODE 0x10
128 static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
130 SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
134 #define ccdunit(x) dkunit(x)
135 #define ccdpart(x) dkpart(x)
138 This is how mirroring works (only writes are special):
140 When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
141 linked together by the cb_mirror field. "cb_pflags &
142 CCDPF_MIRROR_DONE" is set to 0 on both of them.
144 When a component returns to ccdiodone(), it checks if "cb_pflags &
145 CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's
146 flag and returns. If it is, it means its partner has already
147 returned, so it will go to the regular cleanup.
152 struct buf cb_buf; /* new I/O buf */
153 struct vnode *cb_vp; /* related vnode */
154 struct bio *cb_obio; /* ptr. to original I/O buf */
155 struct ccdbuf *cb_freenext; /* free list link */
156 int cb_unit; /* target unit */
157 int cb_comp; /* target component */
158 int cb_pflags; /* mirror/parity status flag */
159 struct ccdbuf *cb_mirror; /* mirror counterpart */
162 /* bits in cb_pflags */
163 #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */
165 #define CCDLABELDEV(dev) \
166 (make_sub_dev(dev, dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
168 static d_open_t ccdopen;
169 static d_close_t ccdclose;
170 static d_strategy_t ccdstrategy;
171 static d_ioctl_t ccdioctl;
172 static d_dump_t ccddump;
173 static d_psize_t ccdsize;
175 #define NCCDFREEHIWAT 16
177 #define CDEV_MAJOR 74
179 static struct cdevsw ccd_cdevsw = {
181 /* maj */ CDEV_MAJOR,
187 /* close */ ccdclose,
189 /* write */ physwrite,
190 /* ioctl */ ccdioctl,
193 /* strategy */ ccdstrategy,
198 /* called during module initialization */
199 static void ccdattach (void);
200 static int ccd_modevent (module_t, int, void *);
202 /* called by biodone() at interrupt time */
203 static void ccdiodone (struct bio *bio);
205 static void ccdstart (struct ccd_softc *, struct bio *);
206 static void ccdinterleave (struct ccd_softc *, int);
207 static void ccdintr (struct ccd_softc *, struct bio *);
208 static int ccdinit (struct ccddevice *, char **, struct thread *);
209 static int ccdlookup (char *, struct thread *td, struct vnode **);
210 static void ccdbuffer (struct ccdbuf **ret, struct ccd_softc *,
211 struct bio *, off_t, caddr_t, long);
212 static void ccdgetdisklabel (dev_t);
213 static void ccdmakedisklabel (struct ccd_softc *);
214 static int ccdlock (struct ccd_softc *);
215 static void ccdunlock (struct ccd_softc *);
218 static void printiinfo (struct ccdiinfo *);
221 /* Non-private for the benefit of libkvm. */
222 struct ccd_softc *ccd_softc;
223 struct ccddevice *ccddevs;
224 struct ccdbuf *ccdfreebufs;
225 static int numccdfreebufs;
226 static int numccd = 0;
229 * getccdbuf() - Allocate and zero a ccd buffer.
231 * This routine is called at splbio().
241 * Allocate from freelist or malloc as necessary
243 if ((cbp = ccdfreebufs) != NULL) {
244 ccdfreebufs = cbp->cb_freenext;
246 reinitbufbio(&cbp->cb_buf);
248 cbp = malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK|M_ZERO);
249 initbufbio(&cbp->cb_buf);
253 * independant struct buf initialization
255 LIST_INIT(&cbp->cb_buf.b_dep);
256 BUF_LOCKINIT(&cbp->cb_buf);
257 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
258 BUF_KERNPROC(&cbp->cb_buf);
264 * putccdbuf() - Free a ccd buffer.
266 * This routine is called at splbio().
271 putccdbuf(struct ccdbuf *cbp)
273 BUF_UNLOCK(&cbp->cb_buf);
274 BUF_LOCKFREE(&cbp->cb_buf);
276 if (numccdfreebufs < NCCDFREEHIWAT) {
277 cbp->cb_freenext = ccdfreebufs;
281 free((caddr_t)cbp, M_DEVBUF);
287 * Number of blocks to untouched in front of a component partition.
288 * This is to avoid violating its disklabel area when it starts at the
289 * beginning of the slice.
291 #if !defined(CCD_OFFSET)
292 #define CCD_OFFSET 16
296 * Called by main() during pseudo-device attachment. All we need
297 * to do is allocate enough space for devices to be configured later, and
307 printf("ccd0-%d: Concatenated disk drivers\n", num-1);
309 printf("ccd0: Concatenated disk driver\n");
311 ccd_softc = malloc(num * sizeof(struct ccd_softc), M_DEVBUF,
313 ccddevs = malloc(num * sizeof(struct ccddevice), M_DEVBUF,
317 cdevsw_add(&ccd_cdevsw, 0, 0);
318 /* XXX: is this necessary? */
319 for (i = 0; i < numccd; ++i)
320 ccddevs[i].ccd_dk = -1;
324 ccd_modevent(module_t mod, int type, void *data)
334 printf("ccd0: Unload not supported!\n");
338 default: /* MOD_SHUTDOWN etc */
344 DEV_MODULE(ccd, ccd_modevent, NULL);
347 ccdinit(struct ccddevice *ccd, char **cpaths, struct thread *td)
349 struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
350 struct ccdcinfo *ci = NULL; /* XXX */
356 struct partinfo dpart;
357 struct ccdgeom *ccg = &cs->sc_geom;
358 char tmppath[MAXPATHLEN];
362 KKASSERT(td->td_proc);
363 cred = td->td_proc->p_ucred;
366 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
367 printf("ccdinit: unit %d\n", ccd->ccd_unit);
371 cs->sc_ileave = ccd->ccd_interleave;
372 cs->sc_nccdisks = ccd->ccd_ndev;
374 /* Allocate space for the component info. */
375 cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
379 * Verify that each component piece exists and record
380 * relevant information about it.
384 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
385 vp = ccd->ccd_vpp[ix];
386 ci = &cs->sc_cinfo[ix];
390 * Copy in the pathname of the component.
392 bzero(tmppath, sizeof(tmppath)); /* sanity */
393 if ((error = copyinstr(cpaths[ix], tmppath,
394 MAXPATHLEN, &ci->ci_pathlen)) != 0) {
396 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
397 printf("ccd%d: can't copy path, error = %d\n",
398 ccd->ccd_unit, error);
402 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
403 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
405 ci->ci_dev = vn_todev(vp);
408 * Get partition information for the component.
410 if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
411 FREAD, cred, td)) != 0) {
413 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
414 printf("ccd%d: %s: ioctl failed, error = %d\n",
415 ccd->ccd_unit, ci->ci_path, error);
419 if (dpart.part->p_fstype == FS_BSDFFS) {
421 ((dpart.disklab->d_secsize > maxsecsize) ?
422 dpart.disklab->d_secsize : maxsecsize);
423 size = dpart.part->p_size - CCD_OFFSET;
426 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
427 printf("ccd%d: %s: incorrect partition type\n",
428 ccd->ccd_unit, ci->ci_path);
435 * Calculate the size, truncating to an interleave
436 * boundary if necessary.
439 if (cs->sc_ileave > 1)
440 size -= size % cs->sc_ileave;
444 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
445 printf("ccd%d: %s: size == 0\n",
446 ccd->ccd_unit, ci->ci_path);
452 if (minsize == 0 || size < minsize)
459 * Don't allow the interleave to be smaller than
460 * the biggest component sector.
462 if ((cs->sc_ileave > 0) &&
463 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
465 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
466 printf("ccd%d: interleave must be at least %d\n",
467 ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
474 * If uniform interleave is desired set all sizes to that of
475 * the smallest component. This will guarentee that a single
476 * interleave table is generated.
478 * Lost space must be taken into account when calculating the
479 * overall size. Half the space is lost when CCDF_MIRROR is
480 * specified. One disk is lost when CCDF_PARITY is specified.
482 if (ccd->ccd_flags & CCDF_UNIFORM) {
483 for (ci = cs->sc_cinfo;
484 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
485 ci->ci_size = minsize;
487 if (ccd->ccd_flags & CCDF_MIRROR) {
489 * Check to see if an even number of components
490 * have been specified. The interleave must also
491 * be non-zero in order for us to be able to
492 * guarentee the topology.
494 if (cs->sc_nccdisks % 2) {
495 printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
499 if (cs->sc_ileave == 0) {
500 printf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
504 cs->sc_size = (cs->sc_nccdisks/2) * minsize;
505 } else if (ccd->ccd_flags & CCDF_PARITY) {
506 cs->sc_size = (cs->sc_nccdisks-1) * minsize;
508 if (cs->sc_ileave == 0) {
509 printf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
513 cs->sc_size = cs->sc_nccdisks * minsize;
518 * Construct the interleave table.
520 ccdinterleave(cs, ccd->ccd_unit);
523 * Create pseudo-geometry based on 1MB cylinders. It's
526 ccg->ccg_secsize = maxsecsize;
527 ccg->ccg_ntracks = 1;
528 ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
529 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
532 * Add an devstat entry for this device.
534 devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
535 ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
536 DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
537 DEVSTAT_PRIORITY_ARRAY);
539 cs->sc_flags |= CCDF_INITED;
540 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
541 cs->sc_unit = ccd->ccd_unit;
544 while (ci > cs->sc_cinfo) {
546 free(ci->ci_path, M_DEVBUF);
548 free(cs->sc_cinfo, M_DEVBUF);
553 ccdinterleave(struct ccd_softc *cs, int unit)
555 struct ccdcinfo *ci, *smallci;
562 if (ccddebug & CCDB_INIT)
563 printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
567 * Allocate an interleave table. The worst case occurs when each
568 * of N disks is of a different size, resulting in N interleave
571 * Chances are this is too big, but we don't care.
573 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
574 cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
575 bzero((caddr_t)cs->sc_itable, size);
578 * Trivial case: no interleave (actually interleave of disk size).
579 * Each table entry represents a single component in its entirety.
581 * An interleave of 0 may not be used with a mirror or parity setup.
583 if (cs->sc_ileave == 0) {
587 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
588 /* Allocate space for ii_index. */
589 ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
591 ii->ii_startblk = bn;
593 ii->ii_index[0] = ix;
594 bn += cs->sc_cinfo[ix].ci_size;
599 if (ccddebug & CCDB_INIT)
600 printiinfo(cs->sc_itable);
606 * The following isn't fast or pretty; it doesn't have to be.
610 for (ii = cs->sc_itable; ; ii++) {
612 * Allocate space for ii_index. We might allocate more then
615 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
619 * Locate the smallest of the remaining components
622 for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks];
624 if (ci->ci_size > size &&
626 ci->ci_size < smallci->ci_size)) {
632 * Nobody left, all done
634 if (smallci == NULL) {
640 * Record starting logical block using an sc_ileave blocksize.
642 ii->ii_startblk = bn / cs->sc_ileave;
645 * Record starting comopnent block using an sc_ileave
646 * blocksize. This value is relative to the beginning of
649 ii->ii_startoff = lbn;
652 * Determine how many disks take part in this interleave
653 * and record their indices.
656 for (ci = cs->sc_cinfo;
657 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
658 if (ci->ci_size >= smallci->ci_size) {
659 ii->ii_index[ix++] = ci - cs->sc_cinfo;
663 bn += ix * (smallci->ci_size - size);
664 lbn = smallci->ci_size / cs->sc_ileave;
665 size = smallci->ci_size;
668 if (ccddebug & CCDB_INIT)
669 printiinfo(cs->sc_itable);
675 ccdopen(dev_t dev, int flags, int fmt, d_thread_t *td)
677 int unit = ccdunit(dev);
678 struct ccd_softc *cs;
679 struct disklabel *lp;
680 int error = 0, part, pmask;
683 if (ccddebug & CCDB_FOLLOW)
684 printf("ccdopen(%x, %x)\n", dev, flags);
688 cs = &ccd_softc[unit];
690 if ((error = ccdlock(cs)) != 0)
699 * If we're initialized, check to see if there are any other
700 * open partitions. If not, then it's safe to update
701 * the in-core disklabel.
703 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
704 ccdgetdisklabel(dev);
706 /* Check that the partition exists. */
707 if (part != RAW_PART && ((part >= lp->d_npartitions) ||
708 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
713 cs->sc_openmask |= pmask;
721 ccdclose(dev_t dev, int flags, int fmt, d_thread_t *td)
723 int unit = ccdunit(dev);
724 struct ccd_softc *cs;
728 if (ccddebug & CCDB_FOLLOW)
729 printf("ccdclose(%x, %x)\n", dev, flags);
734 cs = &ccd_softc[unit];
736 if ((error = ccdlock(cs)) != 0)
741 /* ...that much closer to allowing unconfiguration... */
742 cs->sc_openmask &= ~(1 << part);
748 ccdstrategy(dev_t dev, struct bio *bio)
750 int unit = ccdunit(dev);
752 struct buf *bp = bio->bio_buf;
753 struct ccd_softc *cs = &ccd_softc[unit];
755 struct disklabel *lp;
758 if (ccddebug & CCDB_FOLLOW)
759 printf("ccdstrategy(%x): unit %d\n", bp, unit);
761 if ((cs->sc_flags & CCDF_INITED) == 0) {
763 bp->b_flags |= B_ERROR;
767 /* If it's a nil transfer, wake up the top half now. */
768 if (bp->b_bcount == 0)
774 * Do bounds checking and adjust transfer. If there's an
775 * error, the bounds check will flag that for us.
777 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
778 if (ccdpart(dev) != RAW_PART) {
779 nbio = bounds_check_with_label(dev, bio, lp, wlabel);
783 int pbn; /* in sc_secsize chunks */
784 long sz; /* in sc_secsize chunks */
786 pbn = (int)(bio->bio_offset / cs->sc_geom.ccg_secsize);
787 sz = howmany(bp->b_bcount, cs->sc_geom.ccg_secsize);
790 * If out of bounds return an error. If at the EOF point,
791 * simply read or write less.
794 if (pbn < 0 || pbn >= cs->sc_size) {
795 bp->b_resid = bp->b_bcount;
796 if (pbn != cs->sc_size) {
797 bp->b_error = EINVAL;
798 bp->b_flags |= B_ERROR | B_INVAL;
804 * If the request crosses EOF, truncate the request.
806 if (pbn + sz > cs->sc_size) {
807 bp->b_bcount = (cs->sc_size - pbn) *
808 cs->sc_geom.ccg_secsize;
813 bp->b_resid = bp->b_bcount;
814 nbio->bio_driver_info = dev;
825 * note: bio, not nbio, is valid at the done label.
832 ccdstart(struct ccd_softc *cs, struct bio *bio)
835 struct ccdbuf *cbp[4];
836 struct buf *bp = bio->bio_buf;
837 dev_t dev = bio->bio_driver_info;
838 /* XXX! : 2 reads and 2 writes for RAID 4/5 */
841 struct partition *pp;
844 if (ccddebug & CCDB_FOLLOW)
845 printf("ccdstart(%x, %x)\n", cs, bp);
848 /* Record the transaction start */
849 devstat_start_transaction(&cs->device_stats);
852 * Translate the partition-relative block number to an absolute.
854 doffset = bio->bio_offset;
855 if (ccdpart(dev) != RAW_PART) {
856 pp = &cs->sc_label.d_partitions[ccdpart(dev)];
857 doffset += pp->p_offset * cs->sc_label.d_secsize;
861 * Allocate component buffers and fire off the requests
864 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
865 ccdbuffer(cbp, cs, bio, doffset, addr, bcount);
866 rcount = cbp[0]->cb_buf.b_bcount;
868 if (cs->sc_cflags & CCDF_MIRROR) {
870 * Mirroring. Writes go to both disks, reads are
871 * taken from whichever disk seems most appropriate.
873 * We attempt to localize reads to the disk whos arm
874 * is nearest the read request. We ignore seeks due
875 * to writes when making this determination and we
876 * also try to avoid hogging.
878 if (cbp[0]->cb_buf.b_cmd != BUF_CMD_READ) {
879 vn_strategy(cbp[0]->cb_vp,
880 &cbp[0]->cb_buf.b_bio1);
881 vn_strategy(cbp[1]->cb_vp,
882 &cbp[1]->cb_buf.b_bio1);
884 int pick = cs->sc_pick;
885 daddr_t range = cs->sc_size / 16 * cs->sc_label.d_secsize;
887 if (doffset < cs->sc_blk[pick] - range ||
888 doffset > cs->sc_blk[pick] + range
890 cs->sc_pick = pick = 1 - pick;
892 cs->sc_blk[pick] = doffset + rcount;
893 vn_strategy(cbp[pick]->cb_vp,
894 &cbp[pick]->cb_buf.b_bio1);
900 vn_strategy(cbp[0]->cb_vp,
901 &cbp[0]->cb_buf.b_bio1);
909 * Build a component buffer header.
912 ccdbuffer(struct ccdbuf **cb, struct ccd_softc *cs, struct bio *bio,
913 off_t doffset, caddr_t addr, long bcount)
915 struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
917 daddr_t bn, cbn, cboff;
921 if (ccddebug & CCDB_IO)
922 printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
923 cs, bp, bn, addr, bcount);
926 * Determine which component bn falls in.
928 bn = (daddr_t)(doffset / cs->sc_geom.ccg_secsize);
932 if (cs->sc_ileave == 0) {
934 * Serially concatenated and neither a mirror nor a parity
935 * config. This is a special case.
940 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
948 * Calculate cbn, the logical superblock (sc_ileave chunks),
949 * and cboff, a normal block offset (DEV_BSIZE chunks) relative
952 cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */
953 cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */
956 * Figure out which interleave table to use.
958 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
959 if (ii->ii_startblk > cbn)
965 * off is the logical superblock relative to the beginning
966 * of this interleave block.
968 off = cbn - ii->ii_startblk;
971 * We must calculate which disk component to use (ccdisk),
972 * and recalculate cbn to be the superblock relative to
973 * the beginning of the component. This is typically done by
974 * adding 'off' and ii->ii_startoff together. However, 'off'
975 * must typically be divided by the number of components in
976 * this interleave array to be properly convert it from a
977 * CCD-relative logical superblock number to a
978 * component-relative superblock number.
980 if (ii->ii_ndisk == 1) {
982 * When we have just one disk, it can't be a mirror
983 * or a parity config.
985 ccdisk = ii->ii_index[0];
986 cbn = ii->ii_startoff + off;
988 if (cs->sc_cflags & CCDF_MIRROR) {
990 * We have forced a uniform mapping, resulting
991 * in a single interleave array. We double
992 * up on the first half of the available
993 * components and our mirror is in the second
994 * half. This only works with a single
995 * interleave array because doubling up
996 * doubles the number of sectors, so there
997 * cannot be another interleave array because
998 * the next interleave array's calculations
1001 int ndisk2 = ii->ii_ndisk / 2;
1002 ccdisk = ii->ii_index[off % ndisk2];
1003 cbn = ii->ii_startoff + off / ndisk2;
1004 ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
1005 } else if (cs->sc_cflags & CCDF_PARITY) {
1007 * XXX not implemented yet
1009 int ndisk2 = ii->ii_ndisk - 1;
1010 ccdisk = ii->ii_index[off % ndisk2];
1011 cbn = ii->ii_startoff + off / ndisk2;
1012 if (cbn % ii->ii_ndisk <= ccdisk)
1015 ccdisk = ii->ii_index[off % ii->ii_ndisk];
1016 cbn = ii->ii_startoff + off / ii->ii_ndisk;
1020 ci = &cs->sc_cinfo[ccdisk];
1023 * Convert cbn from a superblock to a normal block so it
1024 * can be used to calculate (along with cboff) the normal
1025 * block index into this particular disk.
1027 cbn *= cs->sc_ileave;
1031 * Fill in the component buf structure.
1033 * NOTE: devices do not use b_bufsize, only b_bcount, but b_bcount
1034 * will be truncated on device EOF so we use b_bufsize to detect
1038 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1039 cbp->cb_buf.b_flags = bio->bio_buf->b_flags | B_PAGING;
1040 cbp->cb_buf.b_data = addr;
1041 cbp->cb_vp = ci->ci_vp;
1042 if (cs->sc_ileave == 0)
1043 cbc = dbtob((off_t)(ci->ci_size - cbn));
1045 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1046 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1047 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1049 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1050 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1051 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
1054 * context for ccdiodone
1057 cbp->cb_unit = cs - ccd_softc;
1058 cbp->cb_comp = ci - cs->sc_cinfo;
1061 if (ccddebug & CCDB_IO)
1062 printf(" dev %x(u%d): cbp %x off %lld addr %x bcnt %d\n",
1063 ci->ci_dev, ci-cs->sc_cinfo, cbp,
1064 cbp->cb_buf.b_bio1.bio_offset,
1065 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1070 * Note: both I/O's setup when reading from mirror, but only one
1073 if (cs->sc_cflags & CCDF_MIRROR) {
1074 /* mirror, setup second I/O */
1077 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1078 cbp->cb_buf.b_flags = bio->bio_buf->b_flags | B_PAGING;
1079 cbp->cb_buf.b_data = addr;
1080 cbp->cb_vp = ci2->ci_vp;
1081 if (cs->sc_ileave == 0)
1082 cbc = dbtob((off_t)(ci->ci_size - cbn));
1084 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1085 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1086 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1088 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1089 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1090 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
1093 * context for ccdiodone
1096 cbp->cb_unit = cs - ccd_softc;
1097 cbp->cb_comp = ci2 - cs->sc_cinfo;
1099 /* link together the ccdbuf's and clear "mirror done" flag */
1100 cb[0]->cb_mirror = cb[1];
1101 cb[1]->cb_mirror = cb[0];
1102 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1103 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1108 ccdintr(struct ccd_softc *cs, struct bio *bio)
1110 struct buf *bp = bio->bio_buf;
1113 if (ccddebug & CCDB_FOLLOW)
1114 printf("ccdintr(%x, %x)\n", cs, bp);
1117 * Request is done for better or worse, wakeup the top half.
1119 if (bp->b_flags & B_ERROR)
1120 bp->b_resid = bp->b_bcount;
1121 devstat_end_transaction_buf(&cs->device_stats, bp);
1126 * Called at interrupt time.
1127 * Mark the component as done and if all components are done,
1128 * take a ccd interrupt.
1131 ccdiodone(struct bio *bio)
1133 struct ccdbuf *cbp = bio->bio_caller_info1.ptr;
1134 struct bio *obio = cbp->cb_obio;
1135 struct buf *obp = obio->bio_buf;
1136 int unit = cbp->cb_unit;
1140 * Since we do not have exclusive access to underlying devices,
1141 * we can't keep cache translations around.
1143 clearbiocache(bio->bio_next);
1147 if (ccddebug & CCDB_FOLLOW)
1148 printf("ccdiodone(%x)\n", cbp);
1149 if (ccddebug & CCDB_IO) {
1150 printf("ccdiodone: bp %x bcount %d resid %d\n",
1151 obp, obp->b_bcount, obp->b_resid);
1152 printf(" dev %x(u%d), cbp %x off %lld addr %x bcnt %d\n",
1153 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1154 cbp->cb_buf.b_loffset, cbp->cb_buf.b_data,
1155 cbp->cb_buf.b_bcount);
1159 * An early EOF is considered an error
1161 if (cbp->cb_buf.b_bcount != cbp->cb_buf.b_bufsize) {
1162 if ((cbp->cb_buf.b_flags & B_ERROR) == 0) {
1163 cbp->cb_buf.b_flags |= B_ERROR;
1164 cbp->cb_buf.b_error = EIO;
1169 * If an error occured, report it. If this is a mirrored
1170 * configuration and the first of two possible reads, do not
1171 * set the error in the bp yet because the second read may
1174 if (cbp->cb_buf.b_flags & B_ERROR) {
1175 const char *msg = "";
1177 if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
1178 (cbp->cb_buf.b_cmd == BUF_CMD_READ) &&
1179 (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1181 * We will try our read on the other disk down
1182 * below, also reverse the default pick so if we
1183 * are doing a scan we do not keep hitting the
1186 struct ccd_softc *cs = &ccd_softc[unit];
1188 msg = ", trying other disk";
1189 cs->sc_pick = 1 - cs->sc_pick;
1190 cs->sc_blk[cs->sc_pick] = obio->bio_offset;
1192 obp->b_flags |= B_ERROR;
1193 obp->b_error = cbp->cb_buf.b_error ?
1194 cbp->cb_buf.b_error : EIO;
1196 printf("ccd%d: error %d on component %d offset %lld (ccd offset %lld)%s\n",
1197 unit, obp->b_error, cbp->cb_comp,
1198 cbp->cb_buf.b_bio2.bio_offset,
1199 obio->bio_offset, msg);
1203 * Process mirror. If we are writing, I/O has been initiated on both
1204 * buffers and we fall through only after both are finished.
1206 * If we are reading only one I/O is initiated at a time. If an
1207 * error occurs we initiate the second I/O and return, otherwise
1208 * we free the second I/O without initiating it.
1211 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
1212 if (cbp->cb_buf.b_cmd != BUF_CMD_READ) {
1214 * When writing, handshake with the second buffer
1215 * to determine when both are done. If both are not
1216 * done, return here.
1218 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1219 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1226 * When reading, either dispose of the second buffer
1227 * or initiate I/O on the second buffer if an error
1228 * occured with this one.
1230 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1231 if (cbp->cb_buf.b_flags & B_ERROR) {
1232 cbp->cb_mirror->cb_pflags |=
1235 cbp->cb_mirror->cb_vp,
1236 &cbp->cb_mirror->cb_buf.b_bio1
1242 putccdbuf(cbp->cb_mirror);
1250 * Use our saved b_bufsize to determine if an unexpected EOF occured.
1252 count = cbp->cb_buf.b_bufsize;
1256 * If all done, "interrupt".
1258 obp->b_resid -= count;
1259 if (obp->b_resid < 0)
1260 panic("ccdiodone: count");
1261 if (obp->b_resid == 0)
1262 ccdintr(&ccd_softc[unit], obio);
1267 ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td)
1269 int unit = ccdunit(dev);
1270 int i, j, lookedup = 0, error = 0;
1272 struct ccd_softc *cs;
1273 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1274 struct ccddevice ccd;
1279 KKASSERT(td->td_proc != NULL);
1280 cred = td->td_proc->p_ucred;
1284 cs = &ccd_softc[unit];
1286 bzero(&ccd, sizeof(ccd));
1290 if (cs->sc_flags & CCDF_INITED)
1293 if ((flag & FWRITE) == 0)
1296 if ((error = ccdlock(cs)) != 0)
1299 if (ccio->ccio_ndisks > CCD_MAXNDISKS)
1302 /* Fill in some important bits. */
1303 ccd.ccd_unit = unit;
1304 ccd.ccd_interleave = ccio->ccio_ileave;
1305 if (ccd.ccd_interleave == 0 &&
1306 ((ccio->ccio_flags & CCDF_MIRROR) ||
1307 (ccio->ccio_flags & CCDF_PARITY))) {
1308 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1309 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1311 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1312 (ccio->ccio_flags & CCDF_PARITY)) {
1313 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1314 ccio->ccio_flags &= ~CCDF_PARITY;
1316 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1317 !(ccio->ccio_flags & CCDF_UNIFORM)) {
1318 printf("ccd%d: mirror/parity forces uniform flag\n",
1320 ccio->ccio_flags |= CCDF_UNIFORM;
1322 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1325 * Allocate space for and copy in the array of
1326 * componet pathnames and device numbers.
1328 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1329 M_DEVBUF, M_WAITOK);
1330 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1331 M_DEVBUF, M_WAITOK);
1333 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1334 ccio->ccio_ndisks * sizeof(char **));
1336 free(vpp, M_DEVBUF);
1337 free(cpp, M_DEVBUF);
1343 if (ccddebug & CCDB_INIT)
1344 for (i = 0; i < ccio->ccio_ndisks; ++i)
1345 printf("ccdioctl: component %d: 0x%x\n",
1349 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1351 if (ccddebug & CCDB_INIT)
1352 printf("ccdioctl: lookedup = %d\n", lookedup);
1354 if ((error = ccdlookup(cpp[i], td, &vpp[i])) != 0) {
1355 for (j = 0; j < lookedup; ++j)
1356 (void)vn_close(vpp[j], FREAD|FWRITE, td);
1357 free(vpp, M_DEVBUF);
1358 free(cpp, M_DEVBUF);
1366 ccd.ccd_ndev = ccio->ccio_ndisks;
1369 * Initialize the ccd. Fills in the softc for us.
1371 if ((error = ccdinit(&ccd, cpp, td)) != 0) {
1372 for (j = 0; j < lookedup; ++j)
1373 (void)vn_close(vpp[j], FREAD|FWRITE, td);
1374 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1375 free(vpp, M_DEVBUF);
1376 free(cpp, M_DEVBUF);
1382 * The ccd has been successfully initialized, so
1383 * we can place it into the array and read the disklabel.
1385 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1386 ccio->ccio_unit = unit;
1387 ccio->ccio_size = cs->sc_size;
1388 ccdgetdisklabel(dev);
1395 if ((cs->sc_flags & CCDF_INITED) == 0)
1398 if ((flag & FWRITE) == 0)
1401 if ((error = ccdlock(cs)) != 0)
1404 /* Don't unconfigure if any other partitions are open */
1405 part = ccdpart(dev);
1406 pmask = (1 << part);
1407 if ((cs->sc_openmask & ~pmask)) {
1413 * Free ccd_softc information and clear entry.
1416 /* Close the components and free their pathnames. */
1417 for (i = 0; i < cs->sc_nccdisks; ++i) {
1419 * XXX: this close could potentially fail and
1420 * cause Bad Things. Maybe we need to force
1421 * the close to happen?
1424 if (ccddebug & CCDB_VNODE)
1425 vprint("CCDIOCCLR: vnode info",
1426 cs->sc_cinfo[i].ci_vp);
1428 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, td);
1429 free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1432 /* Free interleave index. */
1433 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1434 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1436 /* Free component info and interleave table. */
1437 free(cs->sc_cinfo, M_DEVBUF);
1438 free(cs->sc_itable, M_DEVBUF);
1439 cs->sc_flags &= ~CCDF_INITED;
1442 * Free ccddevice information and clear entry.
1444 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1445 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1447 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1450 * And remove the devstat entry.
1452 devstat_remove_entry(&cs->device_stats);
1454 /* This must be atomic. */
1457 bzero(cs, sizeof(struct ccd_softc));
1463 if ((cs->sc_flags & CCDF_INITED) == 0)
1466 *(struct disklabel *)data = cs->sc_label;
1470 if ((cs->sc_flags & CCDF_INITED) == 0)
1473 ((struct partinfo *)data)->disklab = &cs->sc_label;
1474 ((struct partinfo *)data)->part =
1475 &cs->sc_label.d_partitions[ccdpart(dev)];
1480 if ((cs->sc_flags & CCDF_INITED) == 0)
1483 if ((flag & FWRITE) == 0)
1486 if ((error = ccdlock(cs)) != 0)
1489 cs->sc_flags |= CCDF_LABELLING;
1491 error = setdisklabel(&cs->sc_label,
1492 (struct disklabel *)data, 0);
1494 if (cmd == DIOCWDINFO) {
1495 dev_t cdev = CCDLABELDEV(dev);
1496 error = writedisklabel(cdev, &cs->sc_label);
1500 cs->sc_flags &= ~CCDF_LABELLING;
1509 if ((cs->sc_flags & CCDF_INITED) == 0)
1512 if ((flag & FWRITE) == 0)
1514 if (*(int *)data != 0)
1515 cs->sc_flags |= CCDF_WLABEL;
1517 cs->sc_flags &= ~CCDF_WLABEL;
1530 struct ccd_softc *cs;
1533 if (ccdopen(dev, 0, S_IFCHR, curthread))
1536 cs = &ccd_softc[ccdunit(dev)];
1537 part = ccdpart(dev);
1539 if ((cs->sc_flags & CCDF_INITED) == 0)
1542 if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1545 size = cs->sc_label.d_partitions[part].p_size;
1547 if (ccdclose(dev, 0, S_IFCHR, curthread))
1554 ccddump(dev_t dev, u_int count, u_int blkno, u_int secsize)
1556 /* Not implemented. */
1561 * Lookup the provided name in the filesystem. If the file exists,
1562 * is a valid block device, and isn't being used by anyone else,
1563 * set *vpp to the file's vnode.
1566 ccdlookup(char *path, struct thread *td, struct vnode **vpp)
1568 struct nlookupdata nd;
1573 KKASSERT(td->td_proc);
1574 cred = td->td_proc->p_ucred;
1577 error = nlookup_init(&nd, path, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
1580 if ((error = vn_open(&nd, NULL, FREAD|FWRITE, 0)) != 0) {
1582 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1583 printf("ccdlookup: vn_open error = %d\n", error);
1589 if (vp->v_usecount > 1) {
1594 if (!vn_isdisk(vp, &error))
1598 if (ccddebug & CCDB_VNODE)
1599 vprint("ccdlookup: vnode info", vp);
1602 VOP_UNLOCK(vp, 0, td);
1603 nd.nl_open_vp = NULL;
1605 *vpp = vp; /* leave ref intact */
1613 * Read the disklabel from the ccd. If one is not present, fake one
1617 ccdgetdisklabel(dev_t dev)
1619 int unit = ccdunit(dev);
1620 struct ccd_softc *cs = &ccd_softc[unit];
1622 struct disklabel *lp = &cs->sc_label;
1623 struct ccdgeom *ccg = &cs->sc_geom;
1626 bzero(lp, sizeof(*lp));
1628 lp->d_secperunit = cs->sc_size;
1629 lp->d_secsize = ccg->ccg_secsize;
1630 lp->d_nsectors = ccg->ccg_nsectors;
1631 lp->d_ntracks = ccg->ccg_ntracks;
1632 lp->d_ncylinders = ccg->ccg_ncylinders;
1633 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1635 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1636 lp->d_type = DTYPE_CCD;
1637 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1639 lp->d_interleave = 1;
1642 lp->d_partitions[RAW_PART].p_offset = 0;
1643 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1644 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1645 lp->d_npartitions = RAW_PART + 1;
1647 lp->d_bbsize = BBSIZE; /* XXX */
1648 lp->d_sbsize = SBSIZE; /* XXX */
1650 lp->d_magic = DISKMAGIC;
1651 lp->d_magic2 = DISKMAGIC;
1652 lp->d_checksum = dkcksum(&cs->sc_label);
1655 * Call the generic disklabel extraction routine.
1657 cdev = CCDLABELDEV(dev);
1658 errstring = readdisklabel(cdev, &cs->sc_label);
1659 if (errstring != NULL)
1660 ccdmakedisklabel(cs);
1663 /* It's actually extremely common to have unlabeled ccds. */
1664 if (ccddebug & CCDB_LABEL)
1665 if (errstring != NULL)
1666 printf("ccd%d: %s\n", unit, errstring);
1671 * Take care of things one might want to take care of in the event
1672 * that a disklabel isn't present.
1675 ccdmakedisklabel(struct ccd_softc *cs)
1677 struct disklabel *lp = &cs->sc_label;
1680 * For historical reasons, if there's no disklabel present
1681 * the raw partition must be marked FS_BSDFFS.
1683 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1685 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1689 * Wait interruptibly for an exclusive lock.
1692 * Several drivers do this; it should be abstracted and made MP-safe.
1695 ccdlock(struct ccd_softc *cs)
1699 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1700 cs->sc_flags |= CCDF_WANTED;
1701 if ((error = tsleep(cs, PCATCH, "ccdlck", 0)) != 0)
1704 cs->sc_flags |= CCDF_LOCKED;
1709 * Unlock and wake up any waiters.
1712 ccdunlock(struct ccd_softc *cs)
1715 cs->sc_flags &= ~CCDF_LOCKED;
1716 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1717 cs->sc_flags &= ~CCDF_WANTED;
1724 printiinfo(struct ccdiinfo *ii)
1728 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1729 printf(" itab[%d]: #dk %d sblk %d soff %d",
1730 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1731 for (i = 0; i < ii->ii_ndisk; i++)
1732 printf(" %d", ii->ii_index[i]);
1739 /* Local Variables: */
1740 /* c-argdecl-indent: 8 */
1741 /* c-continued-statement-offset: 8 */
1742 /* c-indent-level: 8 */