ccdinterleave(cs, ccd->ccd_unit);
ccdinterleave(cs);
ccdinit(ccd, cpaths, p)	struct ccddevice *ccd;	char **cpaths;	struct proc *p;{	struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];	struct ccdcinfo *ci = NULL;	size_t size;	int ix;	struct vnode *vp;	struct vattr va;	size_t minsize;	int maxsecsize;	struct partinfo dpart;	struct ccdgeom *ccg = &cs->sc_geom;	char tmppath[MAXPATHLEN];	int error;#ifdef DEBUG	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))		printf("ccdinit: unit %d\n", ccd->ccd_unit);#endif	cs->sc_size = 0;	cs->sc_ileave = ccd->ccd_interleave;	cs->sc_nccdisks = ccd->ccd_ndev;	if (snprintf(cs->sc_xname, sizeof(cs->sc_xname), "ccd%d",	    ccd->ccd_unit) >= sizeof(cs->sc_xname)) {		printf("ccdinit: device name too long.\n");		return(ENXIO);	}	/* Allocate space for the component info. */	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),	    M_DEVBUF, M_WAITOK);	/*	 * Verify that each component piece exists and record	 * relevant information about it.	 */	maxsecsize = 0;	minsize = 0;	for (ix = 0; ix < cs->sc_nccdisks; ix++) {		vp = ccd->ccd_vpp[ix];		ci = &cs->sc_cinfo[ix];		ci->ci_vp = vp;		/*		 * Copy in the pathname of the component.		 */		bzero(tmppath, sizeof(tmppath));	/* sanity */		error = copyinstr(cpaths[ix], tmppath,		    MAXPATHLEN, &ci->ci_pathlen);		if (error) {#ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))				printf("%s: can't copy path, error = %d\n",				    cs->sc_xname, error);#endif			free(cs->sc_cinfo, M_DEVBUF);			return (error);		}		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);		/*		 * XXX: Cache the component's dev_t.		 */		if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {#ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))				printf("%s: %s: getattr failed %s = %d\n",				    cs->sc_xname, ci->ci_path,				    "error", error);#endif			free(ci->ci_path, M_DEVBUF);			free(cs->sc_cinfo, M_DEVBUF);			return (error);		}		ci->ci_dev = va.va_rdev;		/*		 * Get partition information for the component.		 */		error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,		    FREAD, p->p_ucred, p);		if (error) {#ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))				 printf("%s: %s: ioctl failed, error = %d\n",				     cs->sc_xname, ci->ci_path, error);#endif			free(ci->ci_path, M_DEVBUF);			free(cs->sc_cinfo, M_DEVBUF);			return (error);		}		if (dpart.part->p_fstype == FS_CCD ||		    dpart.part->p_fstype == FS_BSDFFS) {			maxsecsize =			    ((dpart.disklab->d_secsize > maxsecsize) ?			    dpart.disklab->d_secsize : maxsecsize);			size = dpart.part->p_size;		} else {#ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))				printf("%s: %s: incorrect partition type\n",				    cs->sc_xname, ci->ci_path);#endif			free(ci->ci_path, M_DEVBUF);			free(cs->sc_cinfo, M_DEVBUF);			return (EFTYPE);		}		/*		 * Calculate the size, truncating to an interleave		 * boundary if necessary.		 */		if (cs->sc_ileave > 1)			size -= size % cs->sc_ileave;		if (size == 0) {#ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))				printf("%s: %s: size == 0\n",				    cs->sc_xname, ci->ci_path);#endif			free(ci->ci_path, M_DEVBUF);			free(cs->sc_cinfo, M_DEVBUF);			return (ENODEV);		}		if (minsize == 0 || size < minsize)			minsize = size;		ci->ci_size = size;		cs->sc_size += size;	}	/*	 * Don't allow the interleave to be smaller than	 * the biggest component sector.	 */	if ((cs->sc_ileave > 0) &&	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {#ifdef DEBUG		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))			printf("%s: interleave must be at least %d\n",			    cs->sc_xname, (maxsecsize / DEV_BSIZE));#endif		free(ci->ci_path, M_DEVBUF);		free(cs->sc_cinfo, M_DEVBUF);		return (EINVAL);	}	/*	 * Mirroring support requires uniform interleave and	 * and even number of components.	 */	if (ccd->ccd_flags & CCDF_MIRROR) {		ccd->ccd_flags |= CCDF_UNIFORM;		if (cs->sc_ileave == 0) {#ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))			printf("%s: mirroring requires interleave\n",			    cs->sc_xname);#endif			free(ci->ci_path, M_DEVBUF);			free(cs->sc_cinfo, M_DEVBUF);			return (EINVAL);		}		if (cs->sc_nccdisks % 2) { #ifdef DEBUG			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))			printf("%s: mirroring requires even # of components\n",			    cs->sc_xname); #endif			free(ci->ci_path, M_DEVBUF);			free(cs->sc_cinfo, M_DEVBUF);			return (EINVAL);		}	}	/*	 * If uniform interleave is desired set all sizes to that of	 * the smallest component.	 */	if (ccd->ccd_flags & CCDF_UNIFORM) {		for (ci = cs->sc_cinfo;		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)			ci->ci_size = minsize;		if (ccd->ccd_flags & CCDF_MIRROR)			cs->sc_size = (cs->sc_nccdisks / 2) * minsize;		else			cs->sc_size = cs->sc_nccdisks * minsize;	}	/*	 * Construct the interleave table.	 */	ccdinterleave(cs, ccd->ccd_unit);	/*	 * Create pseudo-geometry based on 1MB cylinders.  It's	 * pretty close.	 */	ccg->ccg_secsize = DEV_BSIZE;	ccg->ccg_ntracks = 1;	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;	cs->sc_flags |= CCDF_INITED;	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */	cs->sc_unit = ccd->ccd_unit;	return (0);}