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