1*c6aa25bfSthorpej /* $NetBSD: ccd.c,v 1.59 1999/01/21 00:35:15 thorpej Exp $ */ 277d85de2Sthorpej 3ee8a2c00Sthorpej /*- 4*c6aa25bfSthorpej * Copyright (c) 1996, 1997, 1998, 1999 The NetBSD Foundation, Inc. 577d85de2Sthorpej * All rights reserved. 677d85de2Sthorpej * 7ee8a2c00Sthorpej * This code is derived from software contributed to The NetBSD Foundation 8ee8a2c00Sthorpej * by Jason R. Thorpe. 9ee8a2c00Sthorpej * 1077d85de2Sthorpej * Redistribution and use in source and binary forms, with or without 1177d85de2Sthorpej * modification, are permitted provided that the following conditions 1277d85de2Sthorpej * are met: 1377d85de2Sthorpej * 1. Redistributions of source code must retain the above copyright 1477d85de2Sthorpej * notice, this list of conditions and the following disclaimer. 1577d85de2Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 1677d85de2Sthorpej * notice, this list of conditions and the following disclaimer in the 1777d85de2Sthorpej * documentation and/or other materials provided with the distribution. 1877d85de2Sthorpej * 3. All advertising materials mentioning features or use of this software 1977d85de2Sthorpej * must display the following acknowledgement: 20ee8a2c00Sthorpej * This product includes software developed by the NetBSD 21ee8a2c00Sthorpej * Foundation, Inc. and its contributors. 22ee8a2c00Sthorpej * 4. Neither the name of The NetBSD Foundation nor the names of its 23ee8a2c00Sthorpej * contributors may be used to endorse or promote products derived 24ee8a2c00Sthorpej * from this software without specific prior written permission. 2577d85de2Sthorpej * 26ee8a2c00Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27ee8a2c00Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28ee8a2c00Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29d6ae2cd7Sjtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30d6ae2cd7Sjtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31ee8a2c00Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32ee8a2c00Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33ee8a2c00Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34ee8a2c00Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35ee8a2c00Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36ee8a2c00Sthorpej * POSSIBILITY OF SUCH DAMAGE. 3777d85de2Sthorpej */ 38cf92afd6Scgd 396f9db1eeShpeyerl /* 406f9db1eeShpeyerl * Copyright (c) 1988 University of Utah. 413214723fShpeyerl * Copyright (c) 1990, 1993 423214723fShpeyerl * The Regents of the University of California. All rights reserved. 436f9db1eeShpeyerl * 446f9db1eeShpeyerl * This code is derived from software contributed to Berkeley by 456f9db1eeShpeyerl * the Systems Programming Group of the University of Utah Computer 466f9db1eeShpeyerl * Science Department. 476f9db1eeShpeyerl * 486f9db1eeShpeyerl * Redistribution and use in source and binary forms, with or without 496f9db1eeShpeyerl * modification, are permitted provided that the following conditions 506f9db1eeShpeyerl * are met: 516f9db1eeShpeyerl * 1. Redistributions of source code must retain the above copyright 526f9db1eeShpeyerl * notice, this list of conditions and the following disclaimer. 536f9db1eeShpeyerl * 2. Redistributions in binary form must reproduce the above copyright 546f9db1eeShpeyerl * notice, this list of conditions and the following disclaimer in the 556f9db1eeShpeyerl * documentation and/or other materials provided with the distribution. 566f9db1eeShpeyerl * 3. All advertising materials mentioning features or use of this software 576f9db1eeShpeyerl * must display the following acknowledgement: 586f9db1eeShpeyerl * This product includes software developed by the University of 596f9db1eeShpeyerl * California, Berkeley and its contributors. 606f9db1eeShpeyerl * 4. Neither the name of the University nor the names of its contributors 616f9db1eeShpeyerl * may be used to endorse or promote products derived from this software 626f9db1eeShpeyerl * without specific prior written permission. 636f9db1eeShpeyerl * 646f9db1eeShpeyerl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 656f9db1eeShpeyerl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 666f9db1eeShpeyerl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 676f9db1eeShpeyerl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 686f9db1eeShpeyerl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 696f9db1eeShpeyerl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 706f9db1eeShpeyerl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 716f9db1eeShpeyerl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 726f9db1eeShpeyerl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 736f9db1eeShpeyerl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 746f9db1eeShpeyerl * SUCH DAMAGE. 756f9db1eeShpeyerl * 76cf92afd6Scgd * from: Utah $Hdr: cd.c 1.6 90/11/28$ 77cf92afd6Scgd * 783214723fShpeyerl * @(#)cd.c 8.2 (Berkeley) 11/16/93 796f9db1eeShpeyerl */ 806f9db1eeShpeyerl 816f9db1eeShpeyerl /* 826f9db1eeShpeyerl * "Concatenated" disk driver. 8377d85de2Sthorpej * 8477d85de2Sthorpej * Dynamic configuration and disklabel support by: 8577d85de2Sthorpej * Jason R. Thorpe <thorpej@nas.nasa.gov> 8677d85de2Sthorpej * Numerical Aerodynamic Simulation Facility 8777d85de2Sthorpej * Mail Stop 258-6 8877d85de2Sthorpej * NASA Ames Research Center 8977d85de2Sthorpej * Moffett Field, CA 94035 906f9db1eeShpeyerl */ 916f9db1eeShpeyerl 926f9db1eeShpeyerl #include <sys/param.h> 936f9db1eeShpeyerl #include <sys/systm.h> 943214723fShpeyerl #include <sys/proc.h> 956f9db1eeShpeyerl #include <sys/errno.h> 966f9db1eeShpeyerl #include <sys/buf.h> 976f9db1eeShpeyerl #include <sys/malloc.h> 9877d85de2Sthorpej #include <sys/namei.h> 993214723fShpeyerl #include <sys/stat.h> 1003214723fShpeyerl #include <sys/ioctl.h> 1013214723fShpeyerl #include <sys/disklabel.h> 10277d85de2Sthorpej #include <sys/device.h> 10377d85de2Sthorpej #include <sys/disk.h> 10477d85de2Sthorpej #include <sys/syslog.h> 1053214723fShpeyerl #include <sys/fcntl.h> 10677d85de2Sthorpej #include <sys/vnode.h> 107e1930da2Schristos #include <sys/conf.h> 1080272b2abSthorpej #include <sys/lock.h> 109d272bb00Sthorpej #include <sys/queue.h> 1106f9db1eeShpeyerl 1116f9db1eeShpeyerl #include <dev/ccdvar.h> 1126f9db1eeShpeyerl 11377d85de2Sthorpej #if defined(CCDDEBUG) && !defined(DEBUG) 11477d85de2Sthorpej #define DEBUG 11577d85de2Sthorpej #endif 11677d85de2Sthorpej 1176f9db1eeShpeyerl #ifdef DEBUG 1183214723fShpeyerl #define CCDB_FOLLOW 0x01 1193214723fShpeyerl #define CCDB_INIT 0x02 1203214723fShpeyerl #define CCDB_IO 0x04 12177d85de2Sthorpej #define CCDB_LABEL 0x08 12277d85de2Sthorpej #define CCDB_VNODE 0x10 123732dd94aSthorpej int ccddebug = 0x00; 1246f9db1eeShpeyerl #endif 1256f9db1eeShpeyerl 126f694af67Scgd #define ccdunit(x) DISKUNIT(x) 1276f9db1eeShpeyerl 128f694af67Scgd struct ccdbuf { 129f694af67Scgd struct buf cb_buf; /* new I/O buf */ 130f694af67Scgd struct buf *cb_obp; /* ptr. to original I/O buf */ 131*c6aa25bfSthorpej struct ccd_softc *cb_sc; /* pointer to ccd softc */ 132f694af67Scgd int cb_comp; /* target component */ 133d272bb00Sthorpej SIMPLEQ_ENTRY(ccdbuf) cb_q; /* fifo of component buffers */ 134f694af67Scgd }; 1356f9db1eeShpeyerl 136b6ac7c9bSthorpej #define CCD_GETBUF(cs) pool_get(&(cs)->sc_cbufpool, PR_NOWAIT) 13743561361Sthorpej #define CCD_PUTBUF(cs, cbp) pool_put(&(cs)->sc_cbufpool, cbp) 1386f9db1eeShpeyerl 13977d85de2Sthorpej #define CCDLABELDEV(dev) \ 14077d85de2Sthorpej (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART)) 1416f9db1eeShpeyerl 14277d85de2Sthorpej /* called by main() at boot time */ 14377d85de2Sthorpej void ccdattach __P((int)); 14477d85de2Sthorpej 14577d85de2Sthorpej /* called by biodone() at interrupt time */ 146d318abdbSchristos void ccdiodone __P((struct buf *)); 147d318abdbSchristos int ccdsize __P((dev_t)); 148f694af67Scgd 14977d85de2Sthorpej static void ccdstart __P((struct ccd_softc *, struct buf *)); 1500272b2abSthorpej static void ccdinterleave __P((struct ccd_softc *)); 15177d85de2Sthorpej static void ccdintr __P((struct ccd_softc *, struct buf *)); 1520272b2abSthorpej static int ccdinit __P((struct ccd_softc *, char **, struct vnode **, 1530272b2abSthorpej struct proc *)); 15477d85de2Sthorpej static int ccdlookup __P((char *, struct proc *p, struct vnode **)); 155092c2019Sthorpej static struct ccdbuf *ccdbuffer __P((struct ccd_softc *, struct buf *, 156092c2019Sthorpej daddr_t, caddr_t, long)); 157939e074dSthorpej static void ccdgetdefaultlabel __P((struct ccd_softc *, struct disklabel *)); 15877d85de2Sthorpej static void ccdgetdisklabel __P((dev_t)); 15977d85de2Sthorpej static void ccdmakedisklabel __P((struct ccd_softc *)); 1603214723fShpeyerl 16177d85de2Sthorpej #ifdef DEBUG 16277d85de2Sthorpej static void printiinfo __P((struct ccdiinfo *)); 16377d85de2Sthorpej #endif 16477d85de2Sthorpej 16577d85de2Sthorpej /* Non-private for the benefit of libkvm. */ 1663214723fShpeyerl struct ccd_softc *ccd_softc; 16777d85de2Sthorpej int numccd = 0; 1686f9db1eeShpeyerl 1696f9db1eeShpeyerl /* 17077d85de2Sthorpej * Called by main() during pseudo-device attachment. All we need 17177d85de2Sthorpej * to do is allocate enough space for devices to be configured later. 1726f9db1eeShpeyerl */ 1736f9db1eeShpeyerl void 1743214723fShpeyerl ccdattach(num) 1753214723fShpeyerl int num; 1766f9db1eeShpeyerl { 1770272b2abSthorpej struct ccd_softc *cs; 1780272b2abSthorpej int i; 1790272b2abSthorpej 18077d85de2Sthorpej if (num <= 0) { 18177d85de2Sthorpej #ifdef DIAGNOSTIC 18277d85de2Sthorpej panic("ccdattach: count <= 0"); 18377d85de2Sthorpej #endif 1843214723fShpeyerl return; 1853214723fShpeyerl } 18677d85de2Sthorpej 18777d85de2Sthorpej ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), 18877d85de2Sthorpej M_DEVBUF, M_NOWAIT); 1890272b2abSthorpej if (ccd_softc == NULL) { 19086373f8cSchristos printf("WARNING: no memory for concatenated disks\n"); 19177d85de2Sthorpej if (ccd_softc != NULL) 19277d85de2Sthorpej free(ccd_softc, M_DEVBUF); 19377d85de2Sthorpej return; 19477d85de2Sthorpej } 1953214723fShpeyerl numccd = num; 19677d85de2Sthorpej bzero(ccd_softc, num * sizeof(struct ccd_softc)); 1970272b2abSthorpej 1980272b2abSthorpej /* Initialize per-softc structures. */ 1990272b2abSthorpej for (i = 0; i < num; i++) { 2000272b2abSthorpej cs = &ccd_softc[i]; 2010272b2abSthorpej sprintf(cs->sc_xname, "ccd%d", i); /* XXX */ 2020272b2abSthorpej cs->sc_dkdev.dk_name = cs->sc_xname; /* XXX */ 2030272b2abSthorpej lockinit(&cs->sc_lock, PRIBIO, "ccdlk", 0, 0); 2040272b2abSthorpej } 2056f9db1eeShpeyerl } 2066f9db1eeShpeyerl 20777d85de2Sthorpej static int 2080272b2abSthorpej ccdinit(cs, cpaths, vpp, p) 2090272b2abSthorpej struct ccd_softc *cs; 21077d85de2Sthorpej char **cpaths; 2110272b2abSthorpej struct vnode **vpp; 21277d85de2Sthorpej struct proc *p; 2136f9db1eeShpeyerl { 214d318abdbSchristos register struct ccdcinfo *ci = NULL; 2156f9db1eeShpeyerl register size_t size; 2166f9db1eeShpeyerl register int ix; 21777d85de2Sthorpej struct vattr va; 2186f9db1eeShpeyerl size_t minsize; 21977d85de2Sthorpej int maxsecsize; 220a44a2765Scgd struct partinfo dpart; 22177d85de2Sthorpej struct ccdgeom *ccg = &cs->sc_geom; 22277d85de2Sthorpej char tmppath[MAXPATHLEN]; 22377d85de2Sthorpej int error; 2246f9db1eeShpeyerl 2256f9db1eeShpeyerl #ifdef DEBUG 2263214723fShpeyerl if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 227*c6aa25bfSthorpej printf("%s: ccdinit\n", cs->sc_xname); 2286f9db1eeShpeyerl #endif 22977d85de2Sthorpej 23077d85de2Sthorpej /* Allocate space for the component info. */ 23177d85de2Sthorpej cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), 23277d85de2Sthorpej M_DEVBUF, M_WAITOK); 23377d85de2Sthorpej 2340272b2abSthorpej cs->sc_size = 0; 2350272b2abSthorpej 2366f9db1eeShpeyerl /* 2376f9db1eeShpeyerl * Verify that each component piece exists and record 2386f9db1eeShpeyerl * relevant information about it. 2396f9db1eeShpeyerl */ 24077d85de2Sthorpej maxsecsize = 0; 2416f9db1eeShpeyerl minsize = 0; 24277d85de2Sthorpej for (ix = 0; ix < cs->sc_nccdisks; ix++) { 2436f9db1eeShpeyerl ci = &cs->sc_cinfo[ix]; 2440272b2abSthorpej ci->ci_vp = vpp[ix]; 245a44a2765Scgd 24677d85de2Sthorpej /* 24777d85de2Sthorpej * Copy in the pathname of the component. 24877d85de2Sthorpej */ 24977d85de2Sthorpej bzero(tmppath, sizeof(tmppath)); /* sanity */ 250d318abdbSchristos error = copyinstr(cpaths[ix], tmppath, 251d318abdbSchristos MAXPATHLEN, &ci->ci_pathlen); 252d318abdbSchristos if (error) { 25377d85de2Sthorpej #ifdef DEBUG 25477d85de2Sthorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 25586373f8cSchristos printf("%s: can't copy path, error = %d\n", 2565b39541eSthorpej cs->sc_xname, error); 25777d85de2Sthorpej #endif 25877d85de2Sthorpej free(cs->sc_cinfo, M_DEVBUF); 25977d85de2Sthorpej return (error); 26077d85de2Sthorpej } 26177d85de2Sthorpej ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); 26277d85de2Sthorpej bcopy(tmppath, ci->ci_path, ci->ci_pathlen); 26377d85de2Sthorpej 26477d85de2Sthorpej /* 26577d85de2Sthorpej * XXX: Cache the component's dev_t. 26677d85de2Sthorpej */ 2670272b2abSthorpej if ((error = VOP_GETATTR(vpp[ix], &va, p->p_ucred, p)) != 0) { 26877d85de2Sthorpej #ifdef DEBUG 26977d85de2Sthorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 27086373f8cSchristos printf("%s: %s: getattr failed %s = %d\n", 2715b39541eSthorpej cs->sc_xname, ci->ci_path, 27277d85de2Sthorpej "error", error); 27377d85de2Sthorpej #endif 27477d85de2Sthorpej free(ci->ci_path, M_DEVBUF); 27577d85de2Sthorpej free(cs->sc_cinfo, M_DEVBUF); 27677d85de2Sthorpej return (error); 27777d85de2Sthorpej } 27877d85de2Sthorpej ci->ci_dev = va.va_rdev; 27977d85de2Sthorpej 28077d85de2Sthorpej /* 28177d85de2Sthorpej * Get partition information for the component. 28277d85de2Sthorpej */ 2830272b2abSthorpej error = VOP_IOCTL(vpp[ix], DIOCGPART, (caddr_t)&dpart, 284d318abdbSchristos FREAD, p->p_ucred, p); 285d318abdbSchristos if (error) { 28677d85de2Sthorpej #ifdef DEBUG 28777d85de2Sthorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 28886373f8cSchristos printf("%s: %s: ioctl failed, error = %d\n", 2895b39541eSthorpej cs->sc_xname, ci->ci_path, error); 29077d85de2Sthorpej #endif 29177d85de2Sthorpej free(ci->ci_path, M_DEVBUF); 29277d85de2Sthorpej free(cs->sc_cinfo, M_DEVBUF); 29377d85de2Sthorpej return (error); 29477d85de2Sthorpej } 29577d85de2Sthorpej 29677d85de2Sthorpej /* 29777d85de2Sthorpej * Calculate the size, truncating to an interleave 29877d85de2Sthorpej * boundary if necessary. 29977d85de2Sthorpej */ 300fd01cb62Sthorpej maxsecsize = 301fd01cb62Sthorpej ((dpart.disklab->d_secsize > maxsecsize) ? 302fd01cb62Sthorpej dpart.disklab->d_secsize : maxsecsize); 303fd01cb62Sthorpej size = dpart.part->p_size; 3046f9db1eeShpeyerl if (cs->sc_ileave > 1) 3056f9db1eeShpeyerl size -= size % cs->sc_ileave; 3063214723fShpeyerl 30777d85de2Sthorpej if (size == 0) { 30877d85de2Sthorpej #ifdef DEBUG 30977d85de2Sthorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 31086373f8cSchristos printf("%s: %s: size == 0\n", 3115b39541eSthorpej cs->sc_xname, ci->ci_path); 3123214723fShpeyerl #endif 31377d85de2Sthorpej free(ci->ci_path, M_DEVBUF); 31477d85de2Sthorpej free(cs->sc_cinfo, M_DEVBUF); 31577d85de2Sthorpej return (ENODEV); 31677d85de2Sthorpej } 31777d85de2Sthorpej 3186f9db1eeShpeyerl if (minsize == 0 || size < minsize) 3196f9db1eeShpeyerl minsize = size; 3206f9db1eeShpeyerl ci->ci_size = size; 3216f9db1eeShpeyerl cs->sc_size += size; 3226f9db1eeShpeyerl } 32377d85de2Sthorpej 32477d85de2Sthorpej /* 32577d85de2Sthorpej * Don't allow the interleave to be smaller than 32677d85de2Sthorpej * the biggest component sector. 32777d85de2Sthorpej */ 32877d85de2Sthorpej if ((cs->sc_ileave > 0) && 32977d85de2Sthorpej (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 33077d85de2Sthorpej #ifdef DEBUG 33177d85de2Sthorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 33286373f8cSchristos printf("%s: interleave must be at least %d\n", 3335b39541eSthorpej cs->sc_xname, (maxsecsize / DEV_BSIZE)); 33477d85de2Sthorpej #endif 33577d85de2Sthorpej free(ci->ci_path, M_DEVBUF); 33677d85de2Sthorpej free(cs->sc_cinfo, M_DEVBUF); 33777d85de2Sthorpej return (EINVAL); 33877d85de2Sthorpej } 33977d85de2Sthorpej 3406f9db1eeShpeyerl /* 3416f9db1eeShpeyerl * If uniform interleave is desired set all sizes to that of 3426f9db1eeShpeyerl * the smallest component. 3436f9db1eeShpeyerl */ 3440272b2abSthorpej if (cs->sc_flags & CCDF_UNIFORM) { 3456f9db1eeShpeyerl for (ci = cs->sc_cinfo; 3466f9db1eeShpeyerl ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 3476f9db1eeShpeyerl ci->ci_size = minsize; 348732dd94aSthorpej 3496f9db1eeShpeyerl cs->sc_size = cs->sc_nccdisks * minsize; 3506f9db1eeShpeyerl } 35177d85de2Sthorpej 3526f9db1eeShpeyerl /* 35377d85de2Sthorpej * Construct the interleave table. 3546f9db1eeShpeyerl */ 3550272b2abSthorpej ccdinterleave(cs); 35677d85de2Sthorpej 35777d85de2Sthorpej /* 35877d85de2Sthorpej * Create pseudo-geometry based on 1MB cylinders. It's 35977d85de2Sthorpej * pretty close. 36077d85de2Sthorpej */ 36177d85de2Sthorpej ccg->ccg_secsize = DEV_BSIZE; 36289d4987eSthorpej ccg->ccg_ntracks = 1; 36377d85de2Sthorpej ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); 36477d85de2Sthorpej ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 36577d85de2Sthorpej 36677d85de2Sthorpej cs->sc_flags |= CCDF_INITED; 3675b39541eSthorpej 36877d85de2Sthorpej return (0); 3696f9db1eeShpeyerl } 3706f9db1eeShpeyerl 37177d85de2Sthorpej static void 3720272b2abSthorpej ccdinterleave(cs) 3736f9db1eeShpeyerl register struct ccd_softc *cs; 3746f9db1eeShpeyerl { 3756f9db1eeShpeyerl register struct ccdcinfo *ci, *smallci; 3766f9db1eeShpeyerl register struct ccdiinfo *ii; 3776f9db1eeShpeyerl register daddr_t bn, lbn; 3786f9db1eeShpeyerl register int ix; 3796f9db1eeShpeyerl u_long size; 3806f9db1eeShpeyerl 3816f9db1eeShpeyerl #ifdef DEBUG 3823214723fShpeyerl if (ccddebug & CCDB_INIT) 38386373f8cSchristos printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave); 3846f9db1eeShpeyerl #endif 3856f9db1eeShpeyerl /* 3866f9db1eeShpeyerl * Allocate an interleave table. 3876f9db1eeShpeyerl * Chances are this is too big, but we don't care. 3886f9db1eeShpeyerl */ 3896f9db1eeShpeyerl size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 3906f9db1eeShpeyerl cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 3916f9db1eeShpeyerl bzero((caddr_t)cs->sc_itable, size); 39277d85de2Sthorpej 3936f9db1eeShpeyerl /* 3946f9db1eeShpeyerl * Trivial case: no interleave (actually interleave of disk size). 39577d85de2Sthorpej * Each table entry represents a single component in its entirety. 3966f9db1eeShpeyerl */ 3976f9db1eeShpeyerl if (cs->sc_ileave == 0) { 3986f9db1eeShpeyerl bn = 0; 3996f9db1eeShpeyerl ii = cs->sc_itable; 40077d85de2Sthorpej 4016f9db1eeShpeyerl for (ix = 0; ix < cs->sc_nccdisks; ix++) { 40289d4987eSthorpej /* Allocate space for ii_index. */ 40389d4987eSthorpej ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); 4046f9db1eeShpeyerl ii->ii_ndisk = 1; 4056f9db1eeShpeyerl ii->ii_startblk = bn; 4066f9db1eeShpeyerl ii->ii_startoff = 0; 4076f9db1eeShpeyerl ii->ii_index[0] = ix; 4086f9db1eeShpeyerl bn += cs->sc_cinfo[ix].ci_size; 4096f9db1eeShpeyerl ii++; 4106f9db1eeShpeyerl } 4116f9db1eeShpeyerl ii->ii_ndisk = 0; 4126f9db1eeShpeyerl #ifdef DEBUG 4133214723fShpeyerl if (ccddebug & CCDB_INIT) 4146f9db1eeShpeyerl printiinfo(cs->sc_itable); 4156f9db1eeShpeyerl #endif 41677d85de2Sthorpej return; 4176f9db1eeShpeyerl } 41877d85de2Sthorpej 4196f9db1eeShpeyerl /* 4206f9db1eeShpeyerl * The following isn't fast or pretty; it doesn't have to be. 4216f9db1eeShpeyerl */ 4226f9db1eeShpeyerl size = 0; 4236f9db1eeShpeyerl bn = lbn = 0; 4246f9db1eeShpeyerl for (ii = cs->sc_itable; ; ii++) { 42577d85de2Sthorpej /* Allocate space for ii_index. */ 42689d4987eSthorpej ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), 42789d4987eSthorpej M_DEVBUF, M_WAITOK); 42877d85de2Sthorpej 4296f9db1eeShpeyerl /* 4306f9db1eeShpeyerl * Locate the smallest of the remaining components 4316f9db1eeShpeyerl */ 4326f9db1eeShpeyerl smallci = NULL; 4336f9db1eeShpeyerl for (ci = cs->sc_cinfo; 4346f9db1eeShpeyerl ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 4356f9db1eeShpeyerl if (ci->ci_size > size && 4366f9db1eeShpeyerl (smallci == NULL || 4376f9db1eeShpeyerl ci->ci_size < smallci->ci_size)) 4386f9db1eeShpeyerl smallci = ci; 43977d85de2Sthorpej 4406f9db1eeShpeyerl /* 4416f9db1eeShpeyerl * Nobody left, all done 4426f9db1eeShpeyerl */ 4436f9db1eeShpeyerl if (smallci == NULL) { 4446f9db1eeShpeyerl ii->ii_ndisk = 0; 4456f9db1eeShpeyerl break; 4466f9db1eeShpeyerl } 44777d85de2Sthorpej 4486f9db1eeShpeyerl /* 4496f9db1eeShpeyerl * Record starting logical block and component offset 4506f9db1eeShpeyerl */ 4516f9db1eeShpeyerl ii->ii_startblk = bn / cs->sc_ileave; 4526f9db1eeShpeyerl ii->ii_startoff = lbn; 45377d85de2Sthorpej 4546f9db1eeShpeyerl /* 4556f9db1eeShpeyerl * Determine how many disks take part in this interleave 4566f9db1eeShpeyerl * and record their indices. 4576f9db1eeShpeyerl */ 4586f9db1eeShpeyerl ix = 0; 4596f9db1eeShpeyerl for (ci = cs->sc_cinfo; 4606f9db1eeShpeyerl ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 4616f9db1eeShpeyerl if (ci->ci_size >= smallci->ci_size) 4626f9db1eeShpeyerl ii->ii_index[ix++] = ci - cs->sc_cinfo; 4636f9db1eeShpeyerl ii->ii_ndisk = ix; 4646f9db1eeShpeyerl bn += ix * (smallci->ci_size - size); 4656f9db1eeShpeyerl lbn = smallci->ci_size / cs->sc_ileave; 4666f9db1eeShpeyerl size = smallci->ci_size; 4676f9db1eeShpeyerl } 4686f9db1eeShpeyerl #ifdef DEBUG 4693214723fShpeyerl if (ccddebug & CCDB_INIT) 4706f9db1eeShpeyerl printiinfo(cs->sc_itable); 4716f9db1eeShpeyerl #endif 4726f9db1eeShpeyerl } 4736f9db1eeShpeyerl 47477d85de2Sthorpej /* ARGSUSED */ 47577d85de2Sthorpej int 47677d85de2Sthorpej ccdopen(dev, flags, fmt, p) 4776f9db1eeShpeyerl dev_t dev; 47877d85de2Sthorpej int flags, fmt; 47977d85de2Sthorpej struct proc *p; 4806f9db1eeShpeyerl { 4816f9db1eeShpeyerl int unit = ccdunit(dev); 48277d85de2Sthorpej struct ccd_softc *cs; 48377d85de2Sthorpej struct disklabel *lp; 484b8dcfbd3Sthorpej int error = 0, part, pmask; 4856f9db1eeShpeyerl 4866f9db1eeShpeyerl #ifdef DEBUG 4873214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 488c27c2868Sfair printf("ccdopen(0x%x, 0x%x)\n", dev, flags); 4896f9db1eeShpeyerl #endif 49077d85de2Sthorpej if (unit >= numccd) 4916f9db1eeShpeyerl return (ENXIO); 49277d85de2Sthorpej cs = &ccd_softc[unit]; 49377d85de2Sthorpej 4940272b2abSthorpej if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0) 495b8dcfbd3Sthorpej return (error); 496b8dcfbd3Sthorpej 4975b39541eSthorpej lp = cs->sc_dkdev.dk_label; 49877d85de2Sthorpej 49977d85de2Sthorpej part = DISKPART(dev); 50077d85de2Sthorpej pmask = (1 << part); 50177d85de2Sthorpej 502b8dcfbd3Sthorpej /* 503b8dcfbd3Sthorpej * If we're initialized, check to see if there are any other 504b8dcfbd3Sthorpej * open partitions. If not, then it's safe to update 505b8dcfbd3Sthorpej * the in-core disklabel. 506b8dcfbd3Sthorpej */ 507b8dcfbd3Sthorpej if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0)) 508b8dcfbd3Sthorpej ccdgetdisklabel(dev); 509b8dcfbd3Sthorpej 51077d85de2Sthorpej /* Check that the partition exists. */ 51191bd533cSthorpej if (part != RAW_PART) { 51291bd533cSthorpej if (((cs->sc_flags & CCDF_INITED) == 0) || 513bb608224Sthorpej ((part >= lp->d_npartitions) || 514b8dcfbd3Sthorpej (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 515b8dcfbd3Sthorpej error = ENXIO; 516b8dcfbd3Sthorpej goto done; 517b8dcfbd3Sthorpej } 51891bd533cSthorpej } 51977d85de2Sthorpej 52077d85de2Sthorpej /* Prevent our unit from being unconfigured while open. */ 52177d85de2Sthorpej switch (fmt) { 52277d85de2Sthorpej case S_IFCHR: 52377d85de2Sthorpej cs->sc_dkdev.dk_copenmask |= pmask; 52477d85de2Sthorpej break; 52577d85de2Sthorpej 52677d85de2Sthorpej case S_IFBLK: 52777d85de2Sthorpej cs->sc_dkdev.dk_bopenmask |= pmask; 52877d85de2Sthorpej break; 52977d85de2Sthorpej } 53077d85de2Sthorpej cs->sc_dkdev.dk_openmask = 53177d85de2Sthorpej cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 53277d85de2Sthorpej 533b8dcfbd3Sthorpej done: 5340272b2abSthorpej (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL); 53549c5d29eSthorpej return (error); 5366f9db1eeShpeyerl } 5376f9db1eeShpeyerl 53877d85de2Sthorpej /* ARGSUSED */ 53977d85de2Sthorpej int 54077d85de2Sthorpej ccdclose(dev, flags, fmt, p) 541a44a2765Scgd dev_t dev; 54277d85de2Sthorpej int flags, fmt; 54377d85de2Sthorpej struct proc *p; 544a44a2765Scgd { 54577d85de2Sthorpej int unit = ccdunit(dev); 54677d85de2Sthorpej struct ccd_softc *cs; 547b8dcfbd3Sthorpej int error = 0, part; 54877d85de2Sthorpej 549a44a2765Scgd #ifdef DEBUG 550a44a2765Scgd if (ccddebug & CCDB_FOLLOW) 551c27c2868Sfair printf("ccdclose(0x%x, 0x%x)\n", dev, flags); 552a44a2765Scgd #endif 55377d85de2Sthorpej 55477d85de2Sthorpej if (unit >= numccd) 55577d85de2Sthorpej return (ENXIO); 55677d85de2Sthorpej cs = &ccd_softc[unit]; 557b8dcfbd3Sthorpej 5580272b2abSthorpej if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0) 559b8dcfbd3Sthorpej return (error); 560b8dcfbd3Sthorpej 56177d85de2Sthorpej part = DISKPART(dev); 56277d85de2Sthorpej 56377d85de2Sthorpej /* ...that much closer to allowing unconfiguration... */ 56477d85de2Sthorpej switch (fmt) { 56577d85de2Sthorpej case S_IFCHR: 56677d85de2Sthorpej cs->sc_dkdev.dk_copenmask &= ~(1 << part); 56777d85de2Sthorpej break; 56877d85de2Sthorpej 56977d85de2Sthorpej case S_IFBLK: 57077d85de2Sthorpej cs->sc_dkdev.dk_bopenmask &= ~(1 << part); 57177d85de2Sthorpej break; 57277d85de2Sthorpej } 57377d85de2Sthorpej cs->sc_dkdev.dk_openmask = 57477d85de2Sthorpej cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 57577d85de2Sthorpej 5760272b2abSthorpej (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL); 577a44a2765Scgd return (0); 578a44a2765Scgd } 579a44a2765Scgd 58077d85de2Sthorpej void 5816f9db1eeShpeyerl ccdstrategy(bp) 5826f9db1eeShpeyerl register struct buf *bp; 5836f9db1eeShpeyerl { 5846f9db1eeShpeyerl register int unit = ccdunit(bp->b_dev); 5856f9db1eeShpeyerl register struct ccd_softc *cs = &ccd_softc[unit]; 586d318abdbSchristos register int s; 58777d85de2Sthorpej int wlabel; 588b8dcfbd3Sthorpej struct disklabel *lp; 5896f9db1eeShpeyerl 5906f9db1eeShpeyerl #ifdef DEBUG 5913214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 59286373f8cSchristos printf("ccdstrategy(%p): unit %d\n", bp, unit); 5936f9db1eeShpeyerl #endif 5943214723fShpeyerl if ((cs->sc_flags & CCDF_INITED) == 0) { 595*c6aa25bfSthorpej #ifdef DEBUG 596*c6aa25bfSthorpej if (ccddebug & CCDB_FOLLOW) 597*c6aa25bfSthorpej printf("ccdstrategy: unit %d: not inited\n", unit); 598*c6aa25bfSthorpej #endif 5996f9db1eeShpeyerl bp->b_error = ENXIO; 6006f9db1eeShpeyerl bp->b_flags |= B_ERROR; 6016f9db1eeShpeyerl goto done; 6026f9db1eeShpeyerl } 60377d85de2Sthorpej 60477d85de2Sthorpej /* If it's a nil transfer, wake up the top half now. */ 60577d85de2Sthorpej if (bp->b_bcount == 0) 6066f9db1eeShpeyerl goto done; 60777d85de2Sthorpej 6085b39541eSthorpej lp = cs->sc_dkdev.dk_label; 609b8dcfbd3Sthorpej 61077d85de2Sthorpej /* 611ab0109adSthorpej * Do bounds checking and adjust transfer. If there's an 61277d85de2Sthorpej * error, the bounds check will flag that for us. 61377d85de2Sthorpej */ 61477d85de2Sthorpej wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 6154e3112d3Sthorpej if (DISKPART(bp->b_dev) != RAW_PART) 616b8dcfbd3Sthorpej if (bounds_check_with_label(bp, lp, wlabel) <= 0) 6176f9db1eeShpeyerl goto done; 61877d85de2Sthorpej 6196f9db1eeShpeyerl bp->b_resid = bp->b_bcount; 62077d85de2Sthorpej 6216f9db1eeShpeyerl /* 6226f9db1eeShpeyerl * "Start" the unit. 6236f9db1eeShpeyerl */ 6246f9db1eeShpeyerl s = splbio(); 6253214723fShpeyerl ccdstart(cs, bp); 6266f9db1eeShpeyerl splx(s); 627d272bb00Sthorpej if (bp->b_flags & B_ERROR) 628d272bb00Sthorpej goto done; 6296f9db1eeShpeyerl return; 6306f9db1eeShpeyerl done: 6316f9db1eeShpeyerl biodone(bp); 6326f9db1eeShpeyerl } 6336f9db1eeShpeyerl 63477d85de2Sthorpej static void 6353214723fShpeyerl ccdstart(cs, bp) 6363214723fShpeyerl register struct ccd_softc *cs; 6373214723fShpeyerl register struct buf *bp; 6386f9db1eeShpeyerl { 6396f9db1eeShpeyerl register long bcount, rcount; 640092c2019Sthorpej struct ccdbuf *cbp; 6416f9db1eeShpeyerl caddr_t addr; 6426f9db1eeShpeyerl daddr_t bn; 643f85819bcSthorpej struct partition *pp; 644d272bb00Sthorpej SIMPLEQ_HEAD(, ccdbuf) cbufq; 6456f9db1eeShpeyerl 6466f9db1eeShpeyerl #ifdef DEBUG 6473214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 64886373f8cSchristos printf("ccdstart(%p, %p)\n", cs, bp); 6496f9db1eeShpeyerl #endif 65077d85de2Sthorpej 6515b39541eSthorpej /* Instrumentation. */ 6525b39541eSthorpej disk_busy(&cs->sc_dkdev); 65377d85de2Sthorpej 6546f9db1eeShpeyerl /* 655ab0109adSthorpej * Translate the partition-relative block number to an absolute. 6566f9db1eeShpeyerl */ 657f85819bcSthorpej bn = bp->b_blkno; 658f85819bcSthorpej if (DISKPART(bp->b_dev) != RAW_PART) { 6595b39541eSthorpej pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)]; 660f85819bcSthorpej bn += pp->p_offset; 661f85819bcSthorpej } 662ab0109adSthorpej 663ab0109adSthorpej /* 664d272bb00Sthorpej * Allocate the component buffers. 665ab0109adSthorpej */ 666d272bb00Sthorpej SIMPLEQ_INIT(&cbufq); 6673214723fShpeyerl addr = bp->b_data; 6686f9db1eeShpeyerl for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 669092c2019Sthorpej cbp = ccdbuffer(cs, bp, bn, addr, bcount); 670d272bb00Sthorpej if (cbp == NULL) { 671d272bb00Sthorpej /* Free the already allocated component buffers. */ 672d272bb00Sthorpej while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) { 673d272bb00Sthorpej SIMPLEQ_REMOVE_HEAD(&cbufq, cbp, cb_q); 674d272bb00Sthorpej CCD_PUTBUF(cs, cbp); 675d272bb00Sthorpej } 676d272bb00Sthorpej 677d272bb00Sthorpej /* Notify the upper layer we are out of memory. */ 678d272bb00Sthorpej bp->b_error = ENOMEM; 679d272bb00Sthorpej bp->b_flags |= B_ERROR; 680*c6aa25bfSthorpej disk_unbusy(&cs->sc_dkdev, 0); 681d272bb00Sthorpej return; 682d272bb00Sthorpej } 683d272bb00Sthorpej SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q); 684092c2019Sthorpej rcount = cbp->cb_buf.b_bcount; 685d272bb00Sthorpej bn += btodb(rcount); 686d272bb00Sthorpej addr += rcount; 687d272bb00Sthorpej } 688d272bb00Sthorpej 689d272bb00Sthorpej /* Now fire off the requests. */ 690d272bb00Sthorpej while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) { 691d272bb00Sthorpej SIMPLEQ_REMOVE_HEAD(&cbufq, cbp, cb_q); 692092c2019Sthorpej if ((cbp->cb_buf.b_flags & B_READ) == 0) 693092c2019Sthorpej cbp->cb_buf.b_vp->v_numoutput++; 694092c2019Sthorpej VOP_STRATEGY(&cbp->cb_buf); 6956f9db1eeShpeyerl } 6966f9db1eeShpeyerl } 6976f9db1eeShpeyerl 6986f9db1eeShpeyerl /* 6996f9db1eeShpeyerl * Build a component buffer header. 7006f9db1eeShpeyerl */ 701092c2019Sthorpej static struct ccdbuf * 702092c2019Sthorpej ccdbuffer(cs, bp, bn, addr, bcount) 7036f9db1eeShpeyerl register struct ccd_softc *cs; 7046f9db1eeShpeyerl struct buf *bp; 7056f9db1eeShpeyerl daddr_t bn; 7066f9db1eeShpeyerl caddr_t addr; 7076f9db1eeShpeyerl long bcount; 7086f9db1eeShpeyerl { 70900172c10Sthorpej register struct ccdcinfo *ci; 710f694af67Scgd register struct ccdbuf *cbp; 7116f9db1eeShpeyerl register daddr_t cbn, cboff; 712902855d6Sthorpej register u_int64_t cbc; 7137770d7c4Sthorpej int ccdisk; 7146f9db1eeShpeyerl 7156f9db1eeShpeyerl #ifdef DEBUG 7163214723fShpeyerl if (ccddebug & CCDB_IO) 71786373f8cSchristos printf("ccdbuffer(%p, %p, %d, %p, %ld)\n", 7186f9db1eeShpeyerl cs, bp, bn, addr, bcount); 7196f9db1eeShpeyerl #endif 7206f9db1eeShpeyerl /* 7216f9db1eeShpeyerl * Determine which component bn falls in. 7226f9db1eeShpeyerl */ 7236f9db1eeShpeyerl cbn = bn; 7246f9db1eeShpeyerl cboff = 0; 72577d85de2Sthorpej 7266f9db1eeShpeyerl /* 7276f9db1eeShpeyerl * Serially concatenated 7286f9db1eeShpeyerl */ 7296f9db1eeShpeyerl if (cs->sc_ileave == 0) { 7306f9db1eeShpeyerl register daddr_t sblk; 7316f9db1eeShpeyerl 7326f9db1eeShpeyerl sblk = 0; 7337770d7c4Sthorpej for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk]; 7347770d7c4Sthorpej cbn >= sblk + ci->ci_size; 7357770d7c4Sthorpej ccdisk++, ci = &cs->sc_cinfo[ccdisk]) 7366f9db1eeShpeyerl sblk += ci->ci_size; 7376f9db1eeShpeyerl cbn -= sblk; 7386f9db1eeShpeyerl } 7396f9db1eeShpeyerl /* 7406f9db1eeShpeyerl * Interleaved 7416f9db1eeShpeyerl */ 7426f9db1eeShpeyerl else { 7436f9db1eeShpeyerl register struct ccdiinfo *ii; 7447770d7c4Sthorpej int off; 7456f9db1eeShpeyerl 7466f9db1eeShpeyerl cboff = cbn % cs->sc_ileave; 7476f9db1eeShpeyerl cbn /= cs->sc_ileave; 7486f9db1eeShpeyerl for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 7496f9db1eeShpeyerl if (ii->ii_startblk > cbn) 7506f9db1eeShpeyerl break; 7516f9db1eeShpeyerl ii--; 7526f9db1eeShpeyerl off = cbn - ii->ii_startblk; 7536f9db1eeShpeyerl if (ii->ii_ndisk == 1) { 7546f9db1eeShpeyerl ccdisk = ii->ii_index[0]; 7556f9db1eeShpeyerl cbn = ii->ii_startoff + off; 7566f9db1eeShpeyerl } else { 7576f9db1eeShpeyerl ccdisk = ii->ii_index[off % ii->ii_ndisk]; 7586f9db1eeShpeyerl cbn = ii->ii_startoff + off / ii->ii_ndisk; 7596f9db1eeShpeyerl } 7606f9db1eeShpeyerl cbn *= cs->sc_ileave; 7616f9db1eeShpeyerl ci = &cs->sc_cinfo[ccdisk]; 7626f9db1eeShpeyerl } 76377d85de2Sthorpej 7646f9db1eeShpeyerl /* 7656f9db1eeShpeyerl * Fill in the component buf structure. 7666f9db1eeShpeyerl */ 76743561361Sthorpej cbp = CCD_GETBUF(cs); 768092c2019Sthorpej if (cbp == NULL) 769092c2019Sthorpej return (NULL); 770f694af67Scgd cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 771d318abdbSchristos cbp->cb_buf.b_iodone = ccdiodone; 772f694af67Scgd cbp->cb_buf.b_proc = bp->b_proc; 77377d85de2Sthorpej cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */ 774f694af67Scgd cbp->cb_buf.b_blkno = cbn + cboff; 775f694af67Scgd cbp->cb_buf.b_data = addr; 77677d85de2Sthorpej cbp->cb_buf.b_vp = ci->ci_vp; 7776f9db1eeShpeyerl if (cs->sc_ileave == 0) 778902855d6Sthorpej cbc = dbtob((u_int64_t)(ci->ci_size - cbn)); 7796f9db1eeShpeyerl else 780902855d6Sthorpej cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff)); 781902855d6Sthorpej cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount; 782f694af67Scgd 7836f9db1eeShpeyerl /* 784f694af67Scgd * context for ccdiodone 7856f9db1eeShpeyerl */ 786f694af67Scgd cbp->cb_obp = bp; 787*c6aa25bfSthorpej cbp->cb_sc = cs; 7887770d7c4Sthorpej cbp->cb_comp = ccdisk; 789f694af67Scgd 7906f9db1eeShpeyerl #ifdef DEBUG 7913214723fShpeyerl if (ccddebug & CCDB_IO) 792c27c2868Sfair printf(" dev 0x%x(u%d): cbp %p bn %d addr %p bcnt %ld\n", 793f694af67Scgd ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 794f694af67Scgd cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 7956f9db1eeShpeyerl #endif 796092c2019Sthorpej 797092c2019Sthorpej return (cbp); 7986f9db1eeShpeyerl } 7996f9db1eeShpeyerl 80077d85de2Sthorpej static void 8013214723fShpeyerl ccdintr(cs, bp) 8023214723fShpeyerl register struct ccd_softc *cs; 8033214723fShpeyerl register struct buf *bp; 8046f9db1eeShpeyerl { 8056f9db1eeShpeyerl 8066f9db1eeShpeyerl #ifdef DEBUG 8073214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 80886373f8cSchristos printf("ccdintr(%p, %p)\n", cs, bp); 8096f9db1eeShpeyerl #endif 8106f9db1eeShpeyerl /* 8116f9db1eeShpeyerl * Request is done for better or worse, wakeup the top half. 8126f9db1eeShpeyerl */ 8136f9db1eeShpeyerl if (bp->b_flags & B_ERROR) 8146f9db1eeShpeyerl bp->b_resid = bp->b_bcount; 8155b39541eSthorpej disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid)); 8166f9db1eeShpeyerl biodone(bp); 8176f9db1eeShpeyerl } 8186f9db1eeShpeyerl 8196f9db1eeShpeyerl /* 82077d85de2Sthorpej * Called at interrupt time. 8216f9db1eeShpeyerl * Mark the component as done and if all components are done, 8226f9db1eeShpeyerl * take a ccd interrupt. 8236f9db1eeShpeyerl */ 8243214723fShpeyerl void 825d318abdbSchristos ccdiodone(vbp) 826d318abdbSchristos struct buf *vbp; 8276f9db1eeShpeyerl { 828d318abdbSchristos struct ccdbuf *cbp = (struct ccdbuf *) vbp; 829*c6aa25bfSthorpej struct buf *bp = cbp->cb_obp; 830*c6aa25bfSthorpej struct ccd_softc *cs = cbp->cb_sc; 83100172c10Sthorpej int count, s; 8326f9db1eeShpeyerl 8336f9db1eeShpeyerl s = splbio(); 8346f9db1eeShpeyerl #ifdef DEBUG 8353214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 83686373f8cSchristos printf("ccdiodone(%p)\n", cbp); 8373214723fShpeyerl if (ccddebug & CCDB_IO) { 83886373f8cSchristos printf("ccdiodone: bp %p bcount %ld resid %ld\n", 8396f9db1eeShpeyerl bp, bp->b_bcount, bp->b_resid); 840c27c2868Sfair printf(" dev 0x%x(u%d), cbp %p bn %d addr %p bcnt %ld\n", 841f694af67Scgd cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 842f694af67Scgd cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 843f694af67Scgd cbp->cb_buf.b_bcount); 8446f9db1eeShpeyerl } 8456f9db1eeShpeyerl #endif 8466f9db1eeShpeyerl 847f694af67Scgd if (cbp->cb_buf.b_flags & B_ERROR) { 8486f9db1eeShpeyerl bp->b_flags |= B_ERROR; 849732dd94aSthorpej bp->b_error = cbp->cb_buf.b_error ? 850732dd94aSthorpej cbp->cb_buf.b_error : EIO; 851732dd94aSthorpej 85200172c10Sthorpej printf("%s: error %d on component %d\n", 85300172c10Sthorpej cs->sc_xname, bp->b_error, cbp->cb_comp); 8546f9db1eeShpeyerl } 855f694af67Scgd count = cbp->cb_buf.b_bcount; 85643561361Sthorpej CCD_PUTBUF(cs, cbp); 8576f9db1eeShpeyerl 8586f9db1eeShpeyerl /* 8596f9db1eeShpeyerl * If all done, "interrupt". 8606f9db1eeShpeyerl */ 8616f9db1eeShpeyerl bp->b_resid -= count; 8626f9db1eeShpeyerl if (bp->b_resid < 0) 8636f9db1eeShpeyerl panic("ccdiodone: count"); 8643214723fShpeyerl if (bp->b_resid == 0) 865*c6aa25bfSthorpej ccdintr(cs, bp); 8666f9db1eeShpeyerl splx(s); 8676f9db1eeShpeyerl } 8686f9db1eeShpeyerl 86977d85de2Sthorpej /* ARGSUSED */ 8707263209cSmycroft int 87177d85de2Sthorpej ccdread(dev, uio, flags) 8723214723fShpeyerl dev_t dev; 8733214723fShpeyerl struct uio *uio; 87477d85de2Sthorpej int flags; 8753214723fShpeyerl { 87677d85de2Sthorpej int unit = ccdunit(dev); 87777d85de2Sthorpej struct ccd_softc *cs; 8783214723fShpeyerl 8793214723fShpeyerl #ifdef DEBUG 8803214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 881c27c2868Sfair printf("ccdread(0x%x, %p)\n", dev, uio); 8823214723fShpeyerl #endif 88377d85de2Sthorpej if (unit >= numccd) 88477d85de2Sthorpej return (ENXIO); 88577d85de2Sthorpej cs = &ccd_softc[unit]; 88677d85de2Sthorpej 88777d85de2Sthorpej if ((cs->sc_flags & CCDF_INITED) == 0) 88877d85de2Sthorpej return (ENXIO); 88977d85de2Sthorpej 89077d85de2Sthorpej /* 89177d85de2Sthorpej * XXX: It's not clear that using minphys() is completely safe, 89277d85de2Sthorpej * in particular, for raw I/O. Underlying devices might have some 89377d85de2Sthorpej * non-obvious limits, because of the copy to user-space. 89477d85de2Sthorpej */ 8953214723fShpeyerl return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio)); 8963214723fShpeyerl } 8973214723fShpeyerl 89877d85de2Sthorpej /* ARGSUSED */ 8997263209cSmycroft int 90077d85de2Sthorpej ccdwrite(dev, uio, flags) 9013214723fShpeyerl dev_t dev; 9023214723fShpeyerl struct uio *uio; 90377d85de2Sthorpej int flags; 9043214723fShpeyerl { 90577d85de2Sthorpej int unit = ccdunit(dev); 90677d85de2Sthorpej struct ccd_softc *cs; 9073214723fShpeyerl 9083214723fShpeyerl #ifdef DEBUG 9093214723fShpeyerl if (ccddebug & CCDB_FOLLOW) 910c27c2868Sfair printf("ccdwrite(0x%x, %p)\n", dev, uio); 9113214723fShpeyerl #endif 91277d85de2Sthorpej if (unit >= numccd) 91377d85de2Sthorpej return (ENXIO); 91477d85de2Sthorpej cs = &ccd_softc[unit]; 91577d85de2Sthorpej 91677d85de2Sthorpej if ((cs->sc_flags & CCDF_INITED) == 0) 91777d85de2Sthorpej return (ENXIO); 91877d85de2Sthorpej 91977d85de2Sthorpej /* 92077d85de2Sthorpej * XXX: It's not clear that using minphys() is completely safe, 92177d85de2Sthorpej * in particular, for raw I/O. Underlying devices might have some 92277d85de2Sthorpej * non-obvious limits, because of the copy to user-space. 92377d85de2Sthorpej */ 9243214723fShpeyerl return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio)); 9253214723fShpeyerl } 9263214723fShpeyerl 92777d85de2Sthorpej int 92877d85de2Sthorpej ccdioctl(dev, cmd, data, flag, p) 9296f9db1eeShpeyerl dev_t dev; 9306ac2bbfcScgd u_long cmd; 9316f9db1eeShpeyerl caddr_t data; 9326f9db1eeShpeyerl int flag; 93377d85de2Sthorpej struct proc *p; 9346f9db1eeShpeyerl { 93577d85de2Sthorpej int unit = ccdunit(dev); 9360272b2abSthorpej int i, j, lookedup = 0, error; 9378f8b0d91Smycroft int part, pmask; 93877d85de2Sthorpej struct ccd_softc *cs; 93977d85de2Sthorpej struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 94077d85de2Sthorpej char **cpp; 94177d85de2Sthorpej struct vnode **vpp; 94277d85de2Sthorpej 94377d85de2Sthorpej if (unit >= numccd) 94477d85de2Sthorpej return (ENXIO); 94577d85de2Sthorpej cs = &ccd_softc[unit]; 94677d85de2Sthorpej 9474cea35ebSthorpej /* Must be open for writes for these commands... */ 9484cea35ebSthorpej switch (cmd) { 9494cea35ebSthorpej case CCDIOCSET: 9504cea35ebSthorpej case CCDIOCCLR: 9514cea35ebSthorpej case DIOCSDINFO: 9524cea35ebSthorpej case DIOCWDINFO: 9534cea35ebSthorpej case DIOCWLABEL: 9544cea35ebSthorpej if ((flag & FWRITE) == 0) 9554cea35ebSthorpej return (EBADF); 9564cea35ebSthorpej } 9574cea35ebSthorpej 9580272b2abSthorpej if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0) 9590272b2abSthorpej return (error); 9600272b2abSthorpej 9614cea35ebSthorpej /* Must be initialized for these... */ 9624cea35ebSthorpej switch (cmd) { 9634cea35ebSthorpej case CCDIOCCLR: 964d72a3b2dSkleink case DIOCGDINFO: 9654cea35ebSthorpej case DIOCSDINFO: 9664cea35ebSthorpej case DIOCWDINFO: 9674cea35ebSthorpej case DIOCGPART: 9684cea35ebSthorpej case DIOCWLABEL: 969939e074dSthorpej case DIOCGDEFLABEL: 9700272b2abSthorpej if ((cs->sc_flags & CCDF_INITED) == 0) { 9710272b2abSthorpej error = ENXIO; 9720272b2abSthorpej goto out; 9730272b2abSthorpej } 9744cea35ebSthorpej } 9754cea35ebSthorpej 97677d85de2Sthorpej switch (cmd) { 97777d85de2Sthorpej case CCDIOCSET: 9780272b2abSthorpej if (cs->sc_flags & CCDF_INITED) { 9790272b2abSthorpej error = EBUSY; 9800272b2abSthorpej goto out; 9810272b2abSthorpej } 982b8dcfbd3Sthorpej 983ab27c3f8Sthorpej /* Validate the flags. */ 9840272b2abSthorpej if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) { 9850272b2abSthorpej error = EINVAL; 9860272b2abSthorpej goto out; 9870272b2abSthorpej } 988ab27c3f8Sthorpej 98977d85de2Sthorpej /* Fill in some important bits. */ 9900272b2abSthorpej cs->sc_ileave = ccio->ccio_ileave; 9910272b2abSthorpej cs->sc_nccdisks = ccio->ccio_ndisks; 9920272b2abSthorpej cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK; 99377d85de2Sthorpej 99477d85de2Sthorpej /* 99577d85de2Sthorpej * Allocate space for and copy in the array of 99677d85de2Sthorpej * componet pathnames and device numbers. 99777d85de2Sthorpej */ 99877d85de2Sthorpej cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 99977d85de2Sthorpej M_DEVBUF, M_WAITOK); 100077d85de2Sthorpej vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 100177d85de2Sthorpej M_DEVBUF, M_WAITOK); 100277d85de2Sthorpej 100377d85de2Sthorpej error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 100477d85de2Sthorpej ccio->ccio_ndisks * sizeof(char **)); 100577d85de2Sthorpej if (error) { 100677d85de2Sthorpej free(vpp, M_DEVBUF); 100777d85de2Sthorpej free(cpp, M_DEVBUF); 10080272b2abSthorpej goto out; 10096f9db1eeShpeyerl } 10106f9db1eeShpeyerl 101177d85de2Sthorpej #ifdef DEBUG 101277d85de2Sthorpej if (ccddebug & CCDB_INIT) 101377d85de2Sthorpej for (i = 0; i < ccio->ccio_ndisks; ++i) 101486373f8cSchristos printf("ccdioctl: component %d: 0x%p\n", 101577d85de2Sthorpej i, cpp[i]); 101677d85de2Sthorpej #endif 101777d85de2Sthorpej 101877d85de2Sthorpej for (i = 0; i < ccio->ccio_ndisks; ++i) { 101977d85de2Sthorpej #ifdef DEBUG 102077d85de2Sthorpej if (ccddebug & CCDB_INIT) 102186373f8cSchristos printf("ccdioctl: lookedup = %d\n", lookedup); 102277d85de2Sthorpej #endif 1023d318abdbSchristos if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) { 102477d85de2Sthorpej for (j = 0; j < lookedup; ++j) 1025a2db2c18Sthorpej (void)vn_close(vpp[j], FREAD|FWRITE, 102677d85de2Sthorpej p->p_ucred, p); 102777d85de2Sthorpej free(vpp, M_DEVBUF); 102877d85de2Sthorpej free(cpp, M_DEVBUF); 10290272b2abSthorpej goto out; 103077d85de2Sthorpej } 103177d85de2Sthorpej ++lookedup; 103277d85de2Sthorpej } 103377d85de2Sthorpej 103477d85de2Sthorpej /* 103577d85de2Sthorpej * Initialize the ccd. Fills in the softc for us. 103677d85de2Sthorpej */ 10370272b2abSthorpej if ((error = ccdinit(cs, cpp, vpp, p)) != 0) { 103877d85de2Sthorpej for (j = 0; j < lookedup; ++j) 1039a1bc3740Sthorpej (void)vn_close(vpp[j], FREAD|FWRITE, 104077d85de2Sthorpej p->p_ucred, p); 104177d85de2Sthorpej free(vpp, M_DEVBUF); 104277d85de2Sthorpej free(cpp, M_DEVBUF); 10430272b2abSthorpej goto out; 104477d85de2Sthorpej } 104577d85de2Sthorpej 10460272b2abSthorpej /* We can free the temporary variables now. */ 10470272b2abSthorpej free(vpp, M_DEVBUF); 10480272b2abSthorpej free(cpp, M_DEVBUF); 10490272b2abSthorpej 105077d85de2Sthorpej /* 105177d85de2Sthorpej * The ccd has been successfully initialized, so 10525b39541eSthorpej * we can place it into the array. Don't try to 10535b39541eSthorpej * read the disklabel until the disk has been attached, 10545b39541eSthorpej * because space for the disklabel is allocated 10555b39541eSthorpej * in disk_attach(); 105677d85de2Sthorpej */ 105777d85de2Sthorpej ccio->ccio_unit = unit; 105877d85de2Sthorpej ccio->ccio_size = cs->sc_size; 10595b39541eSthorpej 10605b39541eSthorpej /* Attach the disk. */ 10615b39541eSthorpej disk_attach(&cs->sc_dkdev); 10625b39541eSthorpej 106343561361Sthorpej /* Initialize the component buffer pool. */ 106443561361Sthorpej pool_init(&cs->sc_cbufpool, sizeof(struct ccdbuf), 0, 106543561361Sthorpej 0, 0, "ccdpl", 0, NULL, NULL, M_DEVBUF); 106643561361Sthorpej 10675b39541eSthorpej /* Try and read the disklabel. */ 106877d85de2Sthorpej ccdgetdisklabel(dev); 106977d85de2Sthorpej break; 107077d85de2Sthorpej 107177d85de2Sthorpej case CCDIOCCLR: 107277d85de2Sthorpej /* 107377d85de2Sthorpej * Don't unconfigure if any other partitions are open 107477d85de2Sthorpej * or if both the character and block flavors of this 107577d85de2Sthorpej * partition are open. 107677d85de2Sthorpej */ 107777d85de2Sthorpej part = DISKPART(dev); 107877d85de2Sthorpej pmask = (1 << part); 107977d85de2Sthorpej if ((cs->sc_dkdev.dk_openmask & ~pmask) || 108077d85de2Sthorpej ((cs->sc_dkdev.dk_bopenmask & pmask) && 1081b8dcfbd3Sthorpej (cs->sc_dkdev.dk_copenmask & pmask))) { 10820272b2abSthorpej error = EBUSY; 10830272b2abSthorpej goto out; 1084b8dcfbd3Sthorpej } 108577d85de2Sthorpej 108677d85de2Sthorpej /* 108777d85de2Sthorpej * Free ccd_softc information and clear entry. 108877d85de2Sthorpej */ 10897268bf55Sthorpej 10907268bf55Sthorpej /* Close the components and free their pathnames. */ 109177d85de2Sthorpej for (i = 0; i < cs->sc_nccdisks; ++i) { 109277d85de2Sthorpej /* 109377d85de2Sthorpej * XXX: this close could potentially fail and 109477d85de2Sthorpej * cause Bad Things. Maybe we need to force 109577d85de2Sthorpej * the close to happen? 109677d85de2Sthorpej */ 109777d85de2Sthorpej #ifdef DEBUG 109877d85de2Sthorpej if (ccddebug & CCDB_VNODE) 109977d85de2Sthorpej vprint("CCDIOCCLR: vnode info", 110077d85de2Sthorpej cs->sc_cinfo[i].ci_vp); 110177d85de2Sthorpej #endif 110277d85de2Sthorpej (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 110377d85de2Sthorpej p->p_ucred, p); 110477d85de2Sthorpej free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 110577d85de2Sthorpej } 11067268bf55Sthorpej 11077268bf55Sthorpej /* Free interleave index. */ 11087268bf55Sthorpej for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 11097268bf55Sthorpej free(cs->sc_itable[i].ii_index, M_DEVBUF); 11107268bf55Sthorpej 11117268bf55Sthorpej /* Free component info and interleave table. */ 111277d85de2Sthorpej free(cs->sc_cinfo, M_DEVBUF); 111377d85de2Sthorpej free(cs->sc_itable, M_DEVBUF); 1114664cb046Sthorpej cs->sc_flags &= ~CCDF_INITED; 111577d85de2Sthorpej 111643561361Sthorpej /* Free the component buffer pool. */ 111743561361Sthorpej pool_destroy(&cs->sc_cbufpool); 111843561361Sthorpej 11195b39541eSthorpej /* Detatch the disk. */ 1120fb815819Shpeyerl disk_detach(&cs->sc_dkdev); 112177d85de2Sthorpej break; 112277d85de2Sthorpej 112377d85de2Sthorpej case DIOCGDINFO: 11245b39541eSthorpej *(struct disklabel *)data = *(cs->sc_dkdev.dk_label); 112577d85de2Sthorpej break; 112677d85de2Sthorpej 112777d85de2Sthorpej case DIOCGPART: 11285b39541eSthorpej ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label; 112977d85de2Sthorpej ((struct partinfo *)data)->part = 11305b39541eSthorpej &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 113177d85de2Sthorpej break; 113277d85de2Sthorpej 113377d85de2Sthorpej case DIOCWDINFO: 113477d85de2Sthorpej case DIOCSDINFO: 113577d85de2Sthorpej cs->sc_flags |= CCDF_LABELLING; 113677d85de2Sthorpej 11375b39541eSthorpej error = setdisklabel(cs->sc_dkdev.dk_label, 11385b39541eSthorpej (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel); 113977d85de2Sthorpej if (error == 0) { 114077d85de2Sthorpej if (cmd == DIOCWDINFO) 114177d85de2Sthorpej error = writedisklabel(CCDLABELDEV(dev), 11425b39541eSthorpej ccdstrategy, cs->sc_dkdev.dk_label, 11435b39541eSthorpej cs->sc_dkdev.dk_cpulabel); 114477d85de2Sthorpej } 114577d85de2Sthorpej 114677d85de2Sthorpej cs->sc_flags &= ~CCDF_LABELLING; 114777d85de2Sthorpej break; 114877d85de2Sthorpej 114977d85de2Sthorpej case DIOCWLABEL: 115077d85de2Sthorpej if (*(int *)data != 0) 115177d85de2Sthorpej cs->sc_flags |= CCDF_WLABEL; 115277d85de2Sthorpej else 115377d85de2Sthorpej cs->sc_flags &= ~CCDF_WLABEL; 115477d85de2Sthorpej break; 115577d85de2Sthorpej 1156939e074dSthorpej case DIOCGDEFLABEL: 1157939e074dSthorpej ccdgetdefaultlabel(cs, (struct disklabel *)data); 1158939e074dSthorpej break; 1159939e074dSthorpej 116077d85de2Sthorpej default: 11610272b2abSthorpej error = ENOTTY; 116277d85de2Sthorpej } 116377d85de2Sthorpej 11640272b2abSthorpej out: 11650272b2abSthorpej (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL); 11660272b2abSthorpej return (error); 116777d85de2Sthorpej } 116877d85de2Sthorpej 116977d85de2Sthorpej int 11706f9db1eeShpeyerl ccdsize(dev) 11716f9db1eeShpeyerl dev_t dev; 11726f9db1eeShpeyerl { 117377d85de2Sthorpej struct ccd_softc *cs; 1174e06bb29bSthorpej struct disklabel *lp; 1175e06bb29bSthorpej int part, unit, omask, size; 11766f9db1eeShpeyerl 1177e06bb29bSthorpej unit = ccdunit(dev); 1178e06bb29bSthorpej if (unit >= numccd) 11796f9db1eeShpeyerl return (-1); 1180e06bb29bSthorpej cs = &ccd_softc[unit]; 118177d85de2Sthorpej 118277d85de2Sthorpej if ((cs->sc_flags & CCDF_INITED) == 0) 118377d85de2Sthorpej return (-1); 118477d85de2Sthorpej 1185e06bb29bSthorpej part = DISKPART(dev); 1186e06bb29bSthorpej omask = cs->sc_dkdev.dk_openmask & (1 << part); 1187e06bb29bSthorpej lp = cs->sc_dkdev.dk_label; 1188e06bb29bSthorpej 1189e06bb29bSthorpej if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc)) 1190e06bb29bSthorpej return (-1); 1191e06bb29bSthorpej 1192e06bb29bSthorpej if (lp->d_partitions[part].p_fstype != FS_SWAP) 119377d85de2Sthorpej size = -1; 119477d85de2Sthorpej else 1195e06bb29bSthorpej size = lp->d_partitions[part].p_size * 1196e06bb29bSthorpej (lp->d_secsize / DEV_BSIZE); 119777d85de2Sthorpej 1198e06bb29bSthorpej if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc)) 119977d85de2Sthorpej return (-1); 120077d85de2Sthorpej 120177d85de2Sthorpej return (size); 12026f9db1eeShpeyerl } 12036f9db1eeShpeyerl 1204bc9de323Scgd int 1205bc9de323Scgd ccddump(dev, blkno, va, size) 1206bc9de323Scgd dev_t dev; 1207bc9de323Scgd daddr_t blkno; 1208bc9de323Scgd caddr_t va; 1209bc9de323Scgd size_t size; 12106f9db1eeShpeyerl { 1211bc9de323Scgd 1212bc9de323Scgd /* Not implemented. */ 1213bc9de323Scgd return ENXIO; 12146f9db1eeShpeyerl } 121577d85de2Sthorpej 121677d85de2Sthorpej /* 121777d85de2Sthorpej * Lookup the provided name in the filesystem. If the file exists, 121877d85de2Sthorpej * is a valid block device, and isn't being used by anyone else, 121977d85de2Sthorpej * set *vpp to the file's vnode. 122077d85de2Sthorpej */ 122177d85de2Sthorpej static int 122277d85de2Sthorpej ccdlookup(path, p, vpp) 122377d85de2Sthorpej char *path; 122477d85de2Sthorpej struct proc *p; 122577d85de2Sthorpej struct vnode **vpp; /* result */ 122677d85de2Sthorpej { 122777d85de2Sthorpej struct nameidata nd; 122877d85de2Sthorpej struct vnode *vp; 122977d85de2Sthorpej struct vattr va; 123077d85de2Sthorpej int error; 123177d85de2Sthorpej 123277d85de2Sthorpej NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1233d318abdbSchristos if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 123477d85de2Sthorpej #ifdef DEBUG 1235d318abdbSchristos if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 123686373f8cSchristos printf("ccdlookup: vn_open error = %d\n", error); 123777d85de2Sthorpej #endif 123877d85de2Sthorpej return (error); 123977d85de2Sthorpej } 124077d85de2Sthorpej vp = nd.ni_vp; 124177d85de2Sthorpej 124277d85de2Sthorpej if (vp->v_usecount > 1) { 1243331fee62Sross VOP_UNLOCK(vp, 0); 124477d85de2Sthorpej (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 124577d85de2Sthorpej return (EBUSY); 124677d85de2Sthorpej } 124777d85de2Sthorpej 1248d318abdbSchristos if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) { 124977d85de2Sthorpej #ifdef DEBUG 1250d318abdbSchristos if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 125186373f8cSchristos printf("ccdlookup: getattr error = %d\n", error); 125277d85de2Sthorpej #endif 1253331fee62Sross VOP_UNLOCK(vp, 0); 125477d85de2Sthorpej (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 125577d85de2Sthorpej return (error); 125677d85de2Sthorpej } 125777d85de2Sthorpej 125877d85de2Sthorpej /* XXX: eventually we should handle VREG, too. */ 125977d85de2Sthorpej if (va.va_type != VBLK) { 1260331fee62Sross VOP_UNLOCK(vp, 0); 126177d85de2Sthorpej (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 126277d85de2Sthorpej return (ENOTBLK); 126377d85de2Sthorpej } 126477d85de2Sthorpej 126577d85de2Sthorpej #ifdef DEBUG 126677d85de2Sthorpej if (ccddebug & CCDB_VNODE) 126777d85de2Sthorpej vprint("ccdlookup: vnode info", vp); 126877d85de2Sthorpej #endif 126977d85de2Sthorpej 1270331fee62Sross VOP_UNLOCK(vp, 0); 127177d85de2Sthorpej *vpp = vp; 127277d85de2Sthorpej return (0); 127377d85de2Sthorpej } 127477d85de2Sthorpej 127577d85de2Sthorpej static void 1276939e074dSthorpej ccdgetdefaultlabel(cs, lp) 1277939e074dSthorpej struct ccd_softc *cs; 1278939e074dSthorpej struct disklabel *lp; 127977d85de2Sthorpej { 128077d85de2Sthorpej struct ccdgeom *ccg = &cs->sc_geom; 128177d85de2Sthorpej 128277d85de2Sthorpej bzero(lp, sizeof(*lp)); 128377d85de2Sthorpej 128477d85de2Sthorpej lp->d_secperunit = cs->sc_size; 128577d85de2Sthorpej lp->d_secsize = ccg->ccg_secsize; 128677d85de2Sthorpej lp->d_nsectors = ccg->ccg_nsectors; 128777d85de2Sthorpej lp->d_ntracks = ccg->ccg_ntracks; 128877d85de2Sthorpej lp->d_ncylinders = ccg->ccg_ncylinders; 128989d4987eSthorpej lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 129077d85de2Sthorpej 129177d85de2Sthorpej strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 129277d85de2Sthorpej lp->d_type = DTYPE_CCD; 129377d85de2Sthorpej strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 129477d85de2Sthorpej lp->d_rpm = 3600; 129577d85de2Sthorpej lp->d_interleave = 1; 129677d85de2Sthorpej lp->d_flags = 0; 129777d85de2Sthorpej 129877d85de2Sthorpej lp->d_partitions[RAW_PART].p_offset = 0; 129977d85de2Sthorpej lp->d_partitions[RAW_PART].p_size = cs->sc_size; 130077d85de2Sthorpej lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 130177d85de2Sthorpej lp->d_npartitions = RAW_PART + 1; 130277d85de2Sthorpej 130377d85de2Sthorpej lp->d_magic = DISKMAGIC; 130477d85de2Sthorpej lp->d_magic2 = DISKMAGIC; 13055b39541eSthorpej lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label); 1306939e074dSthorpej } 1307939e074dSthorpej 1308939e074dSthorpej /* 1309939e074dSthorpej * Read the disklabel from the ccd. If one is not present, fake one 1310939e074dSthorpej * up. 1311939e074dSthorpej */ 1312939e074dSthorpej static void 1313939e074dSthorpej ccdgetdisklabel(dev) 1314939e074dSthorpej dev_t dev; 1315939e074dSthorpej { 1316939e074dSthorpej int unit = ccdunit(dev); 1317939e074dSthorpej struct ccd_softc *cs = &ccd_softc[unit]; 1318939e074dSthorpej char *errstring; 1319939e074dSthorpej struct disklabel *lp = cs->sc_dkdev.dk_label; 1320939e074dSthorpej struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel; 1321939e074dSthorpej 1322939e074dSthorpej bzero(clp, sizeof(*clp)); 1323939e074dSthorpej 1324939e074dSthorpej ccdgetdefaultlabel(cs, lp); 132577d85de2Sthorpej 132677d85de2Sthorpej /* 132777d85de2Sthorpej * Call the generic disklabel extraction routine. 132877d85de2Sthorpej */ 1329d318abdbSchristos errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1330d318abdbSchristos cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel); 1331d318abdbSchristos if (errstring) 133277d85de2Sthorpej ccdmakedisklabel(cs); 1333512a0186Senami else { 1334512a0186Senami int i; 1335512a0186Senami struct partition *pp; 1336512a0186Senami 1337512a0186Senami /* 1338512a0186Senami * Sanity check whether the found disklabel is valid. 1339512a0186Senami * 1340512a0186Senami * This is necessary since total size of ccd may vary 1341512a0186Senami * when an interleave is changed even though exactly 1342512a0186Senami * same componets are used, and old disklabel may used 1343512a0186Senami * if that is found. 1344512a0186Senami */ 1345512a0186Senami if (lp->d_secperunit != cs->sc_size) 1346512a0186Senami printf("WARNING: %s: " 1347512a0186Senami "total sector size in disklabel (%d) != " 1348512a0186Senami "the size of ccd (%d)\n", cs->sc_xname, 1349512a0186Senami lp->d_secperunit, cs->sc_size); 1350512a0186Senami for (i = 0; i < lp->d_npartitions; i++) { 1351512a0186Senami pp = &lp->d_partitions[i]; 1352512a0186Senami if (pp->p_offset + pp->p_size > cs->sc_size) 13539b770726Senami printf("WARNING: %s: end of partition `%c' " 13549b770726Senami "exceeds the size of ccd (%d)\n", 13559b770726Senami cs->sc_xname, 'a' + i, cs->sc_size); 1356512a0186Senami } 1357512a0186Senami } 135877d85de2Sthorpej 135977d85de2Sthorpej #ifdef DEBUG 136077d85de2Sthorpej /* It's actually extremely common to have unlabeled ccds. */ 136177d85de2Sthorpej if (ccddebug & CCDB_LABEL) 136277d85de2Sthorpej if (errstring != NULL) 136386373f8cSchristos printf("%s: %s\n", cs->sc_xname, errstring); 136477d85de2Sthorpej #endif 136577d85de2Sthorpej } 136677d85de2Sthorpej 136777d85de2Sthorpej /* 136877d85de2Sthorpej * Take care of things one might want to take care of in the event 136977d85de2Sthorpej * that a disklabel isn't present. 137077d85de2Sthorpej */ 137177d85de2Sthorpej static void 137277d85de2Sthorpej ccdmakedisklabel(cs) 137377d85de2Sthorpej struct ccd_softc *cs; 137477d85de2Sthorpej { 13755b39541eSthorpej struct disklabel *lp = cs->sc_dkdev.dk_label; 137677d85de2Sthorpej 137777d85de2Sthorpej /* 137877d85de2Sthorpej * For historical reasons, if there's no disklabel present 137977d85de2Sthorpej * the raw partition must be marked FS_BSDFFS. 138077d85de2Sthorpej */ 138177d85de2Sthorpej lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 138277d85de2Sthorpej 138377d85de2Sthorpej strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1384939e074dSthorpej 1385939e074dSthorpej lp->d_checksum = dkcksum(lp); 138677d85de2Sthorpej } 138777d85de2Sthorpej 138877d85de2Sthorpej #ifdef DEBUG 138977d85de2Sthorpej static void 139077d85de2Sthorpej printiinfo(ii) 139177d85de2Sthorpej struct ccdiinfo *ii; 139277d85de2Sthorpej { 139377d85de2Sthorpej register int ix, i; 139477d85de2Sthorpej 139577d85de2Sthorpej for (ix = 0; ii->ii_ndisk; ix++, ii++) { 139686373f8cSchristos printf(" itab[%d]: #dk %d sblk %d soff %d", 139777d85de2Sthorpej ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 139877d85de2Sthorpej for (i = 0; i < ii->ii_ndisk; i++) 139986373f8cSchristos printf(" %d", ii->ii_index[i]); 140086373f8cSchristos printf("\n"); 140177d85de2Sthorpej } 140277d85de2Sthorpej } 14036f9db1eeShpeyerl #endif 1404