geom_ccd.c revision 50623
1/* $FreeBSD: head/sys/geom/geom_ccd.c 50623 1999-08-30 07:56:23Z phk $ */
2
3/*	$NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $	*/
4
5/*
6 * Copyright (c) 1995 Jason R. Thorpe.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed for the NetBSD Project
20 *	by Jason R. Thorpe.
21 * 4. The name of the author may not be used to endorse or promote products
22 *    derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37/*
38 * Copyright (c) 1988 University of Utah.
39 * Copyright (c) 1990, 1993
40 *	The Regents of the University of California.  All rights reserved.
41 *
42 * This code is derived from software contributed to Berkeley by
43 * the Systems Programming Group of the University of Utah Computer
44 * Science Department.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 *    notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 *    notice, this list of conditions and the following disclaimer in the
53 *    documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 *    must display the following acknowledgement:
56 *	This product includes software developed by the University of
57 *	California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 *    may be used to endorse or promote products derived from this software
60 *    without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
73 *
74 * from: Utah $Hdr: cd.c 1.6 90/11/28$
75 *
76 *	@(#)cd.c	8.2 (Berkeley) 11/16/93
77 */
78
79/*
80 * "Concatenated" disk driver.
81 *
82 * Dynamic configuration and disklabel support by:
83 *	Jason R. Thorpe <thorpej@nas.nasa.gov>
84 *	Numerical Aerodynamic Simulation Facility
85 *	Mail Stop 258-6
86 *	NASA Ames Research Center
87 *	Moffett Field, CA 94035
88 */
89
90#include "ccd.h"
91#if NCCD > 0
92
93#include <sys/param.h>
94#include <sys/systm.h>
95#include <sys/kernel.h>
96#include <sys/module.h>
97#include <sys/proc.h>
98#include <sys/buf.h>
99#include <sys/malloc.h>
100#include <sys/namei.h>
101#include <sys/conf.h>
102#include <sys/stat.h>
103#include <sys/sysctl.h>
104#include <sys/disklabel.h>
105#include <ufs/ffs/fs.h>
106#include <sys/device.h>
107#include <sys/devicestat.h>
108#include <sys/fcntl.h>
109#include <sys/vnode.h>
110
111#include <sys/ccdvar.h>
112
113#if defined(CCDDEBUG) && !defined(DEBUG)
114#define DEBUG
115#endif
116
117#ifdef DEBUG
118#define CCDB_FOLLOW	0x01
119#define CCDB_INIT	0x02
120#define CCDB_IO		0x04
121#define CCDB_LABEL	0x08
122#define CCDB_VNODE	0x10
123static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
124    CCDB_VNODE;
125SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
126#undef DEBUG
127#endif
128
129#define	ccdunit(x)	dkunit(x)
130#define ccdpart(x)	dkpart(x)
131
132/*
133   This is how mirroring works (only writes are special):
134
135   When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
136   linked together by the cb_mirror field.  "cb_pflags &
137   CCDPF_MIRROR_DONE" is set to 0 on both of them.
138
139   When a component returns to ccdiodone(), it checks if "cb_pflags &
140   CCDPF_MIRROR_DONE" is set or not.  If not, it sets the partner's
141   flag and returns.  If it is, it means its partner has already
142   returned, so it will go to the regular cleanup.
143
144 */
145
146struct ccdbuf {
147	struct buf	cb_buf;		/* new I/O buf */
148	struct buf	*cb_obp;	/* ptr. to original I/O buf */
149	int		cb_unit;	/* target unit */
150	int		cb_comp;	/* target component */
151	int		cb_pflags;	/* mirror/parity status flag */
152	struct ccdbuf	*cb_mirror;	/* mirror counterpart */
153};
154
155/* bits in cb_pflags */
156#define CCDPF_MIRROR_DONE 1	/* if set, mirror counterpart is done */
157
158#define	getccdbuf()		\
159	((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK))
160#define putccdbuf(cbp)		\
161	free((caddr_t)(cbp), M_DEVBUF)
162
163#define CCDLABELDEV(dev)	\
164	(makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
165
166static d_open_t ccdopen;
167static d_close_t ccdclose;
168static d_strategy_t ccdstrategy;
169static d_ioctl_t ccdioctl;
170static d_dump_t ccddump;
171static d_psize_t ccdsize;
172
173#define CDEV_MAJOR 74
174#define BDEV_MAJOR 21
175
176static struct cdevsw ccd_cdevsw = {
177	/* open */	ccdopen,
178	/* close */	ccdclose,
179	/* read */	physread,
180	/* write */	physwrite,
181	/* ioctl */	ccdioctl,
182	/* stop */	nostop,
183	/* reset */	noreset,
184	/* devtotty */	nodevtotty,
185	/* poll */	nopoll,
186	/* mmap */	nommap,
187	/* strategy */	ccdstrategy,
188	/* name */	"ccd",
189	/* parms */	noparms,
190	/* maj */	CDEV_MAJOR,
191	/* dump */	ccddump,
192	/* psize */	ccdsize,
193	/* flags */	D_DISK,
194	/* maxio */	0,
195	/* bmaj */	BDEV_MAJOR
196};
197
198/* called during module initialization */
199static	void ccdattach __P((void));
200static	int ccd_modevent __P((module_t, int, void *));
201
202/* called by biodone() at interrupt time */
203static	void ccdiodone __P((struct ccdbuf *cbp));
204
205static	void ccdstart __P((struct ccd_softc *, struct buf *));
206static	void ccdinterleave __P((struct ccd_softc *, int));
207static	void ccdintr __P((struct ccd_softc *, struct buf *));
208static	int ccdinit __P((struct ccddevice *, char **, struct proc *));
209static	int ccdlookup __P((char *, struct proc *p, struct vnode **));
210static	void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *,
211		struct buf *, daddr_t, caddr_t, long));
212static	void ccdgetdisklabel __P((dev_t));
213static	void ccdmakedisklabel __P((struct ccd_softc *));
214static	int ccdlock __P((struct ccd_softc *));
215static	void ccdunlock __P((struct ccd_softc *));
216
217#ifdef DEBUG
218static	void printiinfo __P((struct ccdiinfo *));
219#endif
220
221/* Non-private for the benefit of libkvm. */
222struct	ccd_softc *ccd_softc;
223struct	ccddevice *ccddevs;
224static	int numccd = 0;
225
226/*
227 * Number of blocks to untouched in front of a component partition.
228 * This is to avoid violating its disklabel area when it starts at the
229 * beginning of the slice.
230 */
231#if !defined(CCD_OFFSET)
232#define CCD_OFFSET 16
233#endif
234
235/*
236 * Called by main() during pseudo-device attachment.  All we need
237 * to do is allocate enough space for devices to be configured later, and
238 * add devsw entries.
239 */
240static void
241ccdattach()
242{
243	int i;
244	int num = NCCD;
245
246	if (num > 1)
247		printf("ccd0-%d: Concatenated disk drivers\n", num-1);
248	else
249		printf("ccd0: Concatenated disk driver\n");
250
251	ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
252	    M_DEVBUF, M_NOWAIT);
253	ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
254	    M_DEVBUF, M_NOWAIT);
255	if ((ccd_softc == NULL) || (ccddevs == NULL)) {
256		printf("WARNING: no memory for concatenated disks\n");
257		if (ccd_softc != NULL)
258			free(ccd_softc, M_DEVBUF);
259		if (ccddevs != NULL)
260			free(ccddevs, M_DEVBUF);
261		return;
262	}
263	numccd = num;
264	bzero(ccd_softc, num * sizeof(struct ccd_softc));
265	bzero(ccddevs, num * sizeof(struct ccddevice));
266
267	/* XXX: is this necessary? */
268	for (i = 0; i < numccd; ++i)
269		ccddevs[i].ccd_dk = -1;
270}
271
272static int
273ccd_modevent(mod, type, data)
274	module_t mod;
275	int type;
276	void *data;
277{
278	int error = 0;
279
280	switch (type) {
281	case MOD_LOAD:
282		ccdattach();
283		break;
284
285	case MOD_UNLOAD:
286		printf("ccd0: Unload not supported!\n");
287		error = EOPNOTSUPP;
288		break;
289
290	default:	/* MOD_SHUTDOWN etc */
291		break;
292	}
293	return (error);
294}
295
296DEV_MODULE(ccd, CDEV_MAJOR, BDEV_MAJOR, ccd_cdevsw, ccd_modevent, NULL);
297
298static int
299ccdinit(ccd, cpaths, p)
300	struct ccddevice *ccd;
301	char **cpaths;
302	struct proc *p;
303{
304	register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
305	register struct ccdcinfo *ci = NULL;	/* XXX */
306	register size_t size;
307	register int ix;
308	struct vnode *vp;
309	size_t minsize;
310	int maxsecsize;
311	struct partinfo dpart;
312	struct ccdgeom *ccg = &cs->sc_geom;
313	char tmppath[MAXPATHLEN];
314	int error;
315
316#ifdef DEBUG
317	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
318		printf("ccdinit: unit %d\n", ccd->ccd_unit);
319#endif
320
321	cs->sc_size = 0;
322	cs->sc_ileave = ccd->ccd_interleave;
323	cs->sc_nccdisks = ccd->ccd_ndev;
324
325	/* Allocate space for the component info. */
326	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
327	    M_DEVBUF, M_WAITOK);
328
329	/*
330	 * Verify that each component piece exists and record
331	 * relevant information about it.
332	 */
333	maxsecsize = 0;
334	minsize = 0;
335	for (ix = 0; ix < cs->sc_nccdisks; ix++) {
336		vp = ccd->ccd_vpp[ix];
337		ci = &cs->sc_cinfo[ix];
338		ci->ci_vp = vp;
339
340		/*
341		 * Copy in the pathname of the component.
342		 */
343		bzero(tmppath, sizeof(tmppath));	/* sanity */
344		if ((error = copyinstr(cpaths[ix], tmppath,
345		    MAXPATHLEN, &ci->ci_pathlen)) != 0) {
346#ifdef DEBUG
347			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
348				printf("ccd%d: can't copy path, error = %d\n",
349				    ccd->ccd_unit, error);
350#endif
351			while (ci > cs->sc_cinfo) {
352				ci--;
353				free(ci->ci_path, M_DEVBUF);
354			}
355			free(cs->sc_cinfo, M_DEVBUF);
356			return (error);
357		}
358		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
359		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
360
361		ci->ci_dev = vn_todev(vp);
362
363		/*
364		 * Get partition information for the component.
365		 */
366		if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
367		    FREAD, p->p_ucred, p)) != 0) {
368#ifdef DEBUG
369			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
370				 printf("ccd%d: %s: ioctl failed, error = %d\n",
371				     ccd->ccd_unit, ci->ci_path, error);
372#endif
373			while (ci >= cs->sc_cinfo) {
374				free(ci->ci_path, M_DEVBUF);
375				ci--;
376			}
377			free(cs->sc_cinfo, M_DEVBUF);
378			return (error);
379		}
380		if (dpart.part->p_fstype == FS_BSDFFS) {
381			maxsecsize =
382			    ((dpart.disklab->d_secsize > maxsecsize) ?
383			    dpart.disklab->d_secsize : maxsecsize);
384			size = dpart.part->p_size - CCD_OFFSET;
385		} else {
386#ifdef DEBUG
387			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
388				printf("ccd%d: %s: incorrect partition type\n",
389				    ccd->ccd_unit, ci->ci_path);
390#endif
391			while (ci >= cs->sc_cinfo) {
392				free(ci->ci_path, M_DEVBUF);
393				ci--;
394			}
395			free(cs->sc_cinfo, M_DEVBUF);
396			return (EFTYPE);
397		}
398
399		/*
400		 * Calculate the size, truncating to an interleave
401		 * boundary if necessary.
402		 */
403
404		if (cs->sc_ileave > 1)
405			size -= size % cs->sc_ileave;
406
407		if (size == 0) {
408#ifdef DEBUG
409			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
410				printf("ccd%d: %s: size == 0\n",
411				    ccd->ccd_unit, ci->ci_path);
412#endif
413			while (ci >= cs->sc_cinfo) {
414				free(ci->ci_path, M_DEVBUF);
415				ci--;
416			}
417			free(cs->sc_cinfo, M_DEVBUF);
418			return (ENODEV);
419		}
420
421		if (minsize == 0 || size < minsize)
422			minsize = size;
423		ci->ci_size = size;
424		cs->sc_size += size;
425	}
426
427	/*
428	 * Don't allow the interleave to be smaller than
429	 * the biggest component sector.
430	 */
431	if ((cs->sc_ileave > 0) &&
432	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
433#ifdef DEBUG
434		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
435			printf("ccd%d: interleave must be at least %d\n",
436			    ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
437#endif
438		while (ci >= cs->sc_cinfo) {
439			free(ci->ci_path, M_DEVBUF);
440			ci--;
441		}
442		free(cs->sc_cinfo, M_DEVBUF);
443		return (EINVAL);
444	}
445
446	/*
447	 * If uniform interleave is desired set all sizes to that of
448	 * the smallest component.
449	 */
450	if (ccd->ccd_flags & CCDF_UNIFORM) {
451		for (ci = cs->sc_cinfo;
452		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
453			ci->ci_size = minsize;
454		if (ccd->ccd_flags & CCDF_MIRROR) {
455			/*
456			 * Check to see if an even number of components
457			 * have been specified.
458			 */
459			if (cs->sc_nccdisks % 2) {
460				printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
461				while (ci > cs->sc_cinfo) {
462					ci--;
463					free(ci->ci_path, M_DEVBUF);
464				}
465				free(cs->sc_cinfo, M_DEVBUF);
466				return (EINVAL);
467			}
468			cs->sc_size = (cs->sc_nccdisks/2) * minsize;
469		}
470		else if (ccd->ccd_flags & CCDF_PARITY)
471			cs->sc_size = (cs->sc_nccdisks-1) * minsize;
472		else
473			cs->sc_size = cs->sc_nccdisks * minsize;
474	}
475
476	/*
477	 * Construct the interleave table.
478	 */
479	ccdinterleave(cs, ccd->ccd_unit);
480
481	/*
482	 * Create pseudo-geometry based on 1MB cylinders.  It's
483	 * pretty close.
484	 */
485	ccg->ccg_secsize = maxsecsize;
486	ccg->ccg_ntracks = 1;
487	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
488	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
489
490	/*
491	 * Add an devstat entry for this device.
492	 */
493	devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
494			  ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
495			  DEVSTAT_TYPE_ASC0 |DEVSTAT_TYPE_IF_OTHER,
496			  DEVSTAT_PRIORITY_CCD);
497
498	cs->sc_flags |= CCDF_INITED;
499	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */
500	cs->sc_unit = ccd->ccd_unit;
501	return (0);
502}
503
504static void
505ccdinterleave(cs, unit)
506	register struct ccd_softc *cs;
507	int unit;
508{
509	register struct ccdcinfo *ci, *smallci;
510	register struct ccdiinfo *ii;
511	register daddr_t bn, lbn;
512	register int ix;
513	u_long size;
514
515#ifdef DEBUG
516	if (ccddebug & CCDB_INIT)
517		printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
518#endif
519	/*
520	 * Allocate an interleave table.
521	 * Chances are this is too big, but we don't care.
522	 */
523	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
524	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
525	bzero((caddr_t)cs->sc_itable, size);
526
527	/*
528	 * Trivial case: no interleave (actually interleave of disk size).
529	 * Each table entry represents a single component in its entirety.
530	 */
531	if (cs->sc_ileave == 0) {
532		bn = 0;
533		ii = cs->sc_itable;
534
535		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
536			/* Allocate space for ii_index. */
537			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
538			ii->ii_ndisk = 1;
539			ii->ii_startblk = bn;
540			ii->ii_startoff = 0;
541			ii->ii_index[0] = ix;
542			bn += cs->sc_cinfo[ix].ci_size;
543			ii++;
544		}
545		ii->ii_ndisk = 0;
546#ifdef DEBUG
547		if (ccddebug & CCDB_INIT)
548			printiinfo(cs->sc_itable);
549#endif
550		return;
551	}
552
553	/*
554	 * The following isn't fast or pretty; it doesn't have to be.
555	 */
556	size = 0;
557	bn = lbn = 0;
558	for (ii = cs->sc_itable; ; ii++) {
559		/* Allocate space for ii_index. */
560		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
561		    M_DEVBUF, M_WAITOK);
562
563		/*
564		 * Locate the smallest of the remaining components
565		 */
566		smallci = NULL;
567		for (ci = cs->sc_cinfo;
568		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
569			if (ci->ci_size > size &&
570			    (smallci == NULL ||
571			     ci->ci_size < smallci->ci_size))
572				smallci = ci;
573
574		/*
575		 * Nobody left, all done
576		 */
577		if (smallci == NULL) {
578			ii->ii_ndisk = 0;
579			break;
580		}
581
582		/*
583		 * Record starting logical block and component offset
584		 */
585		ii->ii_startblk = bn / cs->sc_ileave;
586		ii->ii_startoff = lbn;
587
588		/*
589		 * Determine how many disks take part in this interleave
590		 * and record their indices.
591		 */
592		ix = 0;
593		for (ci = cs->sc_cinfo;
594		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
595			if (ci->ci_size >= smallci->ci_size)
596				ii->ii_index[ix++] = ci - cs->sc_cinfo;
597		ii->ii_ndisk = ix;
598		bn += ix * (smallci->ci_size - size);
599		lbn = smallci->ci_size / cs->sc_ileave;
600		size = smallci->ci_size;
601	}
602#ifdef DEBUG
603	if (ccddebug & CCDB_INIT)
604		printiinfo(cs->sc_itable);
605#endif
606}
607
608/* ARGSUSED */
609static int
610ccdopen(dev, flags, fmt, p)
611	dev_t dev;
612	int flags, fmt;
613	struct proc *p;
614{
615	int unit = ccdunit(dev);
616	struct ccd_softc *cs;
617	struct disklabel *lp;
618	int error = 0, part, pmask;
619
620#ifdef DEBUG
621	if (ccddebug & CCDB_FOLLOW)
622		printf("ccdopen(%x, %x)\n", dev, flags);
623#endif
624	if (unit >= numccd)
625		return (ENXIO);
626	cs = &ccd_softc[unit];
627
628	if ((error = ccdlock(cs)) != 0)
629		return (error);
630
631	lp = &cs->sc_label;
632
633	part = ccdpart(dev);
634	pmask = (1 << part);
635
636	dev->si_bsize_phys = DEV_BSIZE;
637	dev->si_bsize_max = MAXBSIZE;
638
639	/*
640	 * If we're initialized, check to see if there are any other
641	 * open partitions.  If not, then it's safe to update
642	 * the in-core disklabel.
643	 */
644	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
645		ccdgetdisklabel(dev);
646
647	/* Check that the partition exists. */
648	if (part != RAW_PART && ((part >= lp->d_npartitions) ||
649	    (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
650		error = ENXIO;
651		goto done;
652	}
653
654	/* Prevent our unit from being unconfigured while open. */
655	switch (fmt) {
656	case S_IFCHR:
657		cs->sc_copenmask |= pmask;
658		break;
659
660	case S_IFBLK:
661		cs->sc_bopenmask |= pmask;
662		break;
663	}
664	cs->sc_openmask =
665	    cs->sc_copenmask | cs->sc_bopenmask;
666
667 done:
668	ccdunlock(cs);
669	return (0);
670}
671
672/* ARGSUSED */
673static int
674ccdclose(dev, flags, fmt, p)
675	dev_t dev;
676	int flags, fmt;
677	struct proc *p;
678{
679	int unit = ccdunit(dev);
680	struct ccd_softc *cs;
681	int error = 0, part;
682
683#ifdef DEBUG
684	if (ccddebug & CCDB_FOLLOW)
685		printf("ccdclose(%x, %x)\n", dev, flags);
686#endif
687
688	if (unit >= numccd)
689		return (ENXIO);
690	cs = &ccd_softc[unit];
691
692	if ((error = ccdlock(cs)) != 0)
693		return (error);
694
695	part = ccdpart(dev);
696
697	/* ...that much closer to allowing unconfiguration... */
698	switch (fmt) {
699	case S_IFCHR:
700		cs->sc_copenmask &= ~(1 << part);
701		break;
702
703	case S_IFBLK:
704		cs->sc_bopenmask &= ~(1 << part);
705		break;
706	}
707	cs->sc_openmask =
708	    cs->sc_copenmask | cs->sc_bopenmask;
709
710	ccdunlock(cs);
711	return (0);
712}
713
714static void
715ccdstrategy(bp)
716	register struct buf *bp;
717{
718	register int unit = ccdunit(bp->b_dev);
719	register struct ccd_softc *cs = &ccd_softc[unit];
720	register int s;
721	int wlabel;
722	struct disklabel *lp;
723
724#ifdef DEBUG
725	if (ccddebug & CCDB_FOLLOW)
726		printf("ccdstrategy(%x): unit %d\n", bp, unit);
727#endif
728	if ((cs->sc_flags & CCDF_INITED) == 0) {
729		bp->b_error = ENXIO;
730		bp->b_flags |= B_ERROR;
731		goto done;
732	}
733
734	/* If it's a nil transfer, wake up the top half now. */
735	if (bp->b_bcount == 0)
736		goto done;
737
738	lp = &cs->sc_label;
739
740	/*
741	 * Do bounds checking and adjust transfer.  If there's an
742	 * error, the bounds check will flag that for us.
743	 */
744	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
745	if (ccdpart(bp->b_dev) != RAW_PART)
746		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
747			goto done;
748
749	bp->b_resid = bp->b_bcount;
750
751	/*
752	 * "Start" the unit.
753	 */
754	s = splbio();
755	ccdstart(cs, bp);
756	splx(s);
757	return;
758done:
759	biodone(bp);
760}
761
762static void
763ccdstart(cs, bp)
764	register struct ccd_softc *cs;
765	register struct buf *bp;
766{
767	register long bcount, rcount;
768	struct ccdbuf *cbp[4];
769	/* XXX! : 2 reads and 2 writes for RAID 4/5 */
770	caddr_t addr;
771	daddr_t bn;
772	struct partition *pp;
773
774#ifdef DEBUG
775	if (ccddebug & CCDB_FOLLOW)
776		printf("ccdstart(%x, %x)\n", cs, bp);
777#endif
778
779	/* Record the transaction start  */
780	devstat_start_transaction(&cs->device_stats);
781
782	/*
783	 * Translate the partition-relative block number to an absolute.
784	 */
785	bn = bp->b_blkno;
786	if (ccdpart(bp->b_dev) != RAW_PART) {
787		pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)];
788		bn += pp->p_offset;
789	}
790
791	/*
792	 * Allocate component buffers and fire off the requests
793	 */
794	addr = bp->b_data;
795	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
796		ccdbuffer(cbp, cs, bp, bn, addr, bcount);
797		rcount = cbp[0]->cb_buf.b_bcount;
798		if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
799			cbp[0]->cb_buf.b_vp->v_numoutput++;
800		VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf);
801		if (cs->sc_cflags & CCDF_MIRROR &&
802		    (cbp[0]->cb_buf.b_flags & B_READ) == 0) {
803			/* mirror, start another write */
804			cbp[1]->cb_buf.b_vp->v_numoutput++;
805			VOP_STRATEGY(cbp[1]->cb_buf.b_vp, &cbp[1]->cb_buf);
806		}
807		bn += btodb(rcount);
808		addr += rcount;
809	}
810}
811
812/*
813 * Build a component buffer header.
814 */
815static void
816ccdbuffer(cb, cs, bp, bn, addr, bcount)
817	register struct ccdbuf **cb;
818	register struct ccd_softc *cs;
819	struct buf *bp;
820	daddr_t bn;
821	caddr_t addr;
822	long bcount;
823{
824	register struct ccdcinfo *ci, *ci2 = NULL;	/* XXX */
825	register struct ccdbuf *cbp;
826	register daddr_t cbn, cboff;
827      register off_t cbc;
828
829#ifdef DEBUG
830	if (ccddebug & CCDB_IO)
831		printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
832		       cs, bp, bn, addr, bcount);
833#endif
834	/*
835	 * Determine which component bn falls in.
836	 */
837	cbn = bn;
838	cboff = 0;
839
840	/*
841	 * Serially concatenated
842	 */
843	if (cs->sc_ileave == 0) {
844		register daddr_t sblk;
845
846		sblk = 0;
847		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
848			sblk += ci->ci_size;
849		cbn -= sblk;
850	}
851	/*
852	 * Interleaved
853	 */
854	else {
855		register struct ccdiinfo *ii;
856		int ccdisk, off;
857
858		cboff = cbn % cs->sc_ileave;
859		cbn /= cs->sc_ileave;
860		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
861			if (ii->ii_startblk > cbn)
862				break;
863		ii--;
864		off = cbn - ii->ii_startblk;
865		if (ii->ii_ndisk == 1) {
866			ccdisk = ii->ii_index[0];
867			cbn = ii->ii_startoff + off;
868		} else {
869			if (cs->sc_cflags & CCDF_MIRROR) {
870				ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)];
871				cbn = ii->ii_startoff + off / (ii->ii_ndisk/2);
872				/* mirrored data */
873				ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2];
874			}
875			else if (cs->sc_cflags & CCDF_PARITY) {
876				ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)];
877				cbn = ii->ii_startoff + off / (ii->ii_ndisk-1);
878				if (cbn % ii->ii_ndisk <= ccdisk)
879					ccdisk++;
880			}
881			else {
882				ccdisk = ii->ii_index[off % ii->ii_ndisk];
883				cbn = ii->ii_startoff + off / ii->ii_ndisk;
884			}
885		}
886		cbn *= cs->sc_ileave;
887		ci = &cs->sc_cinfo[ccdisk];
888	}
889
890	/*
891	 * Fill in the component buf structure.
892	 */
893	cbp = getccdbuf();
894	bzero(cbp, sizeof (struct ccdbuf));
895	cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
896	cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone;
897	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */
898	cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET;
899	cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET);
900	cbp->cb_buf.b_data = addr;
901	cbp->cb_buf.b_vp = ci->ci_vp;
902	LIST_INIT(&cbp->cb_buf.b_dep);
903	BUF_LOCKINIT(&cbp->cb_buf);
904	BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
905	cbp->cb_buf.b_resid = 0;
906	if (cs->sc_ileave == 0)
907              cbc = dbtob((off_t)(ci->ci_size - cbn));
908	else
909              cbc = dbtob((off_t)(cs->sc_ileave - cboff));
910	cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
911 	cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
912
913	/*
914	 * context for ccdiodone
915	 */
916	cbp->cb_obp = bp;
917	cbp->cb_unit = cs - ccd_softc;
918	cbp->cb_comp = ci - cs->sc_cinfo;
919
920#ifdef DEBUG
921	if (ccddebug & CCDB_IO)
922		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
923		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
924		       cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
925#endif
926	cb[0] = cbp;
927	if (cs->sc_cflags & CCDF_MIRROR &&
928	    (cbp->cb_buf.b_flags & B_READ) == 0) {
929		/* mirror, start one more write */
930		cbp = getccdbuf();
931		bzero(cbp, sizeof (struct ccdbuf));
932		*cbp = *cb[0];
933		cbp->cb_buf.b_dev = ci2->ci_dev;
934		cbp->cb_buf.b_vp = ci2->ci_vp;
935		LIST_INIT(&cbp->cb_buf.b_dep);
936		BUF_LOCKINIT(&cbp->cb_buf);
937		BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
938		cbp->cb_comp = ci2 - cs->sc_cinfo;
939		cb[1] = cbp;
940		/* link together the ccdbuf's and clear "mirror done" flag */
941		cb[0]->cb_mirror = cb[1];
942		cb[1]->cb_mirror = cb[0];
943		cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
944		cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
945	}
946}
947
948static void
949ccdintr(cs, bp)
950	register struct ccd_softc *cs;
951	register struct buf *bp;
952{
953#ifdef DEBUG
954	if (ccddebug & CCDB_FOLLOW)
955		printf("ccdintr(%x, %x)\n", cs, bp);
956#endif
957	/*
958	 * Request is done for better or worse, wakeup the top half.
959	 */
960	/* Record device statistics */
961	devstat_end_transaction(&cs->device_stats,
962				bp->b_bcount - bp->b_resid,
963				(bp->b_flags & B_ORDERED) ?
964				DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE,
965				(bp->b_flags & B_READ) ? DEVSTAT_READ :
966				DEVSTAT_WRITE);
967
968	if (bp->b_flags & B_ERROR)
969		bp->b_resid = bp->b_bcount;
970	biodone(bp);
971}
972
973/*
974 * Called at interrupt time.
975 * Mark the component as done and if all components are done,
976 * take a ccd interrupt.
977 */
978static void
979ccdiodone(cbp)
980	struct ccdbuf *cbp;
981{
982	register struct buf *bp = cbp->cb_obp;
983	register int unit = cbp->cb_unit;
984	int count, s;
985
986	s = splbio();
987#ifdef DEBUG
988	if (ccddebug & CCDB_FOLLOW)
989		printf("ccdiodone(%x)\n", cbp);
990	if (ccddebug & CCDB_IO) {
991		printf("ccdiodone: bp %x bcount %d resid %d\n",
992		       bp, bp->b_bcount, bp->b_resid);
993		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
994		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
995		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
996		       cbp->cb_buf.b_bcount);
997	}
998#endif
999
1000	if (cbp->cb_buf.b_flags & B_ERROR) {
1001		bp->b_flags |= B_ERROR;
1002		bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1003#ifdef DEBUG
1004		printf("ccd%d: error %d on component %d\n",
1005		       unit, bp->b_error, cbp->cb_comp);
1006#endif
1007	}
1008
1009	if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1010	    (cbp->cb_buf.b_flags & B_READ) == 0)
1011		if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1012			/* I'm done before my counterpart, so just set
1013			   partner's flag and return */
1014			cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1015			putccdbuf(cbp);
1016			splx(s);
1017			return;
1018		}
1019
1020	count = cbp->cb_buf.b_bcount;
1021	putccdbuf(cbp);
1022
1023	/*
1024	 * If all done, "interrupt".
1025	 */
1026	bp->b_resid -= count;
1027	if (bp->b_resid < 0)
1028		panic("ccdiodone: count");
1029	if (bp->b_resid == 0)
1030		ccdintr(&ccd_softc[unit], bp);
1031	splx(s);
1032}
1033
1034static int
1035ccdioctl(dev, cmd, data, flag, p)
1036	dev_t dev;
1037	u_long cmd;
1038	caddr_t data;
1039	int flag;
1040	struct proc *p;
1041{
1042	int unit = ccdunit(dev);
1043	int i, j, lookedup = 0, error = 0;
1044	int part, pmask, s;
1045	struct ccd_softc *cs;
1046	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1047	struct ccddevice ccd;
1048	char **cpp;
1049	struct vnode **vpp;
1050
1051	if (unit >= numccd)
1052		return (ENXIO);
1053	cs = &ccd_softc[unit];
1054
1055	bzero(&ccd, sizeof(ccd));
1056
1057	switch (cmd) {
1058	case CCDIOCSET:
1059		if (cs->sc_flags & CCDF_INITED)
1060			return (EBUSY);
1061
1062		if ((flag & FWRITE) == 0)
1063			return (EBADF);
1064
1065		if ((error = ccdlock(cs)) != 0)
1066			return (error);
1067
1068		/* Fill in some important bits. */
1069		ccd.ccd_unit = unit;
1070		ccd.ccd_interleave = ccio->ccio_ileave;
1071		if (ccd.ccd_interleave == 0 &&
1072		    ((ccio->ccio_flags & CCDF_MIRROR) ||
1073		     (ccio->ccio_flags & CCDF_PARITY))) {
1074			printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1075			ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1076		}
1077		if ((ccio->ccio_flags & CCDF_MIRROR) &&
1078		    (ccio->ccio_flags & CCDF_PARITY)) {
1079			printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1080			ccio->ccio_flags &= ~CCDF_PARITY;
1081		}
1082		if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1083		    !(ccio->ccio_flags & CCDF_UNIFORM)) {
1084			printf("ccd%d: mirror/parity forces uniform flag\n",
1085			       unit);
1086			ccio->ccio_flags |= CCDF_UNIFORM;
1087		}
1088		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1089
1090		/*
1091		 * Allocate space for and copy in the array of
1092		 * componet pathnames and device numbers.
1093		 */
1094		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1095		    M_DEVBUF, M_WAITOK);
1096		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1097		    M_DEVBUF, M_WAITOK);
1098
1099		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1100		    ccio->ccio_ndisks * sizeof(char **));
1101		if (error) {
1102			free(vpp, M_DEVBUF);
1103			free(cpp, M_DEVBUF);
1104			ccdunlock(cs);
1105			return (error);
1106		}
1107
1108#ifdef DEBUG
1109		if (ccddebug & CCDB_INIT)
1110			for (i = 0; i < ccio->ccio_ndisks; ++i)
1111				printf("ccdioctl: component %d: 0x%x\n",
1112				    i, cpp[i]);
1113#endif
1114
1115		for (i = 0; i < ccio->ccio_ndisks; ++i) {
1116#ifdef DEBUG
1117			if (ccddebug & CCDB_INIT)
1118				printf("ccdioctl: lookedup = %d\n", lookedup);
1119#endif
1120			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1121				for (j = 0; j < lookedup; ++j)
1122					(void)vn_close(vpp[j], FREAD|FWRITE,
1123					    p->p_ucred, p);
1124				free(vpp, M_DEVBUF);
1125				free(cpp, M_DEVBUF);
1126				ccdunlock(cs);
1127				return (error);
1128			}
1129			++lookedup;
1130		}
1131		ccd.ccd_cpp = cpp;
1132		ccd.ccd_vpp = vpp;
1133		ccd.ccd_ndev = ccio->ccio_ndisks;
1134
1135		/*
1136		 * Initialize the ccd.  Fills in the softc for us.
1137		 */
1138		if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1139			for (j = 0; j < lookedup; ++j)
1140				(void)vn_close(vpp[j], FREAD|FWRITE,
1141				    p->p_ucred, p);
1142			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1143			free(vpp, M_DEVBUF);
1144			free(cpp, M_DEVBUF);
1145			ccdunlock(cs);
1146			return (error);
1147		}
1148
1149		/*
1150		 * The ccd has been successfully initialized, so
1151		 * we can place it into the array and read the disklabel.
1152		 */
1153		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1154		ccio->ccio_unit = unit;
1155		ccio->ccio_size = cs->sc_size;
1156		ccdgetdisklabel(dev);
1157
1158		ccdunlock(cs);
1159
1160		break;
1161
1162	case CCDIOCCLR:
1163		if ((cs->sc_flags & CCDF_INITED) == 0)
1164			return (ENXIO);
1165
1166		if ((flag & FWRITE) == 0)
1167			return (EBADF);
1168
1169		if ((error = ccdlock(cs)) != 0)
1170			return (error);
1171
1172		/*
1173		 * Don't unconfigure if any other partitions are open
1174		 * or if both the character and block flavors of this
1175		 * partition are open.
1176		 */
1177		part = ccdpart(dev);
1178		pmask = (1 << part);
1179		if ((cs->sc_openmask & ~pmask) ||
1180		    ((cs->sc_bopenmask & pmask) &&
1181		    (cs->sc_copenmask & pmask))) {
1182			ccdunlock(cs);
1183			return (EBUSY);
1184		}
1185
1186		/*
1187		 * Free ccd_softc information and clear entry.
1188		 */
1189
1190		/* Close the components and free their pathnames. */
1191		for (i = 0; i < cs->sc_nccdisks; ++i) {
1192			/*
1193			 * XXX: this close could potentially fail and
1194			 * cause Bad Things.  Maybe we need to force
1195			 * the close to happen?
1196			 */
1197#ifdef DEBUG
1198			if (ccddebug & CCDB_VNODE)
1199				vprint("CCDIOCCLR: vnode info",
1200				    cs->sc_cinfo[i].ci_vp);
1201#endif
1202			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1203			    p->p_ucred, p);
1204			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1205		}
1206
1207		/* Free interleave index. */
1208		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1209			free(cs->sc_itable[i].ii_index, M_DEVBUF);
1210
1211		/* Free component info and interleave table. */
1212		free(cs->sc_cinfo, M_DEVBUF);
1213		free(cs->sc_itable, M_DEVBUF);
1214		cs->sc_flags &= ~CCDF_INITED;
1215
1216		/*
1217		 * Free ccddevice information and clear entry.
1218		 */
1219		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1220		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1221		ccd.ccd_dk = -1;
1222		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1223
1224		/*
1225		 * And remove the devstat entry.
1226		 */
1227		devstat_remove_entry(&cs->device_stats);
1228
1229		/* This must be atomic. */
1230		s = splhigh();
1231		ccdunlock(cs);
1232		bzero(cs, sizeof(struct ccd_softc));
1233		splx(s);
1234
1235		break;
1236
1237	case DIOCGDINFO:
1238		if ((cs->sc_flags & CCDF_INITED) == 0)
1239			return (ENXIO);
1240
1241		*(struct disklabel *)data = cs->sc_label;
1242		break;
1243
1244	case DIOCGPART:
1245		if ((cs->sc_flags & CCDF_INITED) == 0)
1246			return (ENXIO);
1247
1248		((struct partinfo *)data)->disklab = &cs->sc_label;
1249		((struct partinfo *)data)->part =
1250		    &cs->sc_label.d_partitions[ccdpart(dev)];
1251		break;
1252
1253	case DIOCWDINFO:
1254	case DIOCSDINFO:
1255		if ((cs->sc_flags & CCDF_INITED) == 0)
1256			return (ENXIO);
1257
1258		if ((flag & FWRITE) == 0)
1259			return (EBADF);
1260
1261		if ((error = ccdlock(cs)) != 0)
1262			return (error);
1263
1264		cs->sc_flags |= CCDF_LABELLING;
1265
1266		error = setdisklabel(&cs->sc_label,
1267		    (struct disklabel *)data, 0);
1268		if (error == 0) {
1269			if (cmd == DIOCWDINFO)
1270				error = writedisklabel(CCDLABELDEV(dev),
1271				    &cs->sc_label);
1272		}
1273
1274		cs->sc_flags &= ~CCDF_LABELLING;
1275
1276		ccdunlock(cs);
1277
1278		if (error)
1279			return (error);
1280		break;
1281
1282	case DIOCWLABEL:
1283		if ((cs->sc_flags & CCDF_INITED) == 0)
1284			return (ENXIO);
1285
1286		if ((flag & FWRITE) == 0)
1287			return (EBADF);
1288		if (*(int *)data != 0)
1289			cs->sc_flags |= CCDF_WLABEL;
1290		else
1291			cs->sc_flags &= ~CCDF_WLABEL;
1292		break;
1293
1294	default:
1295		return (ENOTTY);
1296	}
1297
1298	return (0);
1299}
1300
1301static int
1302ccdsize(dev)
1303	dev_t dev;
1304{
1305	struct ccd_softc *cs;
1306	int part, size;
1307
1308	if (ccdopen(dev, 0, S_IFBLK, curproc))
1309		return (-1);
1310
1311	cs = &ccd_softc[ccdunit(dev)];
1312	part = ccdpart(dev);
1313
1314	if ((cs->sc_flags & CCDF_INITED) == 0)
1315		return (-1);
1316
1317	if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1318		size = -1;
1319	else
1320		size = cs->sc_label.d_partitions[part].p_size;
1321
1322	if (ccdclose(dev, 0, S_IFBLK, curproc))
1323		return (-1);
1324
1325	return (size);
1326}
1327
1328static int
1329ccddump(dev)
1330	dev_t dev;
1331{
1332
1333	/* Not implemented. */
1334	return ENXIO;
1335}
1336
1337/*
1338 * Lookup the provided name in the filesystem.  If the file exists,
1339 * is a valid block device, and isn't being used by anyone else,
1340 * set *vpp to the file's vnode.
1341 */
1342static int
1343ccdlookup(path, p, vpp)
1344	char *path;
1345	struct proc *p;
1346	struct vnode **vpp;	/* result */
1347{
1348	struct nameidata nd;
1349	struct vnode *vp;
1350	struct vattr va;
1351	int error;
1352
1353	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1354	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1355#ifdef DEBUG
1356		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1357			printf("ccdlookup: vn_open error = %d\n", error);
1358#endif
1359		return (error);
1360	}
1361	vp = nd.ni_vp;
1362
1363	if (vp->v_usecount > 1) {
1364		VOP_UNLOCK(vp, 0, p);
1365		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1366		return (EBUSY);
1367	}
1368
1369	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1370#ifdef DEBUG
1371		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1372			printf("ccdlookup: getattr error = %d\n", error);
1373#endif
1374		VOP_UNLOCK(vp, 0, p);
1375		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1376		return (error);
1377	}
1378
1379	/* XXX: eventually we should handle VREG, too. */
1380	if (va.va_type != VBLK) {
1381		VOP_UNLOCK(vp, 0, p);
1382		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1383		return (ENOTBLK);
1384	}
1385
1386#ifdef DEBUG
1387	if (ccddebug & CCDB_VNODE)
1388		vprint("ccdlookup: vnode info", vp);
1389#endif
1390
1391	VOP_UNLOCK(vp, 0, p);
1392	*vpp = vp;
1393	return (0);
1394}
1395
1396/*
1397 * Read the disklabel from the ccd.  If one is not present, fake one
1398 * up.
1399 */
1400static void
1401ccdgetdisklabel(dev)
1402	dev_t dev;
1403{
1404	int unit = ccdunit(dev);
1405	struct ccd_softc *cs = &ccd_softc[unit];
1406	char *errstring;
1407	struct disklabel *lp = &cs->sc_label;
1408	struct ccdgeom *ccg = &cs->sc_geom;
1409
1410	bzero(lp, sizeof(*lp));
1411
1412	lp->d_secperunit = cs->sc_size;
1413	lp->d_secsize = ccg->ccg_secsize;
1414	lp->d_nsectors = ccg->ccg_nsectors;
1415	lp->d_ntracks = ccg->ccg_ntracks;
1416	lp->d_ncylinders = ccg->ccg_ncylinders;
1417	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1418
1419	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1420	lp->d_type = DTYPE_CCD;
1421	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1422	lp->d_rpm = 3600;
1423	lp->d_interleave = 1;
1424	lp->d_flags = 0;
1425
1426	lp->d_partitions[RAW_PART].p_offset = 0;
1427	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1428	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1429	lp->d_npartitions = RAW_PART + 1;
1430
1431	lp->d_bbsize = BBSIZE;				/* XXX */
1432	lp->d_sbsize = SBSIZE;				/* XXX */
1433
1434	lp->d_magic = DISKMAGIC;
1435	lp->d_magic2 = DISKMAGIC;
1436	lp->d_checksum = dkcksum(&cs->sc_label);
1437
1438	/*
1439	 * Call the generic disklabel extraction routine.
1440	 */
1441	errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label);
1442	if (errstring != NULL)
1443		ccdmakedisklabel(cs);
1444
1445#ifdef DEBUG
1446	/* It's actually extremely common to have unlabeled ccds. */
1447	if (ccddebug & CCDB_LABEL)
1448		if (errstring != NULL)
1449			printf("ccd%d: %s\n", unit, errstring);
1450#endif
1451}
1452
1453/*
1454 * Take care of things one might want to take care of in the event
1455 * that a disklabel isn't present.
1456 */
1457static void
1458ccdmakedisklabel(cs)
1459	struct ccd_softc *cs;
1460{
1461	struct disklabel *lp = &cs->sc_label;
1462
1463	/*
1464	 * For historical reasons, if there's no disklabel present
1465	 * the raw partition must be marked FS_BSDFFS.
1466	 */
1467	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1468
1469	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1470}
1471
1472/*
1473 * Wait interruptibly for an exclusive lock.
1474 *
1475 * XXX
1476 * Several drivers do this; it should be abstracted and made MP-safe.
1477 */
1478static int
1479ccdlock(cs)
1480	struct ccd_softc *cs;
1481{
1482	int error;
1483
1484	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1485		cs->sc_flags |= CCDF_WANTED;
1486		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1487			return (error);
1488	}
1489	cs->sc_flags |= CCDF_LOCKED;
1490	return (0);
1491}
1492
1493/*
1494 * Unlock and wake up any waiters.
1495 */
1496static void
1497ccdunlock(cs)
1498	struct ccd_softc *cs;
1499{
1500
1501	cs->sc_flags &= ~CCDF_LOCKED;
1502	if ((cs->sc_flags & CCDF_WANTED) != 0) {
1503		cs->sc_flags &= ~CCDF_WANTED;
1504		wakeup(cs);
1505	}
1506}
1507
1508#ifdef DEBUG
1509static void
1510printiinfo(ii)
1511	struct ccdiinfo *ii;
1512{
1513	register int ix, i;
1514
1515	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1516		printf(" itab[%d]: #dk %d sblk %d soff %d",
1517		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1518		for (i = 0; i < ii->ii_ndisk; i++)
1519			printf(" %d", ii->ii_index[i]);
1520		printf("\n");
1521	}
1522}
1523#endif
1524
1525#endif /* NCCD > 0 */
1526
1527/* Local Variables: */
1528/* c-argdecl-indent: 8 */
1529/* c-continued-statement-offset: 8 */
1530/* c-indent-level: 8 */
1531/* End: */
1532