geom_ccd.c revision 48865
1/* $Id: ccd.c,v 1.49 1999/06/27 09:28:43 peter Exp $ */
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	struct vattr va;
310	size_t minsize;
311	int maxsecsize;
312	struct partinfo dpart;
313	struct ccdgeom *ccg = &cs->sc_geom;
314	char tmppath[MAXPATHLEN];
315	int error;
316
317#ifdef DEBUG
318	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
319		printf("ccdinit: unit %d\n", ccd->ccd_unit);
320#endif
321
322	cs->sc_size = 0;
323	cs->sc_ileave = ccd->ccd_interleave;
324	cs->sc_nccdisks = ccd->ccd_ndev;
325
326	/* Allocate space for the component info. */
327	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
328	    M_DEVBUF, M_WAITOK);
329
330	/*
331	 * Verify that each component piece exists and record
332	 * relevant information about it.
333	 */
334	maxsecsize = 0;
335	minsize = 0;
336	for (ix = 0; ix < cs->sc_nccdisks; ix++) {
337		vp = ccd->ccd_vpp[ix];
338		ci = &cs->sc_cinfo[ix];
339		ci->ci_vp = vp;
340
341		/*
342		 * Copy in the pathname of the component.
343		 */
344		bzero(tmppath, sizeof(tmppath));	/* sanity */
345		if ((error = copyinstr(cpaths[ix], tmppath,
346		    MAXPATHLEN, &ci->ci_pathlen)) != 0) {
347#ifdef DEBUG
348			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
349				printf("ccd%d: can't copy path, error = %d\n",
350				    ccd->ccd_unit, error);
351#endif
352			while (ci > cs->sc_cinfo) {
353				ci--;
354				free(ci->ci_path, M_DEVBUF);
355			}
356			free(cs->sc_cinfo, M_DEVBUF);
357			return (error);
358		}
359		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
360		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
361
362		/*
363		 * XXX: Cache the component's dev_t.
364		 */
365		if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
366#ifdef DEBUG
367			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
368				printf("ccd%d: %s: getattr failed %s = %d\n",
369				    ccd->ccd_unit, ci->ci_path,
370				    "error", error);
371#endif
372			while (ci >= cs->sc_cinfo) {
373				free(ci->ci_path, M_DEVBUF);
374				ci--;
375			}
376			free(cs->sc_cinfo, M_DEVBUF);
377			return (error);
378		}
379		ci->ci_dev = udev2dev(va.va_rdev, vp->v_type == VBLK ? 1 : 0);
380
381		/*
382		 * Get partition information for the component.
383		 */
384		if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
385		    FREAD, p->p_ucred, p)) != 0) {
386#ifdef DEBUG
387			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
388				 printf("ccd%d: %s: ioctl failed, error = %d\n",
389				     ccd->ccd_unit, ci->ci_path, error);
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 (error);
397		}
398		if (dpart.part->p_fstype == FS_BSDFFS) {
399			maxsecsize =
400			    ((dpart.disklab->d_secsize > maxsecsize) ?
401			    dpart.disklab->d_secsize : maxsecsize);
402			size = dpart.part->p_size - CCD_OFFSET;
403		} else {
404#ifdef DEBUG
405			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
406				printf("ccd%d: %s: incorrect partition type\n",
407				    ccd->ccd_unit, ci->ci_path);
408#endif
409			while (ci >= cs->sc_cinfo) {
410				free(ci->ci_path, M_DEVBUF);
411				ci--;
412			}
413			free(cs->sc_cinfo, M_DEVBUF);
414			return (EFTYPE);
415		}
416
417		/*
418		 * Calculate the size, truncating to an interleave
419		 * boundary if necessary.
420		 */
421
422		if (cs->sc_ileave > 1)
423			size -= size % cs->sc_ileave;
424
425		if (size == 0) {
426#ifdef DEBUG
427			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
428				printf("ccd%d: %s: size == 0\n",
429				    ccd->ccd_unit, ci->ci_path);
430#endif
431			while (ci >= cs->sc_cinfo) {
432				free(ci->ci_path, M_DEVBUF);
433				ci--;
434			}
435			free(cs->sc_cinfo, M_DEVBUF);
436			return (ENODEV);
437		}
438
439		if (minsize == 0 || size < minsize)
440			minsize = size;
441		ci->ci_size = size;
442		cs->sc_size += size;
443	}
444
445	/*
446	 * Don't allow the interleave to be smaller than
447	 * the biggest component sector.
448	 */
449	if ((cs->sc_ileave > 0) &&
450	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
451#ifdef DEBUG
452		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
453			printf("ccd%d: interleave must be at least %d\n",
454			    ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
455#endif
456		while (ci >= cs->sc_cinfo) {
457			free(ci->ci_path, M_DEVBUF);
458			ci--;
459		}
460		free(cs->sc_cinfo, M_DEVBUF);
461		return (EINVAL);
462	}
463
464	/*
465	 * If uniform interleave is desired set all sizes to that of
466	 * the smallest component.
467	 */
468	if (ccd->ccd_flags & CCDF_UNIFORM) {
469		for (ci = cs->sc_cinfo;
470		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
471			ci->ci_size = minsize;
472		if (ccd->ccd_flags & CCDF_MIRROR) {
473			/*
474			 * Check to see if an even number of components
475			 * have been specified.
476			 */
477			if (cs->sc_nccdisks % 2) {
478				printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
479				while (ci > cs->sc_cinfo) {
480					ci--;
481					free(ci->ci_path, M_DEVBUF);
482				}
483				free(cs->sc_cinfo, M_DEVBUF);
484				return (EINVAL);
485			}
486			cs->sc_size = (cs->sc_nccdisks/2) * minsize;
487		}
488		else if (ccd->ccd_flags & CCDF_PARITY)
489			cs->sc_size = (cs->sc_nccdisks-1) * minsize;
490		else
491			cs->sc_size = cs->sc_nccdisks * minsize;
492	}
493
494	/*
495	 * Construct the interleave table.
496	 */
497	ccdinterleave(cs, ccd->ccd_unit);
498
499	/*
500	 * Create pseudo-geometry based on 1MB cylinders.  It's
501	 * pretty close.
502	 */
503	ccg->ccg_secsize = maxsecsize;
504	ccg->ccg_ntracks = 1;
505	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
506	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
507
508	/*
509	 * Add an devstat entry for this device.
510	 */
511	devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
512			  ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
513			  DEVSTAT_TYPE_ASC0 |DEVSTAT_TYPE_IF_OTHER,
514			  DEVSTAT_PRIORITY_CCD);
515
516	cs->sc_flags |= CCDF_INITED;
517	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */
518	cs->sc_unit = ccd->ccd_unit;
519	return (0);
520}
521
522static void
523ccdinterleave(cs, unit)
524	register struct ccd_softc *cs;
525	int unit;
526{
527	register struct ccdcinfo *ci, *smallci;
528	register struct ccdiinfo *ii;
529	register daddr_t bn, lbn;
530	register int ix;
531	u_long size;
532
533#ifdef DEBUG
534	if (ccddebug & CCDB_INIT)
535		printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
536#endif
537	/*
538	 * Allocate an interleave table.
539	 * Chances are this is too big, but we don't care.
540	 */
541	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
542	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
543	bzero((caddr_t)cs->sc_itable, size);
544
545	/*
546	 * Trivial case: no interleave (actually interleave of disk size).
547	 * Each table entry represents a single component in its entirety.
548	 */
549	if (cs->sc_ileave == 0) {
550		bn = 0;
551		ii = cs->sc_itable;
552
553		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
554			/* Allocate space for ii_index. */
555			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
556			ii->ii_ndisk = 1;
557			ii->ii_startblk = bn;
558			ii->ii_startoff = 0;
559			ii->ii_index[0] = ix;
560			bn += cs->sc_cinfo[ix].ci_size;
561			ii++;
562		}
563		ii->ii_ndisk = 0;
564#ifdef DEBUG
565		if (ccddebug & CCDB_INIT)
566			printiinfo(cs->sc_itable);
567#endif
568		return;
569	}
570
571	/*
572	 * The following isn't fast or pretty; it doesn't have to be.
573	 */
574	size = 0;
575	bn = lbn = 0;
576	for (ii = cs->sc_itable; ; ii++) {
577		/* Allocate space for ii_index. */
578		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
579		    M_DEVBUF, M_WAITOK);
580
581		/*
582		 * Locate the smallest of the remaining components
583		 */
584		smallci = NULL;
585		for (ci = cs->sc_cinfo;
586		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
587			if (ci->ci_size > size &&
588			    (smallci == NULL ||
589			     ci->ci_size < smallci->ci_size))
590				smallci = ci;
591
592		/*
593		 * Nobody left, all done
594		 */
595		if (smallci == NULL) {
596			ii->ii_ndisk = 0;
597			break;
598		}
599
600		/*
601		 * Record starting logical block and component offset
602		 */
603		ii->ii_startblk = bn / cs->sc_ileave;
604		ii->ii_startoff = lbn;
605
606		/*
607		 * Determine how many disks take part in this interleave
608		 * and record their indices.
609		 */
610		ix = 0;
611		for (ci = cs->sc_cinfo;
612		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
613			if (ci->ci_size >= smallci->ci_size)
614				ii->ii_index[ix++] = ci - cs->sc_cinfo;
615		ii->ii_ndisk = ix;
616		bn += ix * (smallci->ci_size - size);
617		lbn = smallci->ci_size / cs->sc_ileave;
618		size = smallci->ci_size;
619	}
620#ifdef DEBUG
621	if (ccddebug & CCDB_INIT)
622		printiinfo(cs->sc_itable);
623#endif
624}
625
626/* ARGSUSED */
627static int
628ccdopen(dev, flags, fmt, p)
629	dev_t dev;
630	int flags, fmt;
631	struct proc *p;
632{
633	int unit = ccdunit(dev);
634	struct ccd_softc *cs;
635	struct disklabel *lp;
636	int error = 0, part, pmask;
637
638#ifdef DEBUG
639	if (ccddebug & CCDB_FOLLOW)
640		printf("ccdopen(%x, %x)\n", dev, flags);
641#endif
642	if (unit >= numccd)
643		return (ENXIO);
644	cs = &ccd_softc[unit];
645
646	if ((error = ccdlock(cs)) != 0)
647		return (error);
648
649	lp = &cs->sc_label;
650
651	part = ccdpart(dev);
652	pmask = (1 << part);
653
654	/*
655	 * If we're initialized, check to see if there are any other
656	 * open partitions.  If not, then it's safe to update
657	 * the in-core disklabel.
658	 */
659	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
660		ccdgetdisklabel(dev);
661
662	/* Check that the partition exists. */
663	if (part != RAW_PART && ((part >= lp->d_npartitions) ||
664	    (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
665		error = ENXIO;
666		goto done;
667	}
668
669	/* Prevent our unit from being unconfigured while open. */
670	switch (fmt) {
671	case S_IFCHR:
672		cs->sc_copenmask |= pmask;
673		break;
674
675	case S_IFBLK:
676		cs->sc_bopenmask |= pmask;
677		break;
678	}
679	cs->sc_openmask =
680	    cs->sc_copenmask | cs->sc_bopenmask;
681
682 done:
683	ccdunlock(cs);
684	return (0);
685}
686
687/* ARGSUSED */
688static int
689ccdclose(dev, flags, fmt, p)
690	dev_t dev;
691	int flags, fmt;
692	struct proc *p;
693{
694	int unit = ccdunit(dev);
695	struct ccd_softc *cs;
696	int error = 0, part;
697
698#ifdef DEBUG
699	if (ccddebug & CCDB_FOLLOW)
700		printf("ccdclose(%x, %x)\n", dev, flags);
701#endif
702
703	if (unit >= numccd)
704		return (ENXIO);
705	cs = &ccd_softc[unit];
706
707	if ((error = ccdlock(cs)) != 0)
708		return (error);
709
710	part = ccdpart(dev);
711
712	/* ...that much closer to allowing unconfiguration... */
713	switch (fmt) {
714	case S_IFCHR:
715		cs->sc_copenmask &= ~(1 << part);
716		break;
717
718	case S_IFBLK:
719		cs->sc_bopenmask &= ~(1 << part);
720		break;
721	}
722	cs->sc_openmask =
723	    cs->sc_copenmask | cs->sc_bopenmask;
724
725	ccdunlock(cs);
726	return (0);
727}
728
729static void
730ccdstrategy(bp)
731	register struct buf *bp;
732{
733	register int unit = ccdunit(bp->b_dev);
734	register struct ccd_softc *cs = &ccd_softc[unit];
735	register int s;
736	int wlabel;
737	struct disklabel *lp;
738
739#ifdef DEBUG
740	if (ccddebug & CCDB_FOLLOW)
741		printf("ccdstrategy(%x): unit %d\n", bp, unit);
742#endif
743	if ((cs->sc_flags & CCDF_INITED) == 0) {
744		bp->b_error = ENXIO;
745		bp->b_flags |= B_ERROR;
746		goto done;
747	}
748
749	/* If it's a nil transfer, wake up the top half now. */
750	if (bp->b_bcount == 0)
751		goto done;
752
753	lp = &cs->sc_label;
754
755	/*
756	 * Do bounds checking and adjust transfer.  If there's an
757	 * error, the bounds check will flag that for us.
758	 */
759	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
760	if (ccdpart(bp->b_dev) != RAW_PART)
761		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
762			goto done;
763
764	bp->b_resid = bp->b_bcount;
765
766	/*
767	 * "Start" the unit.
768	 */
769	s = splbio();
770	ccdstart(cs, bp);
771	splx(s);
772	return;
773done:
774	biodone(bp);
775}
776
777static void
778ccdstart(cs, bp)
779	register struct ccd_softc *cs;
780	register struct buf *bp;
781{
782	register long bcount, rcount;
783	struct ccdbuf *cbp[4];
784	/* XXX! : 2 reads and 2 writes for RAID 4/5 */
785	caddr_t addr;
786	daddr_t bn;
787	struct partition *pp;
788
789#ifdef DEBUG
790	if (ccddebug & CCDB_FOLLOW)
791		printf("ccdstart(%x, %x)\n", cs, bp);
792#endif
793
794	/* Record the transaction start  */
795	devstat_start_transaction(&cs->device_stats);
796
797	/*
798	 * Translate the partition-relative block number to an absolute.
799	 */
800	bn = bp->b_blkno;
801	if (ccdpart(bp->b_dev) != RAW_PART) {
802		pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)];
803		bn += pp->p_offset;
804	}
805
806	/*
807	 * Allocate component buffers and fire off the requests
808	 */
809	addr = bp->b_data;
810	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
811		ccdbuffer(cbp, cs, bp, bn, addr, bcount);
812		rcount = cbp[0]->cb_buf.b_bcount;
813		if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
814			cbp[0]->cb_buf.b_vp->v_numoutput++;
815		VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf);
816		if (cs->sc_cflags & CCDF_MIRROR &&
817		    (cbp[0]->cb_buf.b_flags & B_READ) == 0) {
818			/* mirror, start another write */
819			cbp[1]->cb_buf.b_vp->v_numoutput++;
820			VOP_STRATEGY(cbp[1]->cb_buf.b_vp, &cbp[1]->cb_buf);
821		}
822		bn += btodb(rcount);
823		addr += rcount;
824	}
825}
826
827/*
828 * Build a component buffer header.
829 */
830static void
831ccdbuffer(cb, cs, bp, bn, addr, bcount)
832	register struct ccdbuf **cb;
833	register struct ccd_softc *cs;
834	struct buf *bp;
835	daddr_t bn;
836	caddr_t addr;
837	long bcount;
838{
839	register struct ccdcinfo *ci, *ci2 = NULL;	/* XXX */
840	register struct ccdbuf *cbp;
841	register daddr_t cbn, cboff;
842      register off_t cbc;
843
844#ifdef DEBUG
845	if (ccddebug & CCDB_IO)
846		printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
847		       cs, bp, bn, addr, bcount);
848#endif
849	/*
850	 * Determine which component bn falls in.
851	 */
852	cbn = bn;
853	cboff = 0;
854
855	/*
856	 * Serially concatenated
857	 */
858	if (cs->sc_ileave == 0) {
859		register daddr_t sblk;
860
861		sblk = 0;
862		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
863			sblk += ci->ci_size;
864		cbn -= sblk;
865	}
866	/*
867	 * Interleaved
868	 */
869	else {
870		register struct ccdiinfo *ii;
871		int ccdisk, off;
872
873		cboff = cbn % cs->sc_ileave;
874		cbn /= cs->sc_ileave;
875		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
876			if (ii->ii_startblk > cbn)
877				break;
878		ii--;
879		off = cbn - ii->ii_startblk;
880		if (ii->ii_ndisk == 1) {
881			ccdisk = ii->ii_index[0];
882			cbn = ii->ii_startoff + off;
883		} else {
884			if (cs->sc_cflags & CCDF_MIRROR) {
885				ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)];
886				cbn = ii->ii_startoff + off / (ii->ii_ndisk/2);
887				/* mirrored data */
888				ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2];
889			}
890			else if (cs->sc_cflags & CCDF_PARITY) {
891				ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)];
892				cbn = ii->ii_startoff + off / (ii->ii_ndisk-1);
893				if (cbn % ii->ii_ndisk <= ccdisk)
894					ccdisk++;
895			}
896			else {
897				ccdisk = ii->ii_index[off % ii->ii_ndisk];
898				cbn = ii->ii_startoff + off / ii->ii_ndisk;
899			}
900		}
901		cbn *= cs->sc_ileave;
902		ci = &cs->sc_cinfo[ccdisk];
903	}
904
905	/*
906	 * Fill in the component buf structure.
907	 */
908	cbp = getccdbuf();
909	bzero(cbp, sizeof (struct ccdbuf));
910	cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
911	cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone;
912	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */
913	cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET;
914	cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET);
915	cbp->cb_buf.b_data = addr;
916	cbp->cb_buf.b_vp = ci->ci_vp;
917	LIST_INIT(&cbp->cb_buf.b_dep);
918	BUF_LOCKINIT(&cbp->cb_buf);
919	BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
920	cbp->cb_buf.b_resid = 0;
921	if (cs->sc_ileave == 0)
922              cbc = dbtob((off_t)(ci->ci_size - cbn));
923	else
924              cbc = dbtob((off_t)(cs->sc_ileave - cboff));
925	cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
926 	cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
927
928	/*
929	 * context for ccdiodone
930	 */
931	cbp->cb_obp = bp;
932	cbp->cb_unit = cs - ccd_softc;
933	cbp->cb_comp = ci - cs->sc_cinfo;
934
935#ifdef DEBUG
936	if (ccddebug & CCDB_IO)
937		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
938		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
939		       cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
940#endif
941	cb[0] = cbp;
942	if (cs->sc_cflags & CCDF_MIRROR &&
943	    (cbp->cb_buf.b_flags & B_READ) == 0) {
944		/* mirror, start one more write */
945		cbp = getccdbuf();
946		bzero(cbp, sizeof (struct ccdbuf));
947		*cbp = *cb[0];
948		cbp->cb_buf.b_dev = ci2->ci_dev;
949		cbp->cb_buf.b_vp = ci2->ci_vp;
950		LIST_INIT(&cbp->cb_buf.b_dep);
951		BUF_LOCKINIT(&cbp->cb_buf);
952		BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
953		cbp->cb_comp = ci2 - cs->sc_cinfo;
954		cb[1] = cbp;
955		/* link together the ccdbuf's and clear "mirror done" flag */
956		cb[0]->cb_mirror = cb[1];
957		cb[1]->cb_mirror = cb[0];
958		cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
959		cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
960	}
961}
962
963static void
964ccdintr(cs, bp)
965	register struct ccd_softc *cs;
966	register struct buf *bp;
967{
968#ifdef DEBUG
969	if (ccddebug & CCDB_FOLLOW)
970		printf("ccdintr(%x, %x)\n", cs, bp);
971#endif
972	/*
973	 * Request is done for better or worse, wakeup the top half.
974	 */
975	/* Record device statistics */
976	devstat_end_transaction(&cs->device_stats,
977				bp->b_bcount - bp->b_resid,
978				(bp->b_flags & B_ORDERED) ?
979				DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE,
980				(bp->b_flags & B_READ) ? DEVSTAT_READ :
981				DEVSTAT_WRITE);
982
983	if (bp->b_flags & B_ERROR)
984		bp->b_resid = bp->b_bcount;
985	biodone(bp);
986}
987
988/*
989 * Called at interrupt time.
990 * Mark the component as done and if all components are done,
991 * take a ccd interrupt.
992 */
993static void
994ccdiodone(cbp)
995	struct ccdbuf *cbp;
996{
997	register struct buf *bp = cbp->cb_obp;
998	register int unit = cbp->cb_unit;
999	int count, s;
1000
1001	s = splbio();
1002#ifdef DEBUG
1003	if (ccddebug & CCDB_FOLLOW)
1004		printf("ccdiodone(%x)\n", cbp);
1005	if (ccddebug & CCDB_IO) {
1006		printf("ccdiodone: bp %x bcount %d resid %d\n",
1007		       bp, bp->b_bcount, bp->b_resid);
1008		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1009		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1010		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1011		       cbp->cb_buf.b_bcount);
1012	}
1013#endif
1014
1015	if (cbp->cb_buf.b_flags & B_ERROR) {
1016		bp->b_flags |= B_ERROR;
1017		bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1018#ifdef DEBUG
1019		printf("ccd%d: error %d on component %d\n",
1020		       unit, bp->b_error, cbp->cb_comp);
1021#endif
1022	}
1023
1024	if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1025	    (cbp->cb_buf.b_flags & B_READ) == 0)
1026		if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1027			/* I'm done before my counterpart, so just set
1028			   partner's flag and return */
1029			cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1030			putccdbuf(cbp);
1031			splx(s);
1032			return;
1033		}
1034
1035	count = cbp->cb_buf.b_bcount;
1036	putccdbuf(cbp);
1037
1038	/*
1039	 * If all done, "interrupt".
1040	 */
1041	bp->b_resid -= count;
1042	if (bp->b_resid < 0)
1043		panic("ccdiodone: count");
1044	if (bp->b_resid == 0)
1045		ccdintr(&ccd_softc[unit], bp);
1046	splx(s);
1047}
1048
1049static int
1050ccdioctl(dev, cmd, data, flag, p)
1051	dev_t dev;
1052	u_long cmd;
1053	caddr_t data;
1054	int flag;
1055	struct proc *p;
1056{
1057	int unit = ccdunit(dev);
1058	int i, j, lookedup = 0, error = 0;
1059	int part, pmask, s;
1060	struct ccd_softc *cs;
1061	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1062	struct ccddevice ccd;
1063	char **cpp;
1064	struct vnode **vpp;
1065
1066	if (unit >= numccd)
1067		return (ENXIO);
1068	cs = &ccd_softc[unit];
1069
1070	bzero(&ccd, sizeof(ccd));
1071
1072	switch (cmd) {
1073	case CCDIOCSET:
1074		if (cs->sc_flags & CCDF_INITED)
1075			return (EBUSY);
1076
1077		if ((flag & FWRITE) == 0)
1078			return (EBADF);
1079
1080		if ((error = ccdlock(cs)) != 0)
1081			return (error);
1082
1083		/* Fill in some important bits. */
1084		ccd.ccd_unit = unit;
1085		ccd.ccd_interleave = ccio->ccio_ileave;
1086		if (ccd.ccd_interleave == 0 &&
1087		    ((ccio->ccio_flags & CCDF_MIRROR) ||
1088		     (ccio->ccio_flags & CCDF_PARITY))) {
1089			printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1090			ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1091		}
1092		if ((ccio->ccio_flags & CCDF_MIRROR) &&
1093		    (ccio->ccio_flags & CCDF_PARITY)) {
1094			printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1095			ccio->ccio_flags &= ~CCDF_PARITY;
1096		}
1097		if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1098		    !(ccio->ccio_flags & CCDF_UNIFORM)) {
1099			printf("ccd%d: mirror/parity forces uniform flag\n",
1100			       unit);
1101			ccio->ccio_flags |= CCDF_UNIFORM;
1102		}
1103		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1104
1105		/*
1106		 * Allocate space for and copy in the array of
1107		 * componet pathnames and device numbers.
1108		 */
1109		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1110		    M_DEVBUF, M_WAITOK);
1111		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1112		    M_DEVBUF, M_WAITOK);
1113
1114		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1115		    ccio->ccio_ndisks * sizeof(char **));
1116		if (error) {
1117			free(vpp, M_DEVBUF);
1118			free(cpp, M_DEVBUF);
1119			ccdunlock(cs);
1120			return (error);
1121		}
1122
1123#ifdef DEBUG
1124		if (ccddebug & CCDB_INIT)
1125			for (i = 0; i < ccio->ccio_ndisks; ++i)
1126				printf("ccdioctl: component %d: 0x%x\n",
1127				    i, cpp[i]);
1128#endif
1129
1130		for (i = 0; i < ccio->ccio_ndisks; ++i) {
1131#ifdef DEBUG
1132			if (ccddebug & CCDB_INIT)
1133				printf("ccdioctl: lookedup = %d\n", lookedup);
1134#endif
1135			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1136				for (j = 0; j < lookedup; ++j)
1137					(void)vn_close(vpp[j], FREAD|FWRITE,
1138					    p->p_ucred, p);
1139				free(vpp, M_DEVBUF);
1140				free(cpp, M_DEVBUF);
1141				ccdunlock(cs);
1142				return (error);
1143			}
1144			++lookedup;
1145		}
1146		ccd.ccd_cpp = cpp;
1147		ccd.ccd_vpp = vpp;
1148		ccd.ccd_ndev = ccio->ccio_ndisks;
1149
1150		/*
1151		 * Initialize the ccd.  Fills in the softc for us.
1152		 */
1153		if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1154			for (j = 0; j < lookedup; ++j)
1155				(void)vn_close(vpp[j], FREAD|FWRITE,
1156				    p->p_ucred, p);
1157			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1158			free(vpp, M_DEVBUF);
1159			free(cpp, M_DEVBUF);
1160			ccdunlock(cs);
1161			return (error);
1162		}
1163
1164		/*
1165		 * The ccd has been successfully initialized, so
1166		 * we can place it into the array and read the disklabel.
1167		 */
1168		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1169		ccio->ccio_unit = unit;
1170		ccio->ccio_size = cs->sc_size;
1171		ccdgetdisklabel(dev);
1172
1173		ccdunlock(cs);
1174
1175		break;
1176
1177	case CCDIOCCLR:
1178		if ((cs->sc_flags & CCDF_INITED) == 0)
1179			return (ENXIO);
1180
1181		if ((flag & FWRITE) == 0)
1182			return (EBADF);
1183
1184		if ((error = ccdlock(cs)) != 0)
1185			return (error);
1186
1187		/*
1188		 * Don't unconfigure if any other partitions are open
1189		 * or if both the character and block flavors of this
1190		 * partition are open.
1191		 */
1192		part = ccdpart(dev);
1193		pmask = (1 << part);
1194		if ((cs->sc_openmask & ~pmask) ||
1195		    ((cs->sc_bopenmask & pmask) &&
1196		    (cs->sc_copenmask & pmask))) {
1197			ccdunlock(cs);
1198			return (EBUSY);
1199		}
1200
1201		/*
1202		 * Free ccd_softc information and clear entry.
1203		 */
1204
1205		/* Close the components and free their pathnames. */
1206		for (i = 0; i < cs->sc_nccdisks; ++i) {
1207			/*
1208			 * XXX: this close could potentially fail and
1209			 * cause Bad Things.  Maybe we need to force
1210			 * the close to happen?
1211			 */
1212#ifdef DEBUG
1213			if (ccddebug & CCDB_VNODE)
1214				vprint("CCDIOCCLR: vnode info",
1215				    cs->sc_cinfo[i].ci_vp);
1216#endif
1217			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1218			    p->p_ucred, p);
1219			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1220		}
1221
1222		/* Free interleave index. */
1223		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1224			free(cs->sc_itable[i].ii_index, M_DEVBUF);
1225
1226		/* Free component info and interleave table. */
1227		free(cs->sc_cinfo, M_DEVBUF);
1228		free(cs->sc_itable, M_DEVBUF);
1229		cs->sc_flags &= ~CCDF_INITED;
1230
1231		/*
1232		 * Free ccddevice information and clear entry.
1233		 */
1234		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1235		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1236		ccd.ccd_dk = -1;
1237		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1238
1239		/*
1240		 * And remove the devstat entry.
1241		 */
1242		devstat_remove_entry(&cs->device_stats);
1243
1244		/* This must be atomic. */
1245		s = splhigh();
1246		ccdunlock(cs);
1247		bzero(cs, sizeof(struct ccd_softc));
1248		splx(s);
1249
1250		break;
1251
1252	case DIOCGDINFO:
1253		if ((cs->sc_flags & CCDF_INITED) == 0)
1254			return (ENXIO);
1255
1256		*(struct disklabel *)data = cs->sc_label;
1257		break;
1258
1259	case DIOCGPART:
1260		if ((cs->sc_flags & CCDF_INITED) == 0)
1261			return (ENXIO);
1262
1263		((struct partinfo *)data)->disklab = &cs->sc_label;
1264		((struct partinfo *)data)->part =
1265		    &cs->sc_label.d_partitions[ccdpart(dev)];
1266		break;
1267
1268	case DIOCWDINFO:
1269	case DIOCSDINFO:
1270		if ((cs->sc_flags & CCDF_INITED) == 0)
1271			return (ENXIO);
1272
1273		if ((flag & FWRITE) == 0)
1274			return (EBADF);
1275
1276		if ((error = ccdlock(cs)) != 0)
1277			return (error);
1278
1279		cs->sc_flags |= CCDF_LABELLING;
1280
1281		error = setdisklabel(&cs->sc_label,
1282		    (struct disklabel *)data, 0);
1283		if (error == 0) {
1284			if (cmd == DIOCWDINFO)
1285				error = writedisklabel(CCDLABELDEV(dev),
1286				    ccdstrategy, &cs->sc_label);
1287		}
1288
1289		cs->sc_flags &= ~CCDF_LABELLING;
1290
1291		ccdunlock(cs);
1292
1293		if (error)
1294			return (error);
1295		break;
1296
1297	case DIOCWLABEL:
1298		if ((cs->sc_flags & CCDF_INITED) == 0)
1299			return (ENXIO);
1300
1301		if ((flag & FWRITE) == 0)
1302			return (EBADF);
1303		if (*(int *)data != 0)
1304			cs->sc_flags |= CCDF_WLABEL;
1305		else
1306			cs->sc_flags &= ~CCDF_WLABEL;
1307		break;
1308
1309	default:
1310		return (ENOTTY);
1311	}
1312
1313	return (0);
1314}
1315
1316static int
1317ccdsize(dev)
1318	dev_t dev;
1319{
1320	struct ccd_softc *cs;
1321	int part, size;
1322
1323	if (ccdopen(dev, 0, S_IFBLK, curproc))
1324		return (-1);
1325
1326	cs = &ccd_softc[ccdunit(dev)];
1327	part = ccdpart(dev);
1328
1329	if ((cs->sc_flags & CCDF_INITED) == 0)
1330		return (-1);
1331
1332	if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1333		size = -1;
1334	else
1335		size = cs->sc_label.d_partitions[part].p_size;
1336
1337	if (ccdclose(dev, 0, S_IFBLK, curproc))
1338		return (-1);
1339
1340	return (size);
1341}
1342
1343static int
1344ccddump(dev)
1345	dev_t dev;
1346{
1347
1348	/* Not implemented. */
1349	return ENXIO;
1350}
1351
1352/*
1353 * Lookup the provided name in the filesystem.  If the file exists,
1354 * is a valid block device, and isn't being used by anyone else,
1355 * set *vpp to the file's vnode.
1356 */
1357static int
1358ccdlookup(path, p, vpp)
1359	char *path;
1360	struct proc *p;
1361	struct vnode **vpp;	/* result */
1362{
1363	struct nameidata nd;
1364	struct vnode *vp;
1365	struct vattr va;
1366	int error;
1367
1368	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1369	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1370#ifdef DEBUG
1371		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1372			printf("ccdlookup: vn_open error = %d\n", error);
1373#endif
1374		return (error);
1375	}
1376	vp = nd.ni_vp;
1377
1378	if (vp->v_usecount > 1) {
1379		VOP_UNLOCK(vp, 0, p);
1380		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1381		return (EBUSY);
1382	}
1383
1384	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1385#ifdef DEBUG
1386		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1387			printf("ccdlookup: getattr error = %d\n", error);
1388#endif
1389		VOP_UNLOCK(vp, 0, p);
1390		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1391		return (error);
1392	}
1393
1394	/* XXX: eventually we should handle VREG, too. */
1395	if (va.va_type != VBLK) {
1396		VOP_UNLOCK(vp, 0, p);
1397		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1398		return (ENOTBLK);
1399	}
1400
1401#ifdef DEBUG
1402	if (ccddebug & CCDB_VNODE)
1403		vprint("ccdlookup: vnode info", vp);
1404#endif
1405
1406	VOP_UNLOCK(vp, 0, p);
1407	*vpp = vp;
1408	return (0);
1409}
1410
1411/*
1412 * Read the disklabel from the ccd.  If one is not present, fake one
1413 * up.
1414 */
1415static void
1416ccdgetdisklabel(dev)
1417	dev_t dev;
1418{
1419	int unit = ccdunit(dev);
1420	struct ccd_softc *cs = &ccd_softc[unit];
1421	char *errstring;
1422	struct disklabel *lp = &cs->sc_label;
1423	struct ccdgeom *ccg = &cs->sc_geom;
1424
1425	bzero(lp, sizeof(*lp));
1426
1427	lp->d_secperunit = cs->sc_size;
1428	lp->d_secsize = ccg->ccg_secsize;
1429	lp->d_nsectors = ccg->ccg_nsectors;
1430	lp->d_ntracks = ccg->ccg_ntracks;
1431	lp->d_ncylinders = ccg->ccg_ncylinders;
1432	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1433
1434	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1435	lp->d_type = DTYPE_CCD;
1436	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1437	lp->d_rpm = 3600;
1438	lp->d_interleave = 1;
1439	lp->d_flags = 0;
1440
1441	lp->d_partitions[RAW_PART].p_offset = 0;
1442	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1443	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1444	lp->d_npartitions = RAW_PART + 1;
1445
1446	lp->d_bbsize = BBSIZE;				/* XXX */
1447	lp->d_sbsize = SBSIZE;				/* XXX */
1448
1449	lp->d_magic = DISKMAGIC;
1450	lp->d_magic2 = DISKMAGIC;
1451	lp->d_checksum = dkcksum(&cs->sc_label);
1452
1453	/*
1454	 * Call the generic disklabel extraction routine.
1455	 */
1456	if ((errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1457	    &cs->sc_label)) != NULL)
1458		ccdmakedisklabel(cs);
1459
1460#ifdef DEBUG
1461	/* It's actually extremely common to have unlabeled ccds. */
1462	if (ccddebug & CCDB_LABEL)
1463		if (errstring != NULL)
1464			printf("ccd%d: %s\n", unit, errstring);
1465#endif
1466}
1467
1468/*
1469 * Take care of things one might want to take care of in the event
1470 * that a disklabel isn't present.
1471 */
1472static void
1473ccdmakedisklabel(cs)
1474	struct ccd_softc *cs;
1475{
1476	struct disklabel *lp = &cs->sc_label;
1477
1478	/*
1479	 * For historical reasons, if there's no disklabel present
1480	 * the raw partition must be marked FS_BSDFFS.
1481	 */
1482	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1483
1484	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1485}
1486
1487/*
1488 * Wait interruptibly for an exclusive lock.
1489 *
1490 * XXX
1491 * Several drivers do this; it should be abstracted and made MP-safe.
1492 */
1493static int
1494ccdlock(cs)
1495	struct ccd_softc *cs;
1496{
1497	int error;
1498
1499	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1500		cs->sc_flags |= CCDF_WANTED;
1501		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1502			return (error);
1503	}
1504	cs->sc_flags |= CCDF_LOCKED;
1505	return (0);
1506}
1507
1508/*
1509 * Unlock and wake up any waiters.
1510 */
1511static void
1512ccdunlock(cs)
1513	struct ccd_softc *cs;
1514{
1515
1516	cs->sc_flags &= ~CCDF_LOCKED;
1517	if ((cs->sc_flags & CCDF_WANTED) != 0) {
1518		cs->sc_flags &= ~CCDF_WANTED;
1519		wakeup(cs);
1520	}
1521}
1522
1523#ifdef DEBUG
1524static void
1525printiinfo(ii)
1526	struct ccdiinfo *ii;
1527{
1528	register int ix, i;
1529
1530	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1531		printf(" itab[%d]: #dk %d sblk %d soff %d",
1532		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1533		for (i = 0; i < ii->ii_ndisk; i++)
1534			printf(" %d", ii->ii_index[i]);
1535		printf("\n");
1536	}
1537}
1538#endif
1539
1540#endif /* NCCD > 0 */
1541
1542/* Local Variables: */
1543/* c-argdecl-indent: 8 */
1544/* c-continued-statement-offset: 8 */
1545/* c-indent-level: 8 */
1546/* End: */
1547