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.32 2006/05/06 02:43:02 dillon 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);
259 cbp->cb_buf.b_flags = B_PAGING | B_BNOCLIP;
265 * putccdbuf() - Free a ccd buffer.
267 * This routine is called at splbio().
272 putccdbuf(struct ccdbuf *cbp)
274 BUF_UNLOCK(&cbp->cb_buf);
275 BUF_LOCKFREE(&cbp->cb_buf);
277 if (numccdfreebufs < NCCDFREEHIWAT) {
278 cbp->cb_freenext = ccdfreebufs;
282 free((caddr_t)cbp, M_DEVBUF);
288 * Number of blocks to untouched in front of a component partition.
289 * This is to avoid violating its disklabel area when it starts at the
290 * beginning of the slice.
292 #if !defined(CCD_OFFSET)
293 #define CCD_OFFSET 16
297 * Called by main() during pseudo-device attachment. All we need
298 * to do is allocate enough space for devices to be configured later, and
308 printf("ccd0-%d: Concatenated disk drivers\n", num-1);
310 printf("ccd0: Concatenated disk driver\n");
312 ccd_softc = malloc(num * sizeof(struct ccd_softc), M_DEVBUF,
314 ccddevs = malloc(num * sizeof(struct ccddevice), M_DEVBUF,
318 cdevsw_add(&ccd_cdevsw, 0, 0);
319 /* XXX: is this necessary? */
320 for (i = 0; i < numccd; ++i)
321 ccddevs[i].ccd_dk = -1;
325 ccd_modevent(module_t mod, int type, void *data)
335 printf("ccd0: Unload not supported!\n");
339 default: /* MOD_SHUTDOWN etc */
345 DEV_MODULE(ccd, ccd_modevent, NULL);
348 ccdinit(struct ccddevice *ccd, char **cpaths, struct thread *td)
350 struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
351 struct ccdcinfo *ci = NULL; /* XXX */
357 struct partinfo dpart;
358 struct ccdgeom *ccg = &cs->sc_geom;
359 char tmppath[MAXPATHLEN];
363 KKASSERT(td->td_proc);
364 cred = td->td_proc->p_ucred;
367 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
368 printf("ccdinit: unit %d\n", ccd->ccd_unit);
372 cs->sc_ileave = ccd->ccd_interleave;
373 cs->sc_nccdisks = ccd->ccd_ndev;
375 /* Allocate space for the component info. */
376 cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
380 * Verify that each component piece exists and record
381 * relevant information about it.
385 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
386 vp = ccd->ccd_vpp[ix];
387 ci = &cs->sc_cinfo[ix];
391 * Copy in the pathname of the component.
393 bzero(tmppath, sizeof(tmppath)); /* sanity */
394 if ((error = copyinstr(cpaths[ix], tmppath,
395 MAXPATHLEN, &ci->ci_pathlen)) != 0) {
397 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
398 printf("ccd%d: can't copy path, error = %d\n",
399 ccd->ccd_unit, error);
403 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
404 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
406 ci->ci_dev = vn_todev(vp);
409 * Get partition information for the component.
411 if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
412 FREAD, cred)) != 0) {
414 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
415 printf("ccd%d: %s: ioctl failed, error = %d\n",
416 ccd->ccd_unit, ci->ci_path, error);
420 if (dpart.part->p_fstype == FS_BSDFFS) {
422 ((dpart.disklab->d_secsize > maxsecsize) ?
423 dpart.disklab->d_secsize : maxsecsize);
424 size = dpart.part->p_size - CCD_OFFSET;
427 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
428 printf("ccd%d: %s: incorrect partition type\n",
429 ccd->ccd_unit, ci->ci_path);
436 * Calculate the size, truncating to an interleave
437 * boundary if necessary.
440 if (cs->sc_ileave > 1)
441 size -= size % cs->sc_ileave;
445 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
446 printf("ccd%d: %s: size == 0\n",
447 ccd->ccd_unit, ci->ci_path);
453 if (minsize == 0 || size < minsize)
460 * Don't allow the interleave to be smaller than
461 * the biggest component sector.
463 if ((cs->sc_ileave > 0) &&
464 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
466 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
467 printf("ccd%d: interleave must be at least %d\n",
468 ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
475 * If uniform interleave is desired set all sizes to that of
476 * the smallest component. This will guarentee that a single
477 * interleave table is generated.
479 * Lost space must be taken into account when calculating the
480 * overall size. Half the space is lost when CCDF_MIRROR is
481 * specified. One disk is lost when CCDF_PARITY is specified.
483 if (ccd->ccd_flags & CCDF_UNIFORM) {
484 for (ci = cs->sc_cinfo;
485 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
486 ci->ci_size = minsize;
488 if (ccd->ccd_flags & CCDF_MIRROR) {
490 * Check to see if an even number of components
491 * have been specified. The interleave must also
492 * be non-zero in order for us to be able to
493 * guarentee the topology.
495 if (cs->sc_nccdisks % 2) {
496 printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
500 if (cs->sc_ileave == 0) {
501 printf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
505 cs->sc_size = (cs->sc_nccdisks/2) * minsize;
506 } else if (ccd->ccd_flags & CCDF_PARITY) {
507 cs->sc_size = (cs->sc_nccdisks-1) * minsize;
509 if (cs->sc_ileave == 0) {
510 printf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
514 cs->sc_size = cs->sc_nccdisks * minsize;
519 * Construct the interleave table.
521 ccdinterleave(cs, ccd->ccd_unit);
524 * Create pseudo-geometry based on 1MB cylinders. It's
527 ccg->ccg_secsize = maxsecsize;
528 ccg->ccg_ntracks = 1;
529 ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
530 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
533 * Add an devstat entry for this device.
535 devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
536 ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
537 DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
538 DEVSTAT_PRIORITY_ARRAY);
540 cs->sc_flags |= CCDF_INITED;
541 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
542 cs->sc_unit = ccd->ccd_unit;
545 while (ci > cs->sc_cinfo) {
547 free(ci->ci_path, M_DEVBUF);
549 free(cs->sc_cinfo, M_DEVBUF);
554 ccdinterleave(struct ccd_softc *cs, int unit)
556 struct ccdcinfo *ci, *smallci;
563 if (ccddebug & CCDB_INIT)
564 printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
568 * Allocate an interleave table. The worst case occurs when each
569 * of N disks is of a different size, resulting in N interleave
572 * Chances are this is too big, but we don't care.
574 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
575 cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
576 bzero((caddr_t)cs->sc_itable, size);
579 * Trivial case: no interleave (actually interleave of disk size).
580 * Each table entry represents a single component in its entirety.
582 * An interleave of 0 may not be used with a mirror or parity setup.
584 if (cs->sc_ileave == 0) {
588 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
589 /* Allocate space for ii_index. */
590 ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
592 ii->ii_startblk = bn;
594 ii->ii_index[0] = ix;
595 bn += cs->sc_cinfo[ix].ci_size;
600 if (ccddebug & CCDB_INIT)
601 printiinfo(cs->sc_itable);
607 * The following isn't fast or pretty; it doesn't have to be.
611 for (ii = cs->sc_itable; ; ii++) {
613 * Allocate space for ii_index. We might allocate more then
616 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
620 * Locate the smallest of the remaining components
623 for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks];
625 if (ci->ci_size > size &&
627 ci->ci_size < smallci->ci_size)) {
633 * Nobody left, all done
635 if (smallci == NULL) {
641 * Record starting logical block using an sc_ileave blocksize.
643 ii->ii_startblk = bn / cs->sc_ileave;
646 * Record starting comopnent block using an sc_ileave
647 * blocksize. This value is relative to the beginning of
650 ii->ii_startoff = lbn;
653 * Determine how many disks take part in this interleave
654 * and record their indices.
657 for (ci = cs->sc_cinfo;
658 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
659 if (ci->ci_size >= smallci->ci_size) {
660 ii->ii_index[ix++] = ci - cs->sc_cinfo;
664 bn += ix * (smallci->ci_size - size);
665 lbn = smallci->ci_size / cs->sc_ileave;
666 size = smallci->ci_size;
669 if (ccddebug & CCDB_INIT)
670 printiinfo(cs->sc_itable);
676 ccdopen(dev_t dev, int flags, int fmt, d_thread_t *td)
678 int unit = ccdunit(dev);
679 struct ccd_softc *cs;
680 struct disklabel *lp;
681 int error = 0, part, pmask;
684 if (ccddebug & CCDB_FOLLOW)
685 printf("ccdopen(%x, %x)\n", dev, flags);
689 cs = &ccd_softc[unit];
691 if ((error = ccdlock(cs)) != 0)
700 * If we're initialized, check to see if there are any other
701 * open partitions. If not, then it's safe to update
702 * the in-core disklabel.
704 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
705 ccdgetdisklabel(dev);
707 /* Check that the partition exists. */
708 if (part != RAW_PART && ((part >= lp->d_npartitions) ||
709 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
714 cs->sc_openmask |= pmask;
722 ccdclose(dev_t dev, int flags, int fmt, d_thread_t *td)
724 int unit = ccdunit(dev);
725 struct ccd_softc *cs;
729 if (ccddebug & CCDB_FOLLOW)
730 printf("ccdclose(%x, %x)\n", dev, flags);
735 cs = &ccd_softc[unit];
737 if ((error = ccdlock(cs)) != 0)
742 /* ...that much closer to allowing unconfiguration... */
743 cs->sc_openmask &= ~(1 << part);
749 ccdstrategy(dev_t dev, struct bio *bio)
751 int unit = ccdunit(dev);
753 struct buf *bp = bio->bio_buf;
754 struct ccd_softc *cs = &ccd_softc[unit];
756 struct disklabel *lp;
759 if (ccddebug & CCDB_FOLLOW)
760 printf("ccdstrategy(%x): unit %d\n", bp, unit);
762 if ((cs->sc_flags & CCDF_INITED) == 0) {
767 /* If it's a nil transfer, wake up the top half now. */
768 if (bp->b_bcount == 0) {
776 * Do bounds checking and adjust transfer. If there's an
777 * error, the bounds check will flag that for us.
779 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
780 if (ccdpart(dev) != RAW_PART) {
781 nbio = bounds_check_with_label(dev, bio, lp, wlabel);
785 int pbn; /* in sc_secsize chunks */
786 long sz; /* in sc_secsize chunks */
788 pbn = (int)(bio->bio_offset / cs->sc_geom.ccg_secsize);
789 sz = howmany(bp->b_bcount, cs->sc_geom.ccg_secsize);
792 * If out of bounds return an error. If the request goes
793 * past EOF, clip the request as appropriate. If exactly
794 * at EOF, return success (don't clip), but with 0 bytes
797 * Mark EOF B_INVAL (just like bad), indicating that the
798 * contents of the buffer, if any, is invalid.
802 if (pbn + sz > cs->sc_size) {
803 if (pbn > cs->sc_size || (bp->b_flags & B_BNOCLIP))
805 if (pbn == cs->sc_size) {
806 bp->b_resid = bp->b_bcount;
807 bp->b_flags |= B_INVAL;
810 sz = cs->sc_size - pbn;
811 bp->b_bcount = sz * cs->sc_geom.ccg_secsize;
816 bp->b_resid = bp->b_bcount;
817 nbio->bio_driver_info = dev;
828 * note: bio, not nbio, is valid at the done label.
831 bp->b_error = EINVAL;
833 bp->b_resid = bp->b_bcount;
834 bp->b_flags |= B_ERROR | B_INVAL;
840 ccdstart(struct ccd_softc *cs, struct bio *bio)
843 struct ccdbuf *cbp[4];
844 struct buf *bp = bio->bio_buf;
845 dev_t dev = bio->bio_driver_info;
846 /* XXX! : 2 reads and 2 writes for RAID 4/5 */
849 struct partition *pp;
852 if (ccddebug & CCDB_FOLLOW)
853 printf("ccdstart(%x, %x)\n", cs, bp);
856 /* Record the transaction start */
857 devstat_start_transaction(&cs->device_stats);
860 * Translate the partition-relative block number to an absolute.
862 doffset = bio->bio_offset;
863 if (ccdpart(dev) != RAW_PART) {
864 pp = &cs->sc_label.d_partitions[ccdpart(dev)];
865 doffset += pp->p_offset * cs->sc_label.d_secsize;
869 * Allocate component buffers and fire off the requests
872 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
873 ccdbuffer(cbp, cs, bio, doffset, addr, bcount);
874 rcount = cbp[0]->cb_buf.b_bcount;
876 if (cs->sc_cflags & CCDF_MIRROR) {
878 * Mirroring. Writes go to both disks, reads are
879 * taken from whichever disk seems most appropriate.
881 * We attempt to localize reads to the disk whos arm
882 * is nearest the read request. We ignore seeks due
883 * to writes when making this determination and we
884 * also try to avoid hogging.
886 if (cbp[0]->cb_buf.b_cmd != BUF_CMD_READ) {
887 vn_strategy(cbp[0]->cb_vp,
888 &cbp[0]->cb_buf.b_bio1);
889 vn_strategy(cbp[1]->cb_vp,
890 &cbp[1]->cb_buf.b_bio1);
892 int pick = cs->sc_pick;
893 daddr_t range = cs->sc_size / 16 * cs->sc_label.d_secsize;
895 if (doffset < cs->sc_blk[pick] - range ||
896 doffset > cs->sc_blk[pick] + range
898 cs->sc_pick = pick = 1 - pick;
900 cs->sc_blk[pick] = doffset + rcount;
901 vn_strategy(cbp[pick]->cb_vp,
902 &cbp[pick]->cb_buf.b_bio1);
908 vn_strategy(cbp[0]->cb_vp,
909 &cbp[0]->cb_buf.b_bio1);
917 * Build a component buffer header.
920 ccdbuffer(struct ccdbuf **cb, struct ccd_softc *cs, struct bio *bio,
921 off_t doffset, caddr_t addr, long bcount)
923 struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
925 daddr_t bn, cbn, cboff;
929 if (ccddebug & CCDB_IO)
930 printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
931 cs, bp, bn, addr, bcount);
934 * Determine which component bn falls in.
936 bn = (daddr_t)(doffset / cs->sc_geom.ccg_secsize);
940 if (cs->sc_ileave == 0) {
942 * Serially concatenated and neither a mirror nor a parity
943 * config. This is a special case.
948 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
956 * Calculate cbn, the logical superblock (sc_ileave chunks),
957 * and cboff, a normal block offset (DEV_BSIZE chunks) relative
960 cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */
961 cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */
964 * Figure out which interleave table to use.
966 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
967 if (ii->ii_startblk > cbn)
973 * off is the logical superblock relative to the beginning
974 * of this interleave block.
976 off = cbn - ii->ii_startblk;
979 * We must calculate which disk component to use (ccdisk),
980 * and recalculate cbn to be the superblock relative to
981 * the beginning of the component. This is typically done by
982 * adding 'off' and ii->ii_startoff together. However, 'off'
983 * must typically be divided by the number of components in
984 * this interleave array to be properly convert it from a
985 * CCD-relative logical superblock number to a
986 * component-relative superblock number.
988 if (ii->ii_ndisk == 1) {
990 * When we have just one disk, it can't be a mirror
991 * or a parity config.
993 ccdisk = ii->ii_index[0];
994 cbn = ii->ii_startoff + off;
996 if (cs->sc_cflags & CCDF_MIRROR) {
998 * We have forced a uniform mapping, resulting
999 * in a single interleave array. We double
1000 * up on the first half of the available
1001 * components and our mirror is in the second
1002 * half. This only works with a single
1003 * interleave array because doubling up
1004 * doubles the number of sectors, so there
1005 * cannot be another interleave array because
1006 * the next interleave array's calculations
1009 int ndisk2 = ii->ii_ndisk / 2;
1010 ccdisk = ii->ii_index[off % ndisk2];
1011 cbn = ii->ii_startoff + off / ndisk2;
1012 ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
1013 } else if (cs->sc_cflags & CCDF_PARITY) {
1015 * XXX not implemented yet
1017 int ndisk2 = ii->ii_ndisk - 1;
1018 ccdisk = ii->ii_index[off % ndisk2];
1019 cbn = ii->ii_startoff + off / ndisk2;
1020 if (cbn % ii->ii_ndisk <= ccdisk)
1023 ccdisk = ii->ii_index[off % ii->ii_ndisk];
1024 cbn = ii->ii_startoff + off / ii->ii_ndisk;
1028 ci = &cs->sc_cinfo[ccdisk];
1031 * Convert cbn from a superblock to a normal block so it
1032 * can be used to calculate (along with cboff) the normal
1033 * block index into this particular disk.
1035 cbn *= cs->sc_ileave;
1039 * Fill in the component buf structure.
1041 * NOTE: devices do not use b_bufsize, only b_bcount, but b_bcount
1042 * will be truncated on device EOF so we use b_bufsize to detect
1046 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1047 cbp->cb_buf.b_flags |= bio->bio_buf->b_flags;
1048 cbp->cb_buf.b_data = addr;
1049 cbp->cb_vp = ci->ci_vp;
1050 if (cs->sc_ileave == 0)
1051 cbc = dbtob((off_t)(ci->ci_size - cbn));
1053 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1054 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1055 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1057 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1058 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1059 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
1062 * context for ccdiodone
1065 cbp->cb_unit = cs - ccd_softc;
1066 cbp->cb_comp = ci - cs->sc_cinfo;
1069 if (ccddebug & CCDB_IO)
1070 printf(" dev %x(u%d): cbp %x off %lld addr %x bcnt %d\n",
1071 ci->ci_dev, ci-cs->sc_cinfo, cbp,
1072 cbp->cb_buf.b_bio1.bio_offset,
1073 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1078 * Note: both I/O's setup when reading from mirror, but only one
1081 if (cs->sc_cflags & CCDF_MIRROR) {
1082 /* mirror, setup second I/O */
1085 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1086 cbp->cb_buf.b_flags |= bio->bio_buf->b_flags;
1087 cbp->cb_buf.b_data = addr;
1088 cbp->cb_vp = ci2->ci_vp;
1089 if (cs->sc_ileave == 0)
1090 cbc = dbtob((off_t)(ci->ci_size - cbn));
1092 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1093 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1094 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1096 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1097 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1098 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
1101 * context for ccdiodone
1104 cbp->cb_unit = cs - ccd_softc;
1105 cbp->cb_comp = ci2 - cs->sc_cinfo;
1107 /* link together the ccdbuf's and clear "mirror done" flag */
1108 cb[0]->cb_mirror = cb[1];
1109 cb[1]->cb_mirror = cb[0];
1110 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1111 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1116 ccdintr(struct ccd_softc *cs, struct bio *bio)
1118 struct buf *bp = bio->bio_buf;
1121 if (ccddebug & CCDB_FOLLOW)
1122 printf("ccdintr(%x, %x)\n", cs, bp);
1125 * Request is done for better or worse, wakeup the top half.
1127 if (bp->b_flags & B_ERROR)
1128 bp->b_resid = bp->b_bcount;
1129 devstat_end_transaction_buf(&cs->device_stats, bp);
1134 * Called at interrupt time.
1135 * Mark the component as done and if all components are done,
1136 * take a ccd interrupt.
1139 ccdiodone(struct bio *bio)
1141 struct ccdbuf *cbp = bio->bio_caller_info1.ptr;
1142 struct bio *obio = cbp->cb_obio;
1143 struct buf *obp = obio->bio_buf;
1144 int unit = cbp->cb_unit;
1148 * Since we do not have exclusive access to underlying devices,
1149 * we can't keep cache translations around.
1151 clearbiocache(bio->bio_next);
1155 if (ccddebug & CCDB_FOLLOW)
1156 printf("ccdiodone(%x)\n", cbp);
1157 if (ccddebug & CCDB_IO) {
1158 printf("ccdiodone: bp %x bcount %d resid %d\n",
1159 obp, obp->b_bcount, obp->b_resid);
1160 printf(" dev %x(u%d), cbp %x off %lld addr %x bcnt %d\n",
1161 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1162 cbp->cb_buf.b_loffset, cbp->cb_buf.b_data,
1163 cbp->cb_buf.b_bcount);
1168 * If an error occured, report it. If this is a mirrored
1169 * configuration and the first of two possible reads, do not
1170 * set the error in the bp yet because the second read may
1173 if (cbp->cb_buf.b_flags & B_ERROR) {
1174 const char *msg = "";
1176 if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
1177 (cbp->cb_buf.b_cmd == BUF_CMD_READ) &&
1178 (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1180 * We will try our read on the other disk down
1181 * below, also reverse the default pick so if we
1182 * are doing a scan we do not keep hitting the
1185 struct ccd_softc *cs = &ccd_softc[unit];
1187 msg = ", trying other disk";
1188 cs->sc_pick = 1 - cs->sc_pick;
1189 cs->sc_blk[cs->sc_pick] = obio->bio_offset;
1191 obp->b_flags |= B_ERROR;
1192 obp->b_error = cbp->cb_buf.b_error ?
1193 cbp->cb_buf.b_error : EIO;
1195 printf("ccd%d: error %d on component %d offset %lld (ccd offset %lld)%s\n",
1196 unit, obp->b_error, cbp->cb_comp,
1197 cbp->cb_buf.b_bio2.bio_offset,
1198 obio->bio_offset, msg);
1202 * Process mirror. If we are writing, I/O has been initiated on both
1203 * buffers and we fall through only after both are finished.
1205 * If we are reading only one I/O is initiated at a time. If an
1206 * error occurs we initiate the second I/O and return, otherwise
1207 * we free the second I/O without initiating it.
1210 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
1211 if (cbp->cb_buf.b_cmd != BUF_CMD_READ) {
1213 * When writing, handshake with the second buffer
1214 * to determine when both are done. If both are not
1215 * done, return here.
1217 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1218 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1225 * When reading, either dispose of the second buffer
1226 * or initiate I/O on the second buffer if an error
1227 * occured with this one.
1229 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1230 if (cbp->cb_buf.b_flags & B_ERROR) {
1231 cbp->cb_mirror->cb_pflags |=
1234 cbp->cb_mirror->cb_vp,
1235 &cbp->cb_mirror->cb_buf.b_bio1
1241 putccdbuf(cbp->cb_mirror);
1249 * Use our saved b_bufsize to determine if an unexpected EOF occured.
1251 count = cbp->cb_buf.b_bufsize;
1255 * If all done, "interrupt".
1257 obp->b_resid -= count;
1258 if (obp->b_resid < 0)
1259 panic("ccdiodone: count");
1260 if (obp->b_resid == 0)
1261 ccdintr(&ccd_softc[unit], obio);
1266 ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td)
1268 int unit = ccdunit(dev);
1269 int i, j, lookedup = 0, error = 0;
1271 struct ccd_softc *cs;
1272 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1273 struct ccddevice ccd;
1278 KKASSERT(td->td_proc != NULL);
1279 cred = td->td_proc->p_ucred;
1283 cs = &ccd_softc[unit];
1285 bzero(&ccd, sizeof(ccd));
1289 if (cs->sc_flags & CCDF_INITED)
1292 if ((flag & FWRITE) == 0)
1295 if ((error = ccdlock(cs)) != 0)
1298 if (ccio->ccio_ndisks > CCD_MAXNDISKS)
1301 /* Fill in some important bits. */
1302 ccd.ccd_unit = unit;
1303 ccd.ccd_interleave = ccio->ccio_ileave;
1304 if (ccd.ccd_interleave == 0 &&
1305 ((ccio->ccio_flags & CCDF_MIRROR) ||
1306 (ccio->ccio_flags & CCDF_PARITY))) {
1307 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1308 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1310 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1311 (ccio->ccio_flags & CCDF_PARITY)) {
1312 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1313 ccio->ccio_flags &= ~CCDF_PARITY;
1315 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1316 !(ccio->ccio_flags & CCDF_UNIFORM)) {
1317 printf("ccd%d: mirror/parity forces uniform flag\n",
1319 ccio->ccio_flags |= CCDF_UNIFORM;
1321 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1324 * Allocate space for and copy in the array of
1325 * componet pathnames and device numbers.
1327 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1328 M_DEVBUF, M_WAITOK);
1329 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1330 M_DEVBUF, M_WAITOK);
1332 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1333 ccio->ccio_ndisks * sizeof(char **));
1335 free(vpp, M_DEVBUF);
1336 free(cpp, M_DEVBUF);
1342 if (ccddebug & CCDB_INIT)
1343 for (i = 0; i < ccio->ccio_ndisks; ++i)
1344 printf("ccdioctl: component %d: 0x%x\n",
1348 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1350 if (ccddebug & CCDB_INIT)
1351 printf("ccdioctl: lookedup = %d\n", lookedup);
1353 if ((error = ccdlookup(cpp[i], td, &vpp[i])) != 0) {
1354 for (j = 0; j < lookedup; ++j)
1355 (void)vn_close(vpp[j], FREAD|FWRITE);
1356 free(vpp, M_DEVBUF);
1357 free(cpp, M_DEVBUF);
1365 ccd.ccd_ndev = ccio->ccio_ndisks;
1368 * Initialize the ccd. Fills in the softc for us.
1370 if ((error = ccdinit(&ccd, cpp, td)) != 0) {
1371 for (j = 0; j < lookedup; ++j)
1372 (void)vn_close(vpp[j], FREAD|FWRITE);
1373 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1374 free(vpp, M_DEVBUF);
1375 free(cpp, M_DEVBUF);
1381 * The ccd has been successfully initialized, so
1382 * we can place it into the array and read the disklabel.
1384 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1385 ccio->ccio_unit = unit;
1386 ccio->ccio_size = cs->sc_size;
1387 ccdgetdisklabel(dev);
1394 if ((cs->sc_flags & CCDF_INITED) == 0)
1397 if ((flag & FWRITE) == 0)
1400 if ((error = ccdlock(cs)) != 0)
1403 /* Don't unconfigure if any other partitions are open */
1404 part = ccdpart(dev);
1405 pmask = (1 << part);
1406 if ((cs->sc_openmask & ~pmask)) {
1412 * Free ccd_softc information and clear entry.
1415 /* Close the components and free their pathnames. */
1416 for (i = 0; i < cs->sc_nccdisks; ++i) {
1418 * XXX: this close could potentially fail and
1419 * cause Bad Things. Maybe we need to force
1420 * the close to happen?
1423 if (ccddebug & CCDB_VNODE)
1424 vprint("CCDIOCCLR: vnode info",
1425 cs->sc_cinfo[i].ci_vp);
1427 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE);
1428 free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1431 /* Free interleave index. */
1432 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1433 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1435 /* Free component info and interleave table. */
1436 free(cs->sc_cinfo, M_DEVBUF);
1437 free(cs->sc_itable, M_DEVBUF);
1438 cs->sc_flags &= ~CCDF_INITED;
1441 * Free ccddevice information and clear entry.
1443 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1444 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1446 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1449 * And remove the devstat entry.
1451 devstat_remove_entry(&cs->device_stats);
1453 /* This must be atomic. */
1456 bzero(cs, sizeof(struct ccd_softc));
1462 if ((cs->sc_flags & CCDF_INITED) == 0)
1465 *(struct disklabel *)data = cs->sc_label;
1469 if ((cs->sc_flags & CCDF_INITED) == 0)
1472 ((struct partinfo *)data)->disklab = &cs->sc_label;
1473 ((struct partinfo *)data)->part =
1474 &cs->sc_label.d_partitions[ccdpart(dev)];
1479 if ((cs->sc_flags & CCDF_INITED) == 0)
1482 if ((flag & FWRITE) == 0)
1485 if ((error = ccdlock(cs)) != 0)
1488 cs->sc_flags |= CCDF_LABELLING;
1490 error = setdisklabel(&cs->sc_label,
1491 (struct disklabel *)data, 0);
1493 if (cmd == DIOCWDINFO) {
1494 dev_t cdev = CCDLABELDEV(dev);
1495 error = writedisklabel(cdev, &cs->sc_label);
1499 cs->sc_flags &= ~CCDF_LABELLING;
1508 if ((cs->sc_flags & CCDF_INITED) == 0)
1511 if ((flag & FWRITE) == 0)
1513 if (*(int *)data != 0)
1514 cs->sc_flags |= CCDF_WLABEL;
1516 cs->sc_flags &= ~CCDF_WLABEL;
1529 struct ccd_softc *cs;
1532 if (ccdopen(dev, 0, S_IFCHR, curthread))
1535 cs = &ccd_softc[ccdunit(dev)];
1536 part = ccdpart(dev);
1538 if ((cs->sc_flags & CCDF_INITED) == 0)
1541 if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1544 size = cs->sc_label.d_partitions[part].p_size;
1546 if (ccdclose(dev, 0, S_IFCHR, curthread))
1553 ccddump(dev_t dev, u_int count, u_int blkno, u_int secsize)
1555 /* Not implemented. */
1560 * Lookup the provided name in the filesystem. If the file exists,
1561 * is a valid block device, and isn't being used by anyone else,
1562 * set *vpp to the file's vnode.
1565 ccdlookup(char *path, struct thread *td, struct vnode **vpp)
1567 struct nlookupdata nd;
1572 KKASSERT(td->td_proc);
1573 cred = td->td_proc->p_ucred;
1576 error = nlookup_init(&nd, path, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
1579 if ((error = vn_open(&nd, NULL, FREAD|FWRITE, 0)) != 0) {
1581 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1582 printf("ccdlookup: vn_open error = %d\n", error);
1588 if (vp->v_usecount > 1) {
1593 if (!vn_isdisk(vp, &error))
1597 if (ccddebug & CCDB_VNODE)
1598 vprint("ccdlookup: vnode info", vp);
1602 nd.nl_open_vp = NULL;
1604 *vpp = vp; /* leave ref intact */
1612 * Read the disklabel from the ccd. If one is not present, fake one
1616 ccdgetdisklabel(dev_t dev)
1618 int unit = ccdunit(dev);
1619 struct ccd_softc *cs = &ccd_softc[unit];
1621 struct disklabel *lp = &cs->sc_label;
1622 struct ccdgeom *ccg = &cs->sc_geom;
1625 bzero(lp, sizeof(*lp));
1627 lp->d_secperunit = cs->sc_size;
1628 lp->d_secsize = ccg->ccg_secsize;
1629 lp->d_nsectors = ccg->ccg_nsectors;
1630 lp->d_ntracks = ccg->ccg_ntracks;
1631 lp->d_ncylinders = ccg->ccg_ncylinders;
1632 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1634 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1635 lp->d_type = DTYPE_CCD;
1636 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1638 lp->d_interleave = 1;
1641 lp->d_partitions[RAW_PART].p_offset = 0;
1642 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1643 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1644 lp->d_npartitions = RAW_PART + 1;
1646 lp->d_bbsize = BBSIZE; /* XXX */
1647 lp->d_sbsize = SBSIZE; /* XXX */
1649 lp->d_magic = DISKMAGIC;
1650 lp->d_magic2 = DISKMAGIC;
1651 lp->d_checksum = dkcksum(&cs->sc_label);
1654 * Call the generic disklabel extraction routine.
1656 cdev = CCDLABELDEV(dev);
1657 errstring = readdisklabel(cdev, &cs->sc_label);
1658 if (errstring != NULL)
1659 ccdmakedisklabel(cs);
1662 /* It's actually extremely common to have unlabeled ccds. */
1663 if (ccddebug & CCDB_LABEL)
1664 if (errstring != NULL)
1665 printf("ccd%d: %s\n", unit, errstring);
1670 * Take care of things one might want to take care of in the event
1671 * that a disklabel isn't present.
1674 ccdmakedisklabel(struct ccd_softc *cs)
1676 struct disklabel *lp = &cs->sc_label;
1679 * For historical reasons, if there's no disklabel present
1680 * the raw partition must be marked FS_BSDFFS.
1682 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1684 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1688 * Wait interruptibly for an exclusive lock.
1691 * Several drivers do this; it should be abstracted and made MP-safe.
1694 ccdlock(struct ccd_softc *cs)
1698 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1699 cs->sc_flags |= CCDF_WANTED;
1700 if ((error = tsleep(cs, PCATCH, "ccdlck", 0)) != 0)
1703 cs->sc_flags |= CCDF_LOCKED;
1708 * Unlock and wake up any waiters.
1711 ccdunlock(struct ccd_softc *cs)
1714 cs->sc_flags &= ~CCDF_LOCKED;
1715 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1716 cs->sc_flags &= ~CCDF_WANTED;
1723 printiinfo(struct ccdiinfo *ii)
1727 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1728 printf(" itab[%d]: #dk %d sblk %d soff %d",
1729 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1730 for (i = 0; i < ii->ii_ndisk; i++)
1731 printf(" %d", ii->ii_index[i]);
1738 /* Local Variables: */
1739 /* c-argdecl-indent: 8 */
1740 /* c-continued-statement-offset: 8 */
1741 /* c-indent-level: 8 */