CCD_DPRINTF(CCDB_INIT, ("ccdioctl: component %d: %p, lookedup = %d\n", i, cpp[i], lookedup));
ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p){	int unit = ccdunit(dev);	int i, j, lookedup = 0, error = 0;	int part, pmask, s;	struct ccd_softc *cs;	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;	struct ccddevice ccd;	char **cpp;	struct vnode **vpp;	vaddr_t min, max;	if (unit >= numccd)		return (ENXIO);	cs = &ccd_softc[unit];	if (cmd != CCDIOCSET && !(cs->sc_flags & CCDF_INITED))		return (ENXIO);	/* access control */	switch (cmd) {	case CCDIOCSET:	case CCDIOCCLR:	case DIOCWDINFO:	case DIOCSDINFO:	case DIOCWLABEL:		if ((flag & FWRITE) == 0)			return (EBADF);	}	bzero(&ccd, sizeof(ccd));	switch (cmd) {	case CCDIOCSET:		if (cs->sc_flags & CCDF_INITED)			return (EBUSY);		if ((error = ccdlock(cs)) != 0)			return (error);		/* Fill in some important bits. */		ccd.ccd_unit = unit;		ccd.ccd_interleave = ccio->ccio_ileave;		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;		/* XXX the new code is unstable still */		ccd.ccd_flags |= CCDF_OLD;		/*		 * Interleaving which is not a multiple of the click size		 * must use the old I/O code (by design)		 */		if (ccio->ccio_ileave % (PAGE_SIZE / DEV_BSIZE) != 0)			ccd.ccd_flags |= CCDF_OLD;		/*		 * Allocate space for and copy in the array of		 * componet pathnames and device numbers.		 */		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),		    M_DEVBUF, M_WAITOK);		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),		    M_DEVBUF, M_WAITOK);		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,		    ccio->ccio_ndisks * sizeof(char **));		if (error) {			free(vpp, M_DEVBUF);			free(cpp, M_DEVBUF);			ccdunlock(cs);			return (error);		}#ifdef DEBUG		if (ccddebug & CCDB_INIT)			for (i = 0; i < ccio->ccio_ndisks; ++i)				printf("ccdioctl: component %d: %p\n",				    i, cpp[i]);#endif		for (i = 0; i < ccio->ccio_ndisks; ++i) {#ifdef DEBUG			if (ccddebug & CCDB_INIT)				printf("ccdioctl: lookedup = %d\n", lookedup);#endif			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {				for (j = 0; j < lookedup; ++j)					(void)vn_close(vpp[j], FREAD|FWRITE,					    p->p_ucred, p);				free(vpp, M_DEVBUF);				free(cpp, M_DEVBUF);				ccdunlock(cs);				return (error);			}			++lookedup;		}		ccd.ccd_cpp = cpp;		ccd.ccd_vpp = vpp;		ccd.ccd_ndev = ccio->ccio_ndisks;		/*		 * Initialize the ccd.  Fills in the softc for us.		 */		if ((error = ccdinit(&ccd, cpp, p)) != 0) {			for (j = 0; j < lookedup; ++j)				(void)vn_close(vpp[j], FREAD|FWRITE,				    p->p_ucred, p);			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));			free(vpp, M_DEVBUF);			free(cpp, M_DEVBUF);			ccdunlock(cs);			return (error);		}		/*		 * The ccd has been successfully initialized, so		 * we can place it into the array.  Don't try to		 * read the disklabel until the disk has been attached,		 * because space for the disklabel is allocated		 * in disk_attach();		 */		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));		ccio->ccio_unit = unit;		ccio->ccio_size = cs->sc_size;		/*		 * If we use the optimized protocol we need some kvm space		 * for the component buffers.  Allocate it here.		 *		 * XXX I'd like to have a more dynamic way of acquiring kvm		 * XXX space, but that is problematic as we are not allowed		 * XXX to lock the kernel_map in interrupt context.  It is		 * XXX doable via a freelist implementation though.		 */		if (!ccdmap && !(ccd.ccd_flags & CCDF_OLD)) {			min = vm_map_min(kernel_map);			ccdmap = uvm_km_suballoc(kernel_map, &min, &max,			    CCD_CLUSTERS * MAXBSIZE, VM_MAP_INTRSAFE,			    FALSE, NULL);		}		/* Attach the disk. */		cs->sc_dkdev.dk_name = cs->sc_xname;		disk_attach(&cs->sc_dkdev);		/* Try and read the disklabel. */		ccdgetdisklabel(dev, cs, cs->sc_dkdev.dk_label,		    cs->sc_dkdev.dk_cpulabel, 0);		ccdunlock(cs);		break;	case CCDIOCCLR:		if ((error = ccdlock(cs)) != 0)			return (error);		/*		 * Don't unconfigure if any other partitions are open		 * or if both the character and block flavors of this		 * partition are open.		 */		part = DISKPART(dev);		pmask = (1 << part);		if ((cs->sc_dkdev.dk_openmask & ~pmask) ||		    ((cs->sc_dkdev.dk_bopenmask & pmask) &&		    (cs->sc_dkdev.dk_copenmask & pmask))) {			ccdunlock(cs);			return (EBUSY);		}		/*		 * Free ccd_softc information and clear entry.		 */		/* Close the components and free their pathnames. */		for (i = 0; i < cs->sc_nccdisks; ++i) {			/*			 * XXX: this close could potentially fail and			 * cause Bad Things.  Maybe we need to force			 * the close to happen?			 */#ifdef DEBUG			if (ccddebug & CCDB_VNODE)				vprint("CCDIOCCLR: vnode info",				    cs->sc_cinfo[i].ci_vp);#endif			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,			    p->p_ucred, p);			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);		}		/* Free interleave index. */		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)			free(cs->sc_itable[i].ii_index, M_DEVBUF);		/* Free component info and interleave table. */		free(cs->sc_cinfo, M_DEVBUF);		free(cs->sc_itable, M_DEVBUF);		cs->sc_flags &= ~CCDF_INITED;		/*		 * Free ccddevice information and clear entry.		 */		free(ccddevs[unit].ccd_cpp, M_DEVBUF);		free(ccddevs[unit].ccd_vpp, M_DEVBUF);		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));		/* Detatch the disk. */		disk_detach(&cs->sc_dkdev);		/* This must be atomic. */		s = splhigh();		ccdunlock(cs);		bzero(cs, sizeof(struct ccd_softc));		splx(s);		break;	case DIOCGPDINFO: {		struct cpu_disklabel osdep;		if ((error = ccdlock(cs)) != 0)			return (error);		ccdgetdisklabel(dev, cs, (struct disklabel *)data,		    &osdep, 1);		ccdunlock(cs);		break;	}	case DIOCGDINFO:		*(struct disklabel *)data = *(cs->sc_dkdev.dk_label);		break;	case DIOCGPART:		((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;		((struct partinfo *)data)->part =		    &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];		break;	case DIOCWDINFO:	case DIOCSDINFO:		if ((error = ccdlock(cs)) != 0)			return (error);		cs->sc_flags |= CCDF_LABELLING;		error = setdisklabel(cs->sc_dkdev.dk_label,		    (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel);		if (error == 0) {			if (cmd == DIOCWDINFO)				error = writedisklabel(CCDLABELDEV(dev),				    ccdstrategy, cs->sc_dkdev.dk_label,				    cs->sc_dkdev.dk_cpulabel);		}		cs->sc_flags &= ~CCDF_LABELLING;		ccdunlock(cs);		if (error)			return (error);		break;	case DIOCWLABEL:		if (*(int *)data != 0)			cs->sc_flags |= CCDF_WLABEL;		else			cs->sc_flags &= ~CCDF_WLABEL;		break;	default:		return (ENOTTY);	}	return (0);}