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