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.39 2007/05/06 19:23:21 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 dev_ops ccd_ops = {
180 { "ccd", CDEV_MAJOR, D_DISK },
184 .d_write = physwrite,
186 .d_strategy = ccdstrategy,
191 /* called during module initialization */
192 static void ccdattach (void);
193 static int ccd_modevent (module_t, int, void *);
195 /* called by biodone() at interrupt time */
196 static void ccdiodone (struct bio *bio);
198 static void ccdstart (struct ccd_softc *, struct bio *);
199 static void ccdinterleave (struct ccd_softc *, int);
200 static void ccdintr (struct ccd_softc *, struct bio *);
201 static int ccdinit (struct ccddevice *, char **, struct ucred *);
202 static int ccdlookup (char *, struct vnode **);
203 static void ccdbuffer (struct ccdbuf **ret, struct ccd_softc *,
204 struct bio *, off_t, caddr_t, long);
205 static void ccdgetdisklabel (cdev_t);
206 static void ccdmakedisklabel (struct ccd_softc *);
207 static int ccdlock (struct ccd_softc *);
208 static void ccdunlock (struct ccd_softc *);
211 static void printiinfo (struct ccdiinfo *);
214 /* Non-private for the benefit of libkvm. */
215 struct ccd_softc *ccd_softc;
216 struct ccddevice *ccddevs;
217 struct ccdbuf *ccdfreebufs;
218 static int numccdfreebufs;
219 static int numccd = 0;
222 * getccdbuf() - Allocate and zero a ccd buffer.
224 * This routine is called at splbio().
234 * Allocate from freelist or malloc as necessary
236 if ((cbp = ccdfreebufs) != NULL) {
237 ccdfreebufs = cbp->cb_freenext;
239 reinitbufbio(&cbp->cb_buf);
241 cbp = kmalloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK|M_ZERO);
242 initbufbio(&cbp->cb_buf);
246 * independant struct buf initialization
248 LIST_INIT(&cbp->cb_buf.b_dep);
249 BUF_LOCKINIT(&cbp->cb_buf);
250 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
251 BUF_KERNPROC(&cbp->cb_buf);
252 cbp->cb_buf.b_flags = B_PAGING | B_BNOCLIP;
258 * putccdbuf() - Free a ccd buffer.
260 * This routine is called at splbio().
265 putccdbuf(struct ccdbuf *cbp)
267 BUF_UNLOCK(&cbp->cb_buf);
268 BUF_LOCKFREE(&cbp->cb_buf);
270 if (numccdfreebufs < NCCDFREEHIWAT) {
271 cbp->cb_freenext = ccdfreebufs;
275 kfree((caddr_t)cbp, M_DEVBUF);
281 * Number of blocks to untouched in front of a component partition.
282 * This is to avoid violating its disklabel area when it starts at the
283 * beginning of the slice.
285 #if !defined(CCD_OFFSET)
286 #define CCD_OFFSET 16
290 * Called by main() during pseudo-device attachment. All we need
291 * to do is allocate enough space for devices to be configured later, and
301 kprintf("ccd0-%d: Concatenated disk drivers\n", num-1);
303 kprintf("ccd0: Concatenated disk driver\n");
305 ccd_softc = kmalloc(num * sizeof(struct ccd_softc), M_DEVBUF,
307 ccddevs = kmalloc(num * sizeof(struct ccddevice), M_DEVBUF,
311 dev_ops_add(&ccd_ops, 0, 0);
312 /* XXX: is this necessary? */
313 for (i = 0; i < numccd; ++i)
314 ccddevs[i].ccd_dk = -1;
318 ccd_modevent(module_t mod, int type, void *data)
328 kprintf("ccd0: Unload not supported!\n");
332 default: /* MOD_SHUTDOWN etc */
338 DEV_MODULE(ccd, ccd_modevent, NULL);
341 ccdinit(struct ccddevice *ccd, char **cpaths, struct ucred *cred)
343 struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
344 struct ccdcinfo *ci = NULL; /* XXX */
350 struct partinfo dpart;
351 struct ccdgeom *ccg = &cs->sc_geom;
352 char tmppath[MAXPATHLEN];
356 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
357 kprintf("ccdinit: unit %d\n", ccd->ccd_unit);
361 cs->sc_ileave = ccd->ccd_interleave;
362 cs->sc_nccdisks = ccd->ccd_ndev;
364 /* Allocate space for the component info. */
365 cs->sc_cinfo = kmalloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
369 * Verify that each component piece exists and record
370 * relevant information about it.
374 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
375 vp = ccd->ccd_vpp[ix];
376 ci = &cs->sc_cinfo[ix];
380 * Copy in the pathname of the component.
382 bzero(tmppath, sizeof(tmppath)); /* sanity */
383 if ((error = copyinstr(cpaths[ix], tmppath,
384 MAXPATHLEN, &ci->ci_pathlen)) != 0) {
386 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
387 kprintf("ccd%d: can't copy path, error = %d\n",
388 ccd->ccd_unit, error);
392 ci->ci_path = kmalloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
393 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
395 ci->ci_dev = vn_todev(vp);
398 * Get partition information for the component.
400 if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
401 FREAD, cred)) != 0) {
403 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
404 kprintf("ccd%d: %s: ioctl failed, error = %d\n",
405 ccd->ccd_unit, ci->ci_path, error);
409 if (dpart.part->p_fstype == FS_BSDFFS) {
411 ((dpart.disklab->d_secsize > maxsecsize) ?
412 dpart.disklab->d_secsize : maxsecsize);
413 size = dpart.part->p_size - CCD_OFFSET;
416 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
417 kprintf("ccd%d: %s: incorrect partition type\n",
418 ccd->ccd_unit, ci->ci_path);
425 * Calculate the size, truncating to an interleave
426 * boundary if necessary.
429 if (cs->sc_ileave > 1)
430 size -= size % cs->sc_ileave;
434 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
435 kprintf("ccd%d: %s: size == 0\n",
436 ccd->ccd_unit, ci->ci_path);
442 if (minsize == 0 || size < minsize)
449 * Don't allow the interleave to be smaller than
450 * the biggest component sector.
452 if ((cs->sc_ileave > 0) &&
453 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
455 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
456 kprintf("ccd%d: interleave must be at least %d\n",
457 ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
464 * If uniform interleave is desired set all sizes to that of
465 * the smallest component. This will guarentee that a single
466 * interleave table is generated.
468 * Lost space must be taken into account when calculating the
469 * overall size. Half the space is lost when CCDF_MIRROR is
470 * specified. One disk is lost when CCDF_PARITY is specified.
472 if (ccd->ccd_flags & CCDF_UNIFORM) {
473 for (ci = cs->sc_cinfo;
474 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
475 ci->ci_size = minsize;
477 if (ccd->ccd_flags & CCDF_MIRROR) {
479 * Check to see if an even number of components
480 * have been specified. The interleave must also
481 * be non-zero in order for us to be able to
482 * guarentee the topology.
484 if (cs->sc_nccdisks % 2) {
485 kprintf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
489 if (cs->sc_ileave == 0) {
490 kprintf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
494 cs->sc_size = (cs->sc_nccdisks/2) * minsize;
495 } else if (ccd->ccd_flags & CCDF_PARITY) {
496 cs->sc_size = (cs->sc_nccdisks-1) * minsize;
498 if (cs->sc_ileave == 0) {
499 kprintf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
503 cs->sc_size = cs->sc_nccdisks * minsize;
508 * Construct the interleave table.
510 ccdinterleave(cs, ccd->ccd_unit);
513 * Create pseudo-geometry based on 1MB cylinders. It's
516 ccg->ccg_secsize = maxsecsize;
517 ccg->ccg_ntracks = 1;
518 ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
519 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
522 * Add an devstat entry for this device.
524 devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
525 ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
526 DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
527 DEVSTAT_PRIORITY_ARRAY);
529 cs->sc_flags |= CCDF_INITED;
530 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
531 cs->sc_unit = ccd->ccd_unit;
534 while (ci > cs->sc_cinfo) {
536 kfree(ci->ci_path, M_DEVBUF);
538 kfree(cs->sc_cinfo, M_DEVBUF);
543 ccdinterleave(struct ccd_softc *cs, int unit)
545 struct ccdcinfo *ci, *smallci;
552 if (ccddebug & CCDB_INIT)
553 kprintf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
557 * Allocate an interleave table. The worst case occurs when each
558 * of N disks is of a different size, resulting in N interleave
561 * Chances are this is too big, but we don't care.
563 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
564 cs->sc_itable = (struct ccdiinfo *)kmalloc(size, M_DEVBUF, M_WAITOK);
565 bzero((caddr_t)cs->sc_itable, size);
568 * Trivial case: no interleave (actually interleave of disk size).
569 * Each table entry represents a single component in its entirety.
571 * An interleave of 0 may not be used with a mirror or parity setup.
573 if (cs->sc_ileave == 0) {
577 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
578 /* Allocate space for ii_index. */
579 ii->ii_index = kmalloc(sizeof(int), M_DEVBUF, M_WAITOK);
581 ii->ii_startblk = bn;
583 ii->ii_index[0] = ix;
584 bn += cs->sc_cinfo[ix].ci_size;
589 if (ccddebug & CCDB_INIT)
590 printiinfo(cs->sc_itable);
596 * The following isn't fast or pretty; it doesn't have to be.
600 for (ii = cs->sc_itable; ; ii++) {
602 * Allocate space for ii_index. We might allocate more then
605 ii->ii_index = kmalloc((sizeof(int) * cs->sc_nccdisks),
609 * Locate the smallest of the remaining components
612 for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks];
614 if (ci->ci_size > size &&
616 ci->ci_size < smallci->ci_size)) {
622 * Nobody left, all done
624 if (smallci == NULL) {
630 * Record starting logical block using an sc_ileave blocksize.
632 ii->ii_startblk = bn / cs->sc_ileave;
635 * Record starting comopnent block using an sc_ileave
636 * blocksize. This value is relative to the beginning of
639 ii->ii_startoff = lbn;
642 * Determine how many disks take part in this interleave
643 * and record their indices.
646 for (ci = cs->sc_cinfo;
647 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
648 if (ci->ci_size >= smallci->ci_size) {
649 ii->ii_index[ix++] = ci - cs->sc_cinfo;
653 bn += ix * (smallci->ci_size - size);
654 lbn = smallci->ci_size / cs->sc_ileave;
655 size = smallci->ci_size;
658 if (ccddebug & CCDB_INIT)
659 printiinfo(cs->sc_itable);
665 ccdopen(struct dev_open_args *ap)
667 cdev_t dev = ap->a_head.a_dev;
668 int unit = ccdunit(dev);
669 struct ccd_softc *cs;
670 struct disklabel *lp;
671 int error = 0, part, pmask;
674 if (ccddebug & CCDB_FOLLOW)
675 kprintf("ccdopen(%x, %x)\n", dev, flags);
679 cs = &ccd_softc[unit];
681 if ((error = ccdlock(cs)) != 0)
690 * If we're initialized, check to see if there are any other
691 * open partitions. If not, then it's safe to update
692 * the in-core disklabel.
694 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
695 ccdgetdisklabel(dev);
697 /* Check that the partition exists. */
698 if (part != RAW_PART && ((part >= lp->d_npartitions) ||
699 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
704 cs->sc_openmask |= pmask;
712 ccdclose(struct dev_close_args *ap)
714 cdev_t dev = ap->a_head.a_dev;
715 int unit = ccdunit(dev);
716 struct ccd_softc *cs;
720 if (ccddebug & CCDB_FOLLOW)
721 kprintf("ccdclose(%x, %x)\n", dev, flags);
726 cs = &ccd_softc[unit];
728 if ((error = ccdlock(cs)) != 0)
733 /* ...that much closer to allowing unconfiguration... */
734 cs->sc_openmask &= ~(1 << part);
740 ccdstrategy(struct dev_strategy_args *ap)
742 cdev_t dev = ap->a_head.a_dev;
743 struct bio *bio = ap->a_bio;
744 int unit = ccdunit(dev);
746 struct buf *bp = bio->bio_buf;
747 struct ccd_softc *cs = &ccd_softc[unit];
749 struct disklabel *lp;
752 if (ccddebug & CCDB_FOLLOW)
753 kprintf("ccdstrategy(%x): unit %d\n", bp, unit);
755 if ((cs->sc_flags & CCDF_INITED) == 0) {
760 /* If it's a nil transfer, wake up the top half now. */
761 if (bp->b_bcount == 0) {
769 * Do bounds checking and adjust transfer. If there's an
770 * error, the bounds check will flag that for us.
772 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
773 if (ccdpart(dev) != RAW_PART) {
774 nbio = bounds_check_with_label(dev, bio, lp, wlabel);
778 int pbn; /* in sc_secsize chunks */
779 long sz; /* in sc_secsize chunks */
781 pbn = (int)(bio->bio_offset / cs->sc_geom.ccg_secsize);
782 sz = howmany(bp->b_bcount, cs->sc_geom.ccg_secsize);
785 * If out of bounds return an error. If the request goes
786 * past EOF, clip the request as appropriate. If exactly
787 * at EOF, return success (don't clip), but with 0 bytes
790 * Mark EOF B_INVAL (just like bad), indicating that the
791 * contents of the buffer, if any, is invalid.
795 if (pbn + sz > cs->sc_size) {
796 if (pbn > cs->sc_size || (bp->b_flags & B_BNOCLIP))
798 if (pbn == cs->sc_size) {
799 bp->b_resid = bp->b_bcount;
800 bp->b_flags |= B_INVAL;
803 sz = cs->sc_size - pbn;
804 bp->b_bcount = sz * cs->sc_geom.ccg_secsize;
809 bp->b_resid = bp->b_bcount;
810 nbio->bio_driver_info = dev;
821 * note: bio, not nbio, is valid at the done label.
824 bp->b_error = EINVAL;
826 bp->b_resid = bp->b_bcount;
827 bp->b_flags |= B_ERROR | B_INVAL;
834 ccdstart(struct ccd_softc *cs, struct bio *bio)
837 struct ccdbuf *cbp[4];
838 struct buf *bp = bio->bio_buf;
839 cdev_t dev = bio->bio_driver_info;
840 /* XXX! : 2 reads and 2 writes for RAID 4/5 */
843 struct partition *pp;
846 if (ccddebug & CCDB_FOLLOW)
847 kprintf("ccdstart(%x, %x)\n", cs, bp);
850 /* Record the transaction start */
851 devstat_start_transaction(&cs->device_stats);
854 * Translate the partition-relative block number to an absolute.
856 doffset = bio->bio_offset;
857 if (ccdpart(dev) != RAW_PART) {
858 pp = &cs->sc_label.d_partitions[ccdpart(dev)];
859 doffset += pp->p_offset * cs->sc_label.d_secsize;
863 * Allocate component buffers and fire off the requests
866 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
867 ccdbuffer(cbp, cs, bio, doffset, addr, bcount);
868 rcount = cbp[0]->cb_buf.b_bcount;
870 if (cs->sc_cflags & CCDF_MIRROR) {
872 * Mirroring. Writes go to both disks, reads are
873 * taken from whichever disk seems most appropriate.
875 * We attempt to localize reads to the disk whos arm
876 * is nearest the read request. We ignore seeks due
877 * to writes when making this determination and we
878 * also try to avoid hogging.
880 if (cbp[0]->cb_buf.b_cmd != BUF_CMD_READ) {
881 vn_strategy(cbp[0]->cb_vp,
882 &cbp[0]->cb_buf.b_bio1);
883 vn_strategy(cbp[1]->cb_vp,
884 &cbp[1]->cb_buf.b_bio1);
886 int pick = cs->sc_pick;
887 daddr_t range = cs->sc_size / 16 * cs->sc_label.d_secsize;
889 if (doffset < cs->sc_blk[pick] - range ||
890 doffset > cs->sc_blk[pick] + range
892 cs->sc_pick = pick = 1 - pick;
894 cs->sc_blk[pick] = doffset + rcount;
895 vn_strategy(cbp[pick]->cb_vp,
896 &cbp[pick]->cb_buf.b_bio1);
902 vn_strategy(cbp[0]->cb_vp,
903 &cbp[0]->cb_buf.b_bio1);
911 * Build a component buffer header.
914 ccdbuffer(struct ccdbuf **cb, struct ccd_softc *cs, struct bio *bio,
915 off_t doffset, caddr_t addr, long bcount)
917 struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
919 daddr_t bn, cbn, cboff;
923 if (ccddebug & CCDB_IO)
924 kprintf("ccdbuffer(%x, %x, %d, %x, %d)\n",
925 cs, bp, bn, addr, bcount);
928 * Determine which component bn falls in.
930 bn = (daddr_t)(doffset / cs->sc_geom.ccg_secsize);
934 if (cs->sc_ileave == 0) {
936 * Serially concatenated and neither a mirror nor a parity
937 * config. This is a special case.
942 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
950 * Calculate cbn, the logical superblock (sc_ileave chunks),
951 * and cboff, a normal block offset (DEV_BSIZE chunks) relative
954 cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */
955 cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */
958 * Figure out which interleave table to use.
960 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
961 if (ii->ii_startblk > cbn)
967 * off is the logical superblock relative to the beginning
968 * of this interleave block.
970 off = cbn - ii->ii_startblk;
973 * We must calculate which disk component to use (ccdisk),
974 * and recalculate cbn to be the superblock relative to
975 * the beginning of the component. This is typically done by
976 * adding 'off' and ii->ii_startoff together. However, 'off'
977 * must typically be divided by the number of components in
978 * this interleave array to be properly convert it from a
979 * CCD-relative logical superblock number to a
980 * component-relative superblock number.
982 if (ii->ii_ndisk == 1) {
984 * When we have just one disk, it can't be a mirror
985 * or a parity config.
987 ccdisk = ii->ii_index[0];
988 cbn = ii->ii_startoff + off;
990 if (cs->sc_cflags & CCDF_MIRROR) {
992 * We have forced a uniform mapping, resulting
993 * in a single interleave array. We double
994 * up on the first half of the available
995 * components and our mirror is in the second
996 * half. This only works with a single
997 * interleave array because doubling up
998 * doubles the number of sectors, so there
999 * cannot be another interleave array because
1000 * the next interleave array's calculations
1003 int ndisk2 = ii->ii_ndisk / 2;
1004 ccdisk = ii->ii_index[off % ndisk2];
1005 cbn = ii->ii_startoff + off / ndisk2;
1006 ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
1007 } else if (cs->sc_cflags & CCDF_PARITY) {
1009 * XXX not implemented yet
1011 int ndisk2 = ii->ii_ndisk - 1;
1012 ccdisk = ii->ii_index[off % ndisk2];
1013 cbn = ii->ii_startoff + off / ndisk2;
1014 if (cbn % ii->ii_ndisk <= ccdisk)
1017 ccdisk = ii->ii_index[off % ii->ii_ndisk];
1018 cbn = ii->ii_startoff + off / ii->ii_ndisk;
1022 ci = &cs->sc_cinfo[ccdisk];
1025 * Convert cbn from a superblock to a normal block so it
1026 * can be used to calculate (along with cboff) the normal
1027 * block index into this particular disk.
1029 cbn *= cs->sc_ileave;
1033 * Fill in the component buf structure.
1035 * NOTE: devices do not use b_bufsize, only b_bcount, but b_bcount
1036 * will be truncated on device EOF so we use b_bufsize to detect
1040 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1041 cbp->cb_buf.b_flags |= bio->bio_buf->b_flags;
1042 cbp->cb_buf.b_data = addr;
1043 cbp->cb_vp = ci->ci_vp;
1044 if (cs->sc_ileave == 0)
1045 cbc = dbtob((off_t)(ci->ci_size - cbn));
1047 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1048 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1049 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1051 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1052 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1053 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
1056 * context for ccdiodone
1059 cbp->cb_unit = cs - ccd_softc;
1060 cbp->cb_comp = ci - cs->sc_cinfo;
1063 if (ccddebug & CCDB_IO)
1064 kprintf(" dev %x(u%d): cbp %x off %lld addr %x bcnt %d\n",
1065 ci->ci_dev, ci-cs->sc_cinfo, cbp,
1066 cbp->cb_buf.b_bio1.bio_offset,
1067 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1072 * Note: both I/O's setup when reading from mirror, but only one
1075 if (cs->sc_cflags & CCDF_MIRROR) {
1076 /* mirror, setup second I/O */
1079 cbp->cb_buf.b_cmd = bio->bio_buf->b_cmd;
1080 cbp->cb_buf.b_flags |= bio->bio_buf->b_flags;
1081 cbp->cb_buf.b_data = addr;
1082 cbp->cb_vp = ci2->ci_vp;
1083 if (cs->sc_ileave == 0)
1084 cbc = dbtob((off_t)(ci->ci_size - cbn));
1086 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1087 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1088 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1090 cbp->cb_buf.b_bio1.bio_done = ccdiodone;
1091 cbp->cb_buf.b_bio1.bio_caller_info1.ptr = cbp;
1092 cbp->cb_buf.b_bio1.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
1095 * context for ccdiodone
1098 cbp->cb_unit = cs - ccd_softc;
1099 cbp->cb_comp = ci2 - cs->sc_cinfo;
1101 /* link together the ccdbuf's and clear "mirror done" flag */
1102 cb[0]->cb_mirror = cb[1];
1103 cb[1]->cb_mirror = cb[0];
1104 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1105 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1110 ccdintr(struct ccd_softc *cs, struct bio *bio)
1112 struct buf *bp = bio->bio_buf;
1115 if (ccddebug & CCDB_FOLLOW)
1116 kprintf("ccdintr(%x, %x)\n", cs, bp);
1119 * Request is done for better or worse, wakeup the top half.
1121 if (bp->b_flags & B_ERROR)
1122 bp->b_resid = bp->b_bcount;
1123 devstat_end_transaction_buf(&cs->device_stats, bp);
1128 * Called at interrupt time.
1129 * Mark the component as done and if all components are done,
1130 * take a ccd interrupt.
1133 ccdiodone(struct bio *bio)
1135 struct ccdbuf *cbp = bio->bio_caller_info1.ptr;
1136 struct bio *obio = cbp->cb_obio;
1137 struct buf *obp = obio->bio_buf;
1138 int unit = cbp->cb_unit;
1142 * Since we do not have exclusive access to underlying devices,
1143 * we can't keep cache translations around.
1145 clearbiocache(bio->bio_next);
1149 if (ccddebug & CCDB_FOLLOW)
1150 kprintf("ccdiodone(%x)\n", cbp);
1151 if (ccddebug & CCDB_IO) {
1152 kprintf("ccdiodone: bp %x bcount %d resid %d\n",
1153 obp, obp->b_bcount, obp->b_resid);
1154 kprintf(" dev %x(u%d), cbp %x off %lld addr %x bcnt %d\n",
1155 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1156 cbp->cb_buf.b_loffset, cbp->cb_buf.b_data,
1157 cbp->cb_buf.b_bcount);
1162 * If an error occured, report it. If this is a mirrored
1163 * configuration and the first of two possible reads, do not
1164 * set the error in the bp yet because the second read may
1167 if (cbp->cb_buf.b_flags & B_ERROR) {
1168 const char *msg = "";
1170 if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
1171 (cbp->cb_buf.b_cmd == BUF_CMD_READ) &&
1172 (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1174 * We will try our read on the other disk down
1175 * below, also reverse the default pick so if we
1176 * are doing a scan we do not keep hitting the
1179 struct ccd_softc *cs = &ccd_softc[unit];
1181 msg = ", trying other disk";
1182 cs->sc_pick = 1 - cs->sc_pick;
1183 cs->sc_blk[cs->sc_pick] = obio->bio_offset;
1185 obp->b_flags |= B_ERROR;
1186 obp->b_error = cbp->cb_buf.b_error ?
1187 cbp->cb_buf.b_error : EIO;
1189 kprintf("ccd%d: error %d on component %d offset %lld (ccd offset %lld)%s\n",
1190 unit, obp->b_error, cbp->cb_comp,
1191 cbp->cb_buf.b_bio2.bio_offset,
1192 obio->bio_offset, msg);
1196 * Process mirror. If we are writing, I/O has been initiated on both
1197 * buffers and we fall through only after both are finished.
1199 * If we are reading only one I/O is initiated at a time. If an
1200 * error occurs we initiate the second I/O and return, otherwise
1201 * we free the second I/O without initiating it.
1204 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
1205 if (cbp->cb_buf.b_cmd != BUF_CMD_READ) {
1207 * When writing, handshake with the second buffer
1208 * to determine when both are done. If both are not
1209 * done, return here.
1211 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1212 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1219 * When reading, either dispose of the second buffer
1220 * or initiate I/O on the second buffer if an error
1221 * occured with this one.
1223 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1224 if (cbp->cb_buf.b_flags & B_ERROR) {
1225 cbp->cb_mirror->cb_pflags |=
1228 cbp->cb_mirror->cb_vp,
1229 &cbp->cb_mirror->cb_buf.b_bio1
1235 putccdbuf(cbp->cb_mirror);
1243 * Use our saved b_bufsize to determine if an unexpected EOF occured.
1245 count = cbp->cb_buf.b_bufsize;
1249 * If all done, "interrupt".
1251 obp->b_resid -= count;
1252 if (obp->b_resid < 0)
1253 panic("ccdiodone: count");
1254 if (obp->b_resid == 0)
1255 ccdintr(&ccd_softc[unit], obio);
1260 ccdioctl(struct dev_ioctl_args *ap)
1262 cdev_t dev = ap->a_head.a_dev;
1263 int unit = ccdunit(dev);
1264 int i, j, lookedup = 0, error = 0;
1266 struct ccd_softc *cs;
1267 struct ccd_ioctl *ccio = (struct ccd_ioctl *)ap->a_data;
1268 struct ccddevice ccd;
1274 cs = &ccd_softc[unit];
1276 bzero(&ccd, sizeof(ccd));
1278 switch (ap->a_cmd) {
1280 if (cs->sc_flags & CCDF_INITED)
1283 if ((ap->a_fflag & FWRITE) == 0)
1286 if ((error = ccdlock(cs)) != 0)
1289 if (ccio->ccio_ndisks > CCD_MAXNDISKS)
1292 /* Fill in some important bits. */
1293 ccd.ccd_unit = unit;
1294 ccd.ccd_interleave = ccio->ccio_ileave;
1295 if (ccd.ccd_interleave == 0 &&
1296 ((ccio->ccio_flags & CCDF_MIRROR) ||
1297 (ccio->ccio_flags & CCDF_PARITY))) {
1298 kprintf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1299 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1301 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1302 (ccio->ccio_flags & CCDF_PARITY)) {
1303 kprintf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1304 ccio->ccio_flags &= ~CCDF_PARITY;
1306 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1307 !(ccio->ccio_flags & CCDF_UNIFORM)) {
1308 kprintf("ccd%d: mirror/parity forces uniform flag\n",
1310 ccio->ccio_flags |= CCDF_UNIFORM;
1312 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1315 * Allocate space for and copy in the array of
1316 * componet pathnames and device numbers.
1318 cpp = kmalloc(ccio->ccio_ndisks * sizeof(char *),
1319 M_DEVBUF, M_WAITOK);
1320 vpp = kmalloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1321 M_DEVBUF, M_WAITOK);
1323 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1324 ccio->ccio_ndisks * sizeof(char **));
1326 kfree(vpp, M_DEVBUF);
1327 kfree(cpp, M_DEVBUF);
1333 if (ccddebug & CCDB_INIT)
1334 for (i = 0; i < ccio->ccio_ndisks; ++i)
1335 kprintf("ccdioctl: component %d: 0x%x\n",
1339 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1341 if (ccddebug & CCDB_INIT)
1342 kprintf("ccdioctl: lookedup = %d\n", lookedup);
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);
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 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1365 kfree(vpp, M_DEVBUF);
1366 kfree(cpp, M_DEVBUF);
1372 * The ccd has been successfully initialized, so
1373 * we can place it into the array and read the disklabel.
1375 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1376 ccio->ccio_unit = unit;
1377 ccio->ccio_size = cs->sc_size;
1378 ccdgetdisklabel(dev);
1385 if ((cs->sc_flags & CCDF_INITED) == 0)
1388 if ((ap->a_fflag & FWRITE) == 0)
1391 if ((error = ccdlock(cs)) != 0)
1394 /* Don't unconfigure if any other partitions are open */
1395 part = ccdpart(dev);
1396 pmask = (1 << part);
1397 if ((cs->sc_openmask & ~pmask)) {
1403 * Free ccd_softc information and clear entry.
1406 /* Close the components and free their pathnames. */
1407 for (i = 0; i < cs->sc_nccdisks; ++i) {
1409 * XXX: this close could potentially fail and
1410 * cause Bad Things. Maybe we need to force
1411 * the close to happen?
1414 if (ccddebug & CCDB_VNODE)
1415 vprint("CCDIOCCLR: vnode info",
1416 cs->sc_cinfo[i].ci_vp);
1418 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE);
1419 kfree(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1422 /* Free interleave index. */
1423 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1424 kfree(cs->sc_itable[i].ii_index, M_DEVBUF);
1426 /* Free component info and interleave table. */
1427 kfree(cs->sc_cinfo, M_DEVBUF);
1428 kfree(cs->sc_itable, M_DEVBUF);
1429 cs->sc_flags &= ~CCDF_INITED;
1432 * Free ccddevice information and clear entry.
1434 kfree(ccddevs[unit].ccd_cpp, M_DEVBUF);
1435 kfree(ccddevs[unit].ccd_vpp, M_DEVBUF);
1437 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1440 * And remove the devstat entry.
1442 devstat_remove_entry(&cs->device_stats);
1444 /* This must be atomic. */
1447 bzero(cs, sizeof(struct ccd_softc));
1453 if ((cs->sc_flags & CCDF_INITED) == 0)
1456 *(struct disklabel *)ap->a_data = cs->sc_label;
1460 if ((cs->sc_flags & CCDF_INITED) == 0)
1463 ((struct partinfo *)ap->a_data)->disklab = &cs->sc_label;
1464 ((struct partinfo *)ap->a_data)->part =
1465 &cs->sc_label.d_partitions[ccdpart(dev)];
1470 if ((cs->sc_flags & CCDF_INITED) == 0)
1473 if ((ap->a_fflag & FWRITE) == 0)
1476 if ((error = ccdlock(cs)) != 0)
1479 cs->sc_flags |= CCDF_LABELLING;
1481 error = setdisklabel(&cs->sc_label,
1482 (struct disklabel *)ap->a_data, 0);
1484 if (ap->a_cmd == DIOCWDINFO) {
1485 cdev_t cdev = CCDLABELDEV(dev);
1486 error = writedisklabel(cdev, &cs->sc_label);
1490 cs->sc_flags &= ~CCDF_LABELLING;
1499 if ((cs->sc_flags & CCDF_INITED) == 0)
1502 if ((ap->a_fflag & FWRITE) == 0)
1504 if (*(int *)ap->a_data != 0)
1505 cs->sc_flags |= CCDF_WLABEL;
1507 cs->sc_flags &= ~CCDF_WLABEL;
1518 ccdsize(struct dev_psize_args *ap)
1520 cdev_t dev = ap->a_head.a_dev;
1521 struct ccd_softc *cs;
1524 if (dev_dopen(dev, 0, S_IFCHR, proc0.p_ucred))
1527 cs = &ccd_softc[ccdunit(dev)];
1528 part = ccdpart(dev);
1530 if ((cs->sc_flags & CCDF_INITED) == 0)
1533 if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1536 size = cs->sc_label.d_partitions[part].p_size;
1538 if (dev_dclose(dev, 0, S_IFCHR))
1541 ap->a_result = size;
1546 ccddump(struct dev_dump_args *ap)
1548 /* Not implemented. */
1553 * Lookup the provided name in the filesystem. If the file exists,
1554 * is a valid block device, and isn't being used by anyone else,
1555 * set *vpp to the file's vnode.
1558 ccdlookup(char *path, struct vnode **vpp)
1560 struct nlookupdata nd;
1566 error = nlookup_init(&nd, path, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
1569 if ((error = vn_open(&nd, NULL, FREAD|FWRITE, 0)) != 0) {
1571 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1572 kprintf("ccdlookup: vn_open error = %d\n", error);
1578 if (vp->v_opencount > 1) {
1583 if (!vn_isdisk(vp, &error))
1587 if (ccddebug & CCDB_VNODE)
1588 vprint("ccdlookup: vnode info", vp);
1592 nd.nl_open_vp = NULL;
1594 *vpp = vp; /* leave ref intact */
1602 * Read the disklabel from the ccd. If one is not present, fake one
1606 ccdgetdisklabel(cdev_t dev)
1608 int unit = ccdunit(dev);
1609 struct ccd_softc *cs = &ccd_softc[unit];
1611 struct disklabel *lp = &cs->sc_label;
1612 struct ccdgeom *ccg = &cs->sc_geom;
1615 bzero(lp, sizeof(*lp));
1617 lp->d_secperunit = cs->sc_size;
1618 lp->d_secsize = ccg->ccg_secsize;
1619 lp->d_nsectors = ccg->ccg_nsectors;
1620 lp->d_ntracks = ccg->ccg_ntracks;
1621 lp->d_ncylinders = ccg->ccg_ncylinders;
1622 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1624 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1625 lp->d_type = DTYPE_CCD;
1626 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1628 lp->d_interleave = 1;
1631 lp->d_partitions[RAW_PART].p_offset = 0;
1632 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1633 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1634 lp->d_npartitions = RAW_PART + 1;
1636 lp->d_bbsize = BBSIZE; /* XXX */
1637 lp->d_sbsize = SBSIZE; /* XXX */
1639 lp->d_magic = DISKMAGIC;
1640 lp->d_magic2 = DISKMAGIC;
1641 lp->d_checksum = dkcksum(&cs->sc_label);
1644 * Call the generic disklabel extraction routine.
1646 cdev = CCDLABELDEV(dev);
1647 errstring = readdisklabel(cdev, &cs->sc_label);
1648 if (errstring != NULL)
1649 ccdmakedisklabel(cs);
1652 /* It's actually extremely common to have unlabeled ccds. */
1653 if (ccddebug & CCDB_LABEL)
1654 if (errstring != NULL)
1655 kprintf("ccd%d: %s\n", unit, errstring);
1660 * Take care of things one might want to take care of in the event
1661 * that a disklabel isn't present.
1664 ccdmakedisklabel(struct ccd_softc *cs)
1666 struct disklabel *lp = &cs->sc_label;
1669 * For historical reasons, if there's no disklabel present
1670 * the raw partition must be marked FS_BSDFFS.
1672 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1674 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1678 * Wait interruptibly for an exclusive lock.
1681 * Several drivers do this; it should be abstracted and made MP-safe.
1684 ccdlock(struct ccd_softc *cs)
1688 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1689 cs->sc_flags |= CCDF_WANTED;
1690 if ((error = tsleep(cs, PCATCH, "ccdlck", 0)) != 0)
1693 cs->sc_flags |= CCDF_LOCKED;
1698 * Unlock and wake up any waiters.
1701 ccdunlock(struct ccd_softc *cs)
1704 cs->sc_flags &= ~CCDF_LOCKED;
1705 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1706 cs->sc_flags &= ~CCDF_WANTED;
1713 printiinfo(struct ccdiinfo *ii)
1717 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1718 kprintf(" itab[%d]: #dk %d sblk %d soff %d",
1719 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1720 for (i = 0; i < ii->ii_ndisk; i++)
1721 kprintf(" %d", ii->ii_index[i]);
1728 /* Local Variables: */
1729 /* c-argdecl-indent: 8 */
1730 /* c-continued-statement-offset: 8 */
1731 /* c-indent-level: 8 */