geom_ccd.c revision 33363
1130803Smarcel/* $Id: ccd.c,v 1.28 1998/01/31 03:19:06 eivind Exp $ */ 2130803Smarcel 3130803Smarcel/* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */ 4130803Smarcel 5130803Smarcel/* 6130803Smarcel * Copyright (c) 1995 Jason R. Thorpe. 7130803Smarcel * All rights reserved. 8130803Smarcel * 9130803Smarcel * Redistribution and use in source and binary forms, with or without 10130803Smarcel * modification, are permitted provided that the following conditions 11130803Smarcel * are met: 12130803Smarcel * 1. Redistributions of source code must retain the above copyright 13130803Smarcel * notice, this list of conditions and the following disclaimer. 14130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright 15130803Smarcel * notice, this list of conditions and the following disclaimer in the 16130803Smarcel * documentation and/or other materials provided with the distribution. 17130803Smarcel * 3. All advertising materials mentioning features or use of this software 18130803Smarcel * must display the following acknowledgement: 19130803Smarcel * This product includes software developed for the NetBSD Project 20130803Smarcel * by Jason R. Thorpe. 21130803Smarcel * 4. The name of the author may not be used to endorse or promote products 22130803Smarcel * derived from this software without specific prior written permission. 23130803Smarcel * 24130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25130803Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26130803Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27130803Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28130803Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29130803Smarcel * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30130803Smarcel * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31130803Smarcel * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32130803Smarcel * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34130803Smarcel * SUCH DAMAGE. 35130803Smarcel */ 36130803Smarcel 37130803Smarcel/* 38130803Smarcel * Copyright (c) 1988 University of Utah. 39130803Smarcel * Copyright (c) 1990, 1993 40130803Smarcel * The Regents of the University of California. All rights reserved. 41130803Smarcel * 42130803Smarcel * This code is derived from software contributed to Berkeley by 43130803Smarcel * the Systems Programming Group of the University of Utah Computer 44130803Smarcel * Science Department. 45130803Smarcel * 46130803Smarcel * Redistribution and use in source and binary forms, with or without 47130803Smarcel * modification, are permitted provided that the following conditions 48130803Smarcel * are met: 49130803Smarcel * 1. Redistributions of source code must retain the above copyright 50130803Smarcel * notice, this list of conditions and the following disclaimer. 51130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright 52130803Smarcel * notice, this list of conditions and the following disclaimer in the 53130803Smarcel * documentation and/or other materials provided with the distribution. 54130803Smarcel * 3. All advertising materials mentioning features or use of this software 55130803Smarcel * must display the following acknowledgement: 56130803Smarcel * This product includes software developed by the University of 57130803Smarcel * California, Berkeley and its contributors. 58130803Smarcel * 4. Neither the name of the University nor the names of its contributors 59130803Smarcel * may be used to endorse or promote products derived from this software 60130803Smarcel * without specific prior written permission. 61130803Smarcel * 62130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65130803Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72130803Smarcel * SUCH DAMAGE. 73130803Smarcel * 74130803Smarcel * from: Utah $Hdr: cd.c 1.6 90/11/28$ 75130803Smarcel * 76130803Smarcel * @(#)cd.c 8.2 (Berkeley) 11/16/93 77130803Smarcel */ 78130803Smarcel 79130803Smarcel/* 80130803Smarcel * "Concatenated" disk driver. 81130803Smarcel * 82130803Smarcel * Dynamic configuration and disklabel support by: 83130803Smarcel * Jason R. Thorpe <thorpej@nas.nasa.gov> 84130803Smarcel * Numerical Aerodynamic Simulation Facility 85130803Smarcel * Mail Stop 258-6 86130803Smarcel * NASA Ames Research Center 87130803Smarcel * Moffett Field, CA 94035 88130803Smarcel */ 89130803Smarcel 90130803Smarcel#include "ccd.h" 91130803Smarcel#if NCCD > 0 92130803Smarcel 93130803Smarcel#include <sys/param.h> 94130803Smarcel#include <sys/systm.h> 95130803Smarcel#include <sys/kernel.h> 96130803Smarcel#include <sys/proc.h> 97130803Smarcel#include <sys/buf.h> 98130803Smarcel#include <sys/malloc.h> 99130803Smarcel#include <sys/namei.h> 100130803Smarcel#include <sys/conf.h> 101130803Smarcel#include <sys/stat.h> 102130803Smarcel#include <sys/sysctl.h> 103130803Smarcel#include <sys/disklabel.h> 104130803Smarcel#include <ufs/ffs/fs.h> 105130803Smarcel#include <sys/device.h> 106130803Smarcel#undef KERNEL /* XXX */ 107130803Smarcel#include <sys/disk.h> 108130803Smarcel#define KERNEL 109130803Smarcel#include <sys/fcntl.h> 110130803Smarcel#include <sys/vnode.h> 111130803Smarcel 112130803Smarcel#include <sys/ccdvar.h> 113130803Smarcel 114130803Smarcel#if defined(CCDDEBUG) && !defined(DEBUG) 115130803Smarcel#define DEBUG 116130803Smarcel#endif 117130803Smarcel 118130803Smarcel#ifdef DEBUG 119130803Smarcel#define CCDB_FOLLOW 0x01 120130803Smarcel#define CCDB_INIT 0x02 121130803Smarcel#define CCDB_IO 0x04 122130803Smarcel#define CCDB_LABEL 0x08 123130803Smarcel#define CCDB_VNODE 0x10 124130803Smarcelstatic int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | 125130803Smarcel CCDB_VNODE; 126130803SmarcelSYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, ""); 127130803Smarcel#undef DEBUG 128130803Smarcel#endif 129130803Smarcel 130130803Smarcel#define ccdunit(x) dkunit(x) 131130803Smarcel#define ccdpart(x) dkpart(x) 132130803Smarcel 133130803Smarcel/* 134130803Smarcel This is how mirroring works (only writes are special): 135130803Smarcel 136130803Smarcel When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s 137130803Smarcel linked together by the cb_mirror field. "cb_pflags & 138130803Smarcel CCDPF_MIRROR_DONE" is set to 0 on both of them. 139130803Smarcel 140130803Smarcel When a component returns to ccdiodone(), it checks if "cb_pflags & 141130803Smarcel CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's 142130803Smarcel flag and returns. If it is, it means its partner has already 143130803Smarcel returned, so it will go to the regular cleanup. 144130803Smarcel 145130803Smarcel */ 146130803Smarcel 147130803Smarcelstruct ccdbuf { 148130803Smarcel struct buf cb_buf; /* new I/O buf */ 149130803Smarcel struct buf *cb_obp; /* ptr. to original I/O buf */ 150130803Smarcel int cb_unit; /* target unit */ 151130803Smarcel int cb_comp; /* target component */ 152130803Smarcel int cb_pflags; /* mirror/parity status flag */ 153130803Smarcel struct ccdbuf *cb_mirror; /* mirror counterpart */ 154130803Smarcel}; 155130803Smarcel 156130803Smarcel/* bits in cb_pflags */ 157130803Smarcel#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ 158130803Smarcel 159130803Smarcel#define getccdbuf() \ 160130803Smarcel ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) 161130803Smarcel#define putccdbuf(cbp) \ 162130803Smarcel free((caddr_t)(cbp), M_DEVBUF) 163130803Smarcel 164130803Smarcel#define CCDLABELDEV(dev) \ 165130803Smarcel (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART))) 166130803Smarcel 167130803Smarcelstatic d_open_t ccdopen; 168130803Smarcelstatic d_close_t ccdclose; 169130803Smarcelstatic d_strategy_t ccdstrategy; 170130803Smarcelstatic d_ioctl_t ccdioctl; 171130803Smarcelstatic d_dump_t ccddump; 172130803Smarcelstatic d_psize_t ccdsize; 173130803Smarcel 174130803Smarcel#define CDEV_MAJOR 74 175130803Smarcel#define BDEV_MAJOR 21 176130803Smarcel 177130803Smarcelstatic struct cdevsw ccd_cdevsw; 178130803Smarcelstatic struct bdevsw ccd_bdevsw = { 179130803Smarcel ccdopen, ccdclose, ccdstrategy, ccdioctl, 180130803Smarcel ccddump, ccdsize, 0, 181130803Smarcel "ccd", &ccd_cdevsw, -1 182130803Smarcel}; 183130803Smarcel 184130803Smarcel/* Called by main() during pseudo-device attachment */ 185130803Smarcelstatic void ccdattach __P((void *)); 186130803SmarcelPSEUDO_SET(ccdattach, ccd); 187130803Smarcel 188130803Smarcel/* called by biodone() at interrupt time */ 189130803Smarcelstatic void ccdiodone __P((struct ccdbuf *cbp)); 190130803Smarcel 191130803Smarcelstatic void ccdstart __P((struct ccd_softc *, struct buf *)); 192130803Smarcelstatic void ccdinterleave __P((struct ccd_softc *, int)); 193130803Smarcelstatic void ccdintr __P((struct ccd_softc *, struct buf *)); 194130803Smarcelstatic int ccdinit __P((struct ccddevice *, char **, struct proc *)); 195130803Smarcelstatic int ccdlookup __P((char *, struct proc *p, struct vnode **)); 196130803Smarcelstatic void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *, 197130803Smarcel struct buf *, daddr_t, caddr_t, long)); 198130803Smarcelstatic void ccdgetdisklabel __P((dev_t)); 199130803Smarcelstatic void ccdmakedisklabel __P((struct ccd_softc *)); 200130803Smarcelstatic int ccdlock __P((struct ccd_softc *)); 201130803Smarcelstatic void ccdunlock __P((struct ccd_softc *)); 202130803Smarcel 203130803Smarcel#ifdef DEBUG 204130803Smarcelstatic void printiinfo __P((struct ccdiinfo *)); 205130803Smarcel#endif 206130803Smarcel 207130803Smarcel/* Non-private for the benefit of libkvm. */ 208130803Smarcelstruct ccd_softc *ccd_softc; 209130803Smarcelstruct ccddevice *ccddevs; 210130803Smarcelstatic int numccd = 0; 211130803Smarcel 212130803Smarcelstatic int ccd_devsw_installed = 0; 213130803Smarcel 214130803Smarcel/* 215130803Smarcel * Number of blocks to untouched in front of a component partition. 216130803Smarcel * This is to avoid violating its disklabel area when it starts at the 217130803Smarcel * beginning of the slice. 218130803Smarcel */ 219130803Smarcel#if !defined(CCD_OFFSET) 220130803Smarcel#define CCD_OFFSET 16 221130803Smarcel#endif 222130803Smarcel 223130803Smarcel/* 224130803Smarcel * Called by main() during pseudo-device attachment. All we need 225130803Smarcel * to do is allocate enough space for devices to be configured later, and 226130803Smarcel * add devsw entries. 227130803Smarcel */ 228130803Smarcelstatic void 229130803Smarcelccdattach(dummy) 230130803Smarcel void *dummy; 231130803Smarcel{ 232130803Smarcel int i; 233130803Smarcel int num = NCCD; 234130803Smarcel 235130803Smarcel if (num > 1) 236130803Smarcel printf("ccd0-%d: Concatenated disk drivers\n", num-1); 237130803Smarcel else 238130803Smarcel printf("ccd0: Concatenated disk driver\n"); 239130803Smarcel 240130803Smarcel ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), 241130803Smarcel M_DEVBUF, M_NOWAIT); 242130803Smarcel ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice), 243130803Smarcel M_DEVBUF, M_NOWAIT); 244130803Smarcel if ((ccd_softc == NULL) || (ccddevs == NULL)) { 245130803Smarcel printf("WARNING: no memory for concatenated disks\n"); 246130803Smarcel if (ccd_softc != NULL) 247130803Smarcel free(ccd_softc, M_DEVBUF); 248130803Smarcel if (ccddevs != NULL) 249130803Smarcel free(ccddevs, M_DEVBUF); 250130803Smarcel return; 251130803Smarcel } 252130803Smarcel numccd = num; 253130803Smarcel bzero(ccd_softc, num * sizeof(struct ccd_softc)); 254130803Smarcel bzero(ccddevs, num * sizeof(struct ccddevice)); 255130803Smarcel 256130803Smarcel /* XXX: is this necessary? */ 257130803Smarcel for (i = 0; i < numccd; ++i) 258130803Smarcel ccddevs[i].ccd_dk = -1; 259130803Smarcel 260130803Smarcel if( ! ccd_devsw_installed ) { 261130803Smarcel bdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &ccd_bdevsw); 262130803Smarcel ccd_devsw_installed = 1; 263130803Smarcel } 264130803Smarcel else { 265130803Smarcel printf("huh?\n"); 266130803Smarcel } 267130803Smarcel} 268130803Smarcel 269130803Smarcelstatic int 270130803Smarcelccdinit(ccd, cpaths, p) 271130803Smarcel struct ccddevice *ccd; 272130803Smarcel char **cpaths; 273130803Smarcel struct proc *p; 274130803Smarcel{ 275130803Smarcel register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; 276130803Smarcel register struct ccdcinfo *ci = NULL; /* XXX */ 277130803Smarcel register size_t size; 278130803Smarcel register int ix; 279130803Smarcel struct vnode *vp; 280130803Smarcel struct vattr va; 281130803Smarcel size_t minsize; 282130803Smarcel int maxsecsize; 283130803Smarcel struct partinfo dpart; 284130803Smarcel struct ccdgeom *ccg = &cs->sc_geom; 285130803Smarcel char tmppath[MAXPATHLEN]; 286130803Smarcel int error; 287130803Smarcel 288130803Smarcel#ifdef DEBUG 289130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 290130803Smarcel printf("ccdinit: unit %d\n", ccd->ccd_unit); 291130803Smarcel#endif 292130803Smarcel 293130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 294130803Smarcel cs->sc_dk = ccd->ccd_dk; 295130803Smarcel#endif 296130803Smarcel cs->sc_size = 0; 297130803Smarcel cs->sc_ileave = ccd->ccd_interleave; 298130803Smarcel cs->sc_nccdisks = ccd->ccd_ndev; 299130803Smarcel 300130803Smarcel /* Allocate space for the component info. */ 301130803Smarcel cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), 302130803Smarcel M_DEVBUF, M_WAITOK); 303130803Smarcel 304130803Smarcel /* 305130803Smarcel * Verify that each component piece exists and record 306130803Smarcel * relevant information about it. 307130803Smarcel */ 308130803Smarcel maxsecsize = 0; 309130803Smarcel minsize = 0; 310130803Smarcel for (ix = 0; ix < cs->sc_nccdisks; ix++) { 311130803Smarcel vp = ccd->ccd_vpp[ix]; 312130803Smarcel ci = &cs->sc_cinfo[ix]; 313130803Smarcel ci->ci_vp = vp; 314130803Smarcel 315130803Smarcel /* 316130803Smarcel * Copy in the pathname of the component. 317130803Smarcel */ 318130803Smarcel bzero(tmppath, sizeof(tmppath)); /* sanity */ 319130803Smarcel if (error = copyinstr(cpaths[ix], tmppath, 320130803Smarcel MAXPATHLEN, &ci->ci_pathlen)) { 321130803Smarcel#ifdef DEBUG 322130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 323130803Smarcel printf("ccd%d: can't copy path, error = %d\n", 324130803Smarcel ccd->ccd_unit, error); 325130803Smarcel#endif 326130803Smarcel while (ci > cs->sc_cinfo) { 327130803Smarcel ci--; 328130803Smarcel free(ci->ci_path, M_DEVBUF); 329130803Smarcel } 330130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 331130803Smarcel return (error); 332130803Smarcel } 333130803Smarcel ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); 334130803Smarcel bcopy(tmppath, ci->ci_path, ci->ci_pathlen); 335130803Smarcel 336130803Smarcel /* 337130803Smarcel * XXX: Cache the component's dev_t. 338130803Smarcel */ 339130803Smarcel if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { 340130803Smarcel#ifdef DEBUG 341130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 342130803Smarcel printf("ccd%d: %s: getattr failed %s = %d\n", 343130803Smarcel ccd->ccd_unit, ci->ci_path, 344130803Smarcel "error", error); 345130803Smarcel#endif 346130803Smarcel while (ci >= cs->sc_cinfo) { 347130803Smarcel free(ci->ci_path, M_DEVBUF); 348130803Smarcel ci--; 349130803Smarcel } 350130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 351130803Smarcel return (error); 352130803Smarcel } 353130803Smarcel ci->ci_dev = va.va_rdev; 354130803Smarcel 355130803Smarcel /* 356130803Smarcel * Get partition information for the component. 357130803Smarcel */ 358130803Smarcel if (error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, 359130803Smarcel FREAD, p->p_ucred, p)) { 360130803Smarcel#ifdef DEBUG 361130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 362130803Smarcel printf("ccd%d: %s: ioctl failed, error = %d\n", 363130803Smarcel ccd->ccd_unit, ci->ci_path, error); 364130803Smarcel#endif 365130803Smarcel while (ci >= cs->sc_cinfo) { 366130803Smarcel free(ci->ci_path, M_DEVBUF); 367130803Smarcel ci--; 368130803Smarcel } 369130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 370130803Smarcel return (error); 371130803Smarcel } 372130803Smarcel if (dpart.part->p_fstype == FS_BSDFFS) { 373130803Smarcel maxsecsize = 374130803Smarcel ((dpart.disklab->d_secsize > maxsecsize) ? 375130803Smarcel dpart.disklab->d_secsize : maxsecsize); 376130803Smarcel size = dpart.part->p_size - CCD_OFFSET; 377130803Smarcel } else { 378130803Smarcel#ifdef DEBUG 379130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 380130803Smarcel printf("ccd%d: %s: incorrect partition type\n", 381130803Smarcel ccd->ccd_unit, ci->ci_path); 382130803Smarcel#endif 383130803Smarcel while (ci >= cs->sc_cinfo) { 384130803Smarcel free(ci->ci_path, M_DEVBUF); 385130803Smarcel ci--; 386130803Smarcel } 387130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 388130803Smarcel return (EFTYPE); 389130803Smarcel } 390130803Smarcel 391130803Smarcel /* 392130803Smarcel * Calculate the size, truncating to an interleave 393130803Smarcel * boundary if necessary. 394130803Smarcel */ 395130803Smarcel 396130803Smarcel if (cs->sc_ileave > 1) 397130803Smarcel size -= size % cs->sc_ileave; 398130803Smarcel 399130803Smarcel if (size == 0) { 400130803Smarcel#ifdef DEBUG 401130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 402130803Smarcel printf("ccd%d: %s: size == 0\n", 403130803Smarcel ccd->ccd_unit, ci->ci_path); 404130803Smarcel#endif 405130803Smarcel while (ci >= cs->sc_cinfo) { 406130803Smarcel free(ci->ci_path, M_DEVBUF); 407130803Smarcel ci--; 408130803Smarcel } 409130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 410130803Smarcel return (ENODEV); 411130803Smarcel } 412130803Smarcel 413130803Smarcel if (minsize == 0 || size < minsize) 414130803Smarcel minsize = size; 415130803Smarcel ci->ci_size = size; 416130803Smarcel cs->sc_size += size; 417130803Smarcel } 418130803Smarcel 419130803Smarcel /* 420130803Smarcel * Don't allow the interleave to be smaller than 421130803Smarcel * the biggest component sector. 422130803Smarcel */ 423130803Smarcel if ((cs->sc_ileave > 0) && 424130803Smarcel (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 425130803Smarcel#ifdef DEBUG 426130803Smarcel if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 427130803Smarcel printf("ccd%d: interleave must be at least %d\n", 428130803Smarcel ccd->ccd_unit, (maxsecsize / DEV_BSIZE)); 429130803Smarcel#endif 430130803Smarcel while (ci >= cs->sc_cinfo) { 431130803Smarcel free(ci->ci_path, M_DEVBUF); 432130803Smarcel ci--; 433130803Smarcel } 434130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 435130803Smarcel return (EINVAL); 436130803Smarcel } 437130803Smarcel 438130803Smarcel /* 439130803Smarcel * If uniform interleave is desired set all sizes to that of 440130803Smarcel * the smallest component. 441130803Smarcel */ 442130803Smarcel if (ccd->ccd_flags & CCDF_UNIFORM) { 443130803Smarcel for (ci = cs->sc_cinfo; 444130803Smarcel ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 445130803Smarcel ci->ci_size = minsize; 446130803Smarcel if (ccd->ccd_flags & CCDF_MIRROR) { 447130803Smarcel /* 448130803Smarcel * Check to see if an even number of components 449130803Smarcel * have been specified. 450130803Smarcel */ 451130803Smarcel if (cs->sc_nccdisks % 2) { 452130803Smarcel printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit ); 453130803Smarcel while (ci > cs->sc_cinfo) { 454130803Smarcel ci--; 455130803Smarcel free(ci->ci_path, M_DEVBUF); 456130803Smarcel } 457130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 458130803Smarcel return (EINVAL); 459130803Smarcel } 460130803Smarcel cs->sc_size = (cs->sc_nccdisks/2) * minsize; 461130803Smarcel } 462130803Smarcel else if (ccd->ccd_flags & CCDF_PARITY) 463130803Smarcel cs->sc_size = (cs->sc_nccdisks-1) * minsize; 464130803Smarcel else 465130803Smarcel cs->sc_size = cs->sc_nccdisks * minsize; 466130803Smarcel } 467130803Smarcel 468130803Smarcel /* 469130803Smarcel * Construct the interleave table. 470130803Smarcel */ 471130803Smarcel ccdinterleave(cs, ccd->ccd_unit); 472130803Smarcel 473130803Smarcel /* 474130803Smarcel * Create pseudo-geometry based on 1MB cylinders. It's 475130803Smarcel * pretty close. 476130803Smarcel */ 477130803Smarcel ccg->ccg_secsize = maxsecsize; 478130803Smarcel ccg->ccg_ntracks = 1; 479130803Smarcel ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); 480130803Smarcel ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 481130803Smarcel 482130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 483130803Smarcel if (ccd->ccd_dk >= 0) 484130803Smarcel dk_wpms[ccd->ccd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 485130803Smarcel#endif 486130803Smarcel 487130803Smarcel cs->sc_flags |= CCDF_INITED; 488130803Smarcel cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */ 489130803Smarcel cs->sc_unit = ccd->ccd_unit; 490130803Smarcel return (0); 491130803Smarcel} 492130803Smarcel 493130803Smarcelstatic void 494130803Smarcelccdinterleave(cs, unit) 495130803Smarcel register struct ccd_softc *cs; 496130803Smarcel int unit; 497130803Smarcel{ 498130803Smarcel register struct ccdcinfo *ci, *smallci; 499130803Smarcel register struct ccdiinfo *ii; 500130803Smarcel register daddr_t bn, lbn; 501130803Smarcel register int ix; 502130803Smarcel u_long size; 503130803Smarcel 504130803Smarcel#ifdef DEBUG 505130803Smarcel if (ccddebug & CCDB_INIT) 506130803Smarcel printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); 507130803Smarcel#endif 508130803Smarcel /* 509130803Smarcel * Allocate an interleave table. 510130803Smarcel * Chances are this is too big, but we don't care. 511130803Smarcel */ 512130803Smarcel size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 513130803Smarcel cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 514130803Smarcel bzero((caddr_t)cs->sc_itable, size); 515130803Smarcel 516130803Smarcel /* 517130803Smarcel * Trivial case: no interleave (actually interleave of disk size). 518130803Smarcel * Each table entry represents a single component in its entirety. 519130803Smarcel */ 520130803Smarcel if (cs->sc_ileave == 0) { 521130803Smarcel bn = 0; 522130803Smarcel ii = cs->sc_itable; 523130803Smarcel 524130803Smarcel for (ix = 0; ix < cs->sc_nccdisks; ix++) { 525130803Smarcel /* Allocate space for ii_index. */ 526130803Smarcel ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); 527130803Smarcel ii->ii_ndisk = 1; 528130803Smarcel ii->ii_startblk = bn; 529130803Smarcel ii->ii_startoff = 0; 530130803Smarcel ii->ii_index[0] = ix; 531130803Smarcel bn += cs->sc_cinfo[ix].ci_size; 532130803Smarcel ii++; 533130803Smarcel } 534130803Smarcel ii->ii_ndisk = 0; 535130803Smarcel#ifdef DEBUG 536130803Smarcel if (ccddebug & CCDB_INIT) 537130803Smarcel printiinfo(cs->sc_itable); 538130803Smarcel#endif 539130803Smarcel return; 540130803Smarcel } 541130803Smarcel 542130803Smarcel /* 543130803Smarcel * The following isn't fast or pretty; it doesn't have to be. 544130803Smarcel */ 545130803Smarcel size = 0; 546130803Smarcel bn = lbn = 0; 547130803Smarcel for (ii = cs->sc_itable; ; ii++) { 548130803Smarcel /* Allocate space for ii_index. */ 549130803Smarcel ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), 550130803Smarcel M_DEVBUF, M_WAITOK); 551130803Smarcel 552130803Smarcel /* 553130803Smarcel * Locate the smallest of the remaining components 554130803Smarcel */ 555130803Smarcel smallci = NULL; 556130803Smarcel for (ci = cs->sc_cinfo; 557130803Smarcel ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 558130803Smarcel if (ci->ci_size > size && 559130803Smarcel (smallci == NULL || 560130803Smarcel ci->ci_size < smallci->ci_size)) 561130803Smarcel smallci = ci; 562130803Smarcel 563130803Smarcel /* 564130803Smarcel * Nobody left, all done 565130803Smarcel */ 566130803Smarcel if (smallci == NULL) { 567130803Smarcel ii->ii_ndisk = 0; 568130803Smarcel break; 569130803Smarcel } 570130803Smarcel 571130803Smarcel /* 572130803Smarcel * Record starting logical block and component offset 573130803Smarcel */ 574130803Smarcel ii->ii_startblk = bn / cs->sc_ileave; 575130803Smarcel ii->ii_startoff = lbn; 576130803Smarcel 577130803Smarcel /* 578130803Smarcel * Determine how many disks take part in this interleave 579130803Smarcel * and record their indices. 580130803Smarcel */ 581130803Smarcel ix = 0; 582130803Smarcel for (ci = cs->sc_cinfo; 583130803Smarcel ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 584130803Smarcel if (ci->ci_size >= smallci->ci_size) 585130803Smarcel ii->ii_index[ix++] = ci - cs->sc_cinfo; 586130803Smarcel ii->ii_ndisk = ix; 587130803Smarcel bn += ix * (smallci->ci_size - size); 588130803Smarcel lbn = smallci->ci_size / cs->sc_ileave; 589130803Smarcel size = smallci->ci_size; 590130803Smarcel } 591130803Smarcel#ifdef DEBUG 592130803Smarcel if (ccddebug & CCDB_INIT) 593130803Smarcel printiinfo(cs->sc_itable); 594130803Smarcel#endif 595130803Smarcel} 596130803Smarcel 597130803Smarcel/* ARGSUSED */ 598130803Smarcelstatic int 599130803Smarcelccdopen(dev, flags, fmt, p) 600130803Smarcel dev_t dev; 601130803Smarcel int flags, fmt; 602130803Smarcel struct proc *p; 603130803Smarcel{ 604130803Smarcel int unit = ccdunit(dev); 605130803Smarcel struct ccd_softc *cs; 606130803Smarcel struct disklabel *lp; 607130803Smarcel int error = 0, part, pmask; 608130803Smarcel 609130803Smarcel#ifdef DEBUG 610130803Smarcel if (ccddebug & CCDB_FOLLOW) 611130803Smarcel printf("ccdopen(%x, %x)\n", dev, flags); 612130803Smarcel#endif 613130803Smarcel if (unit >= numccd) 614130803Smarcel return (ENXIO); 615130803Smarcel cs = &ccd_softc[unit]; 616130803Smarcel 617130803Smarcel if (error = ccdlock(cs)) 618130803Smarcel return (error); 619130803Smarcel 620130803Smarcel lp = &cs->sc_dkdev.dk_label; 621130803Smarcel 622130803Smarcel part = ccdpart(dev); 623130803Smarcel pmask = (1 << part); 624130803Smarcel 625130803Smarcel /* 626130803Smarcel * If we're initialized, check to see if there are any other 627130803Smarcel * open partitions. If not, then it's safe to update 628130803Smarcel * the in-core disklabel. 629130803Smarcel */ 630130803Smarcel if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0)) 631130803Smarcel ccdgetdisklabel(dev); 632130803Smarcel 633130803Smarcel /* Check that the partition exists. */ 634130803Smarcel if (part != RAW_PART && ((part >= lp->d_npartitions) || 635130803Smarcel (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 636130803Smarcel error = ENXIO; 637130803Smarcel goto done; 638130803Smarcel } 639130803Smarcel 640130803Smarcel /* Prevent our unit from being unconfigured while open. */ 641130803Smarcel switch (fmt) { 642130803Smarcel case S_IFCHR: 643130803Smarcel cs->sc_dkdev.dk_copenmask |= pmask; 644130803Smarcel break; 645130803Smarcel 646130803Smarcel case S_IFBLK: 647130803Smarcel cs->sc_dkdev.dk_bopenmask |= pmask; 648130803Smarcel break; 649130803Smarcel } 650130803Smarcel cs->sc_dkdev.dk_openmask = 651130803Smarcel cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 652130803Smarcel 653130803Smarcel done: 654130803Smarcel ccdunlock(cs); 655130803Smarcel return (0); 656130803Smarcel} 657130803Smarcel 658130803Smarcel/* ARGSUSED */ 659130803Smarcelstatic int 660130803Smarcelccdclose(dev, flags, fmt, p) 661130803Smarcel dev_t dev; 662130803Smarcel int flags, fmt; 663130803Smarcel struct proc *p; 664130803Smarcel{ 665130803Smarcel int unit = ccdunit(dev); 666130803Smarcel struct ccd_softc *cs; 667130803Smarcel int error = 0, part; 668130803Smarcel 669130803Smarcel#ifdef DEBUG 670130803Smarcel if (ccddebug & CCDB_FOLLOW) 671130803Smarcel printf("ccdclose(%x, %x)\n", dev, flags); 672130803Smarcel#endif 673130803Smarcel 674130803Smarcel if (unit >= numccd) 675130803Smarcel return (ENXIO); 676130803Smarcel cs = &ccd_softc[unit]; 677130803Smarcel 678130803Smarcel if (error = ccdlock(cs)) 679130803Smarcel return (error); 680130803Smarcel 681130803Smarcel part = ccdpart(dev); 682130803Smarcel 683130803Smarcel /* ...that much closer to allowing unconfiguration... */ 684130803Smarcel switch (fmt) { 685130803Smarcel case S_IFCHR: 686130803Smarcel cs->sc_dkdev.dk_copenmask &= ~(1 << part); 687130803Smarcel break; 688130803Smarcel 689130803Smarcel case S_IFBLK: 690130803Smarcel cs->sc_dkdev.dk_bopenmask &= ~(1 << part); 691130803Smarcel break; 692130803Smarcel } 693130803Smarcel cs->sc_dkdev.dk_openmask = 694130803Smarcel cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 695130803Smarcel 696130803Smarcel ccdunlock(cs); 697130803Smarcel return (0); 698130803Smarcel} 699130803Smarcel 700130803Smarcelstatic void 701130803Smarcelccdstrategy(bp) 702130803Smarcel register struct buf *bp; 703130803Smarcel{ 704130803Smarcel register int unit = ccdunit(bp->b_dev); 705130803Smarcel register struct ccd_softc *cs = &ccd_softc[unit]; 706130803Smarcel register int s; 707130803Smarcel int wlabel; 708130803Smarcel struct disklabel *lp; 709130803Smarcel 710130803Smarcel#ifdef DEBUG 711130803Smarcel if (ccddebug & CCDB_FOLLOW) 712130803Smarcel printf("ccdstrategy(%x): unit %d\n", bp, unit); 713130803Smarcel#endif 714130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) { 715130803Smarcel bp->b_error = ENXIO; 716130803Smarcel bp->b_flags |= B_ERROR; 717130803Smarcel goto done; 718130803Smarcel } 719130803Smarcel 720130803Smarcel /* If it's a nil transfer, wake up the top half now. */ 721130803Smarcel if (bp->b_bcount == 0) 722130803Smarcel goto done; 723130803Smarcel 724130803Smarcel lp = &cs->sc_dkdev.dk_label; 725130803Smarcel 726130803Smarcel /* 727130803Smarcel * Do bounds checking and adjust transfer. If there's an 728130803Smarcel * error, the bounds check will flag that for us. 729130803Smarcel */ 730130803Smarcel wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 731130803Smarcel if (ccdpart(bp->b_dev) != RAW_PART) 732130803Smarcel if (bounds_check_with_label(bp, lp, wlabel) <= 0) 733130803Smarcel goto done; 734130803Smarcel 735130803Smarcel bp->b_resid = bp->b_bcount; 736130803Smarcel 737130803Smarcel /* 738130803Smarcel * "Start" the unit. 739130803Smarcel */ 740130803Smarcel s = splbio(); 741130803Smarcel ccdstart(cs, bp); 742130803Smarcel splx(s); 743130803Smarcel return; 744130803Smarceldone: 745130803Smarcel biodone(bp); 746130803Smarcel} 747130803Smarcel 748130803Smarcelstatic void 749130803Smarcelccdstart(cs, bp) 750130803Smarcel register struct ccd_softc *cs; 751130803Smarcel register struct buf *bp; 752130803Smarcel{ 753130803Smarcel register long bcount, rcount; 754130803Smarcel struct ccdbuf *cbp[4]; 755130803Smarcel /* XXX! : 2 reads and 2 writes for RAID 4/5 */ 756130803Smarcel caddr_t addr; 757130803Smarcel daddr_t bn; 758130803Smarcel struct partition *pp; 759130803Smarcel 760130803Smarcel#ifdef DEBUG 761130803Smarcel if (ccddebug & CCDB_FOLLOW) 762130803Smarcel printf("ccdstart(%x, %x)\n", cs, bp); 763130803Smarcel#endif 764130803Smarcel 765130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 766130803Smarcel /* 767130803Smarcel * Instrumentation (not very meaningful) 768130803Smarcel */ 769130803Smarcel cs->sc_nactive++; 770130803Smarcel if (cs->sc_dk >= 0) { 771130803Smarcel dk_busy |= 1 << cs->sc_dk; 772130803Smarcel dk_xfer[cs->sc_dk]++; 773130803Smarcel dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 774130803Smarcel } 775130803Smarcel#endif 776130803Smarcel 777130803Smarcel /* 778130803Smarcel * Translate the partition-relative block number to an absolute. 779130803Smarcel */ 780130803Smarcel bn = bp->b_blkno; 781130803Smarcel if (ccdpart(bp->b_dev) != RAW_PART) { 782130803Smarcel pp = &cs->sc_dkdev.dk_label.d_partitions[ccdpart(bp->b_dev)]; 783130803Smarcel bn += pp->p_offset; 784130803Smarcel } 785130803Smarcel 786130803Smarcel /* 787130803Smarcel * Allocate component buffers and fire off the requests 788130803Smarcel */ 789130803Smarcel addr = bp->b_data; 790130803Smarcel for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 791130803Smarcel ccdbuffer(cbp, cs, bp, bn, addr, bcount); 792130803Smarcel rcount = cbp[0]->cb_buf.b_bcount; 793130803Smarcel if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) 794130803Smarcel cbp[0]->cb_buf.b_vp->v_numoutput++; 795130803Smarcel VOP_STRATEGY(&cbp[0]->cb_buf); 796130803Smarcel if (cs->sc_cflags & CCDF_MIRROR && 797130803Smarcel (cbp[0]->cb_buf.b_flags & B_READ) == 0) { 798130803Smarcel /* mirror, start another write */ 799130803Smarcel cbp[1]->cb_buf.b_vp->v_numoutput++; 800130803Smarcel VOP_STRATEGY(&cbp[1]->cb_buf); 801130803Smarcel } 802130803Smarcel bn += btodb(rcount); 803130803Smarcel addr += rcount; 804130803Smarcel } 805130803Smarcel} 806130803Smarcel 807130803Smarcel/* 808130803Smarcel * Build a component buffer header. 809130803Smarcel */ 810130803Smarcelstatic void 811130803Smarcelccdbuffer(cb, cs, bp, bn, addr, bcount) 812130803Smarcel register struct ccdbuf **cb; 813130803Smarcel register struct ccd_softc *cs; 814130803Smarcel struct buf *bp; 815130803Smarcel daddr_t bn; 816130803Smarcel caddr_t addr; 817130803Smarcel long bcount; 818130803Smarcel{ 819130803Smarcel register struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ 820130803Smarcel register struct ccdbuf *cbp; 821130803Smarcel register daddr_t cbn, cboff; 822130803Smarcel 823130803Smarcel#ifdef DEBUG 824130803Smarcel if (ccddebug & CCDB_IO) 825130803Smarcel printf("ccdbuffer(%x, %x, %d, %x, %d)\n", 826130803Smarcel cs, bp, bn, addr, bcount); 827130803Smarcel#endif 828130803Smarcel /* 829130803Smarcel * Determine which component bn falls in. 830130803Smarcel */ 831130803Smarcel cbn = bn; 832130803Smarcel cboff = 0; 833130803Smarcel 834130803Smarcel /* 835130803Smarcel * Serially concatenated 836130803Smarcel */ 837130803Smarcel if (cs->sc_ileave == 0) { 838130803Smarcel register daddr_t sblk; 839130803Smarcel 840130803Smarcel sblk = 0; 841130803Smarcel for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 842130803Smarcel sblk += ci->ci_size; 843130803Smarcel cbn -= sblk; 844130803Smarcel } 845130803Smarcel /* 846130803Smarcel * Interleaved 847130803Smarcel */ 848130803Smarcel else { 849130803Smarcel register struct ccdiinfo *ii; 850130803Smarcel int ccdisk, off; 851130803Smarcel 852130803Smarcel cboff = cbn % cs->sc_ileave; 853130803Smarcel cbn /= cs->sc_ileave; 854130803Smarcel for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 855130803Smarcel if (ii->ii_startblk > cbn) 856130803Smarcel break; 857130803Smarcel ii--; 858130803Smarcel off = cbn - ii->ii_startblk; 859130803Smarcel if (ii->ii_ndisk == 1) { 860130803Smarcel ccdisk = ii->ii_index[0]; 861130803Smarcel cbn = ii->ii_startoff + off; 862130803Smarcel } else { 863130803Smarcel if (cs->sc_cflags & CCDF_MIRROR) { 864130803Smarcel ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)]; 865130803Smarcel cbn = ii->ii_startoff + off / (ii->ii_ndisk/2); 866130803Smarcel /* mirrored data */ 867130803Smarcel ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2]; 868130803Smarcel } 869130803Smarcel else if (cs->sc_cflags & CCDF_PARITY) { 870130803Smarcel ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)]; 871130803Smarcel cbn = ii->ii_startoff + off / (ii->ii_ndisk-1); 872130803Smarcel if (cbn % ii->ii_ndisk <= ccdisk) 873130803Smarcel ccdisk++; 874130803Smarcel } 875130803Smarcel else { 876130803Smarcel ccdisk = ii->ii_index[off % ii->ii_ndisk]; 877130803Smarcel cbn = ii->ii_startoff + off / ii->ii_ndisk; 878130803Smarcel } 879130803Smarcel } 880130803Smarcel cbn *= cs->sc_ileave; 881130803Smarcel ci = &cs->sc_cinfo[ccdisk]; 882130803Smarcel } 883130803Smarcel 884130803Smarcel /* 885130803Smarcel * Fill in the component buf structure. 886130803Smarcel */ 887130803Smarcel cbp = getccdbuf(); 888130803Smarcel cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 889130803Smarcel cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone; 890130803Smarcel cbp->cb_buf.b_proc = bp->b_proc; 891130803Smarcel cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */ 892130803Smarcel cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET; 893130803Smarcel cbp->cb_buf.b_data = addr; 894130803Smarcel cbp->cb_buf.b_vp = ci->ci_vp; 895130803Smarcel if (cs->sc_ileave == 0) 896130803Smarcel cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn); 897130803Smarcel else 898130803Smarcel cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff); 899130803Smarcel if (cbp->cb_buf.b_bcount > bcount) 900130803Smarcel cbp->cb_buf.b_bcount = bcount; 901130803Smarcel 902130803Smarcel cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount; 903130803Smarcel 904130803Smarcel /* 905130803Smarcel * context for ccdiodone 906130803Smarcel */ 907130803Smarcel cbp->cb_obp = bp; 908130803Smarcel cbp->cb_unit = cs - ccd_softc; 909130803Smarcel cbp->cb_comp = ci - cs->sc_cinfo; 910130803Smarcel 911130803Smarcel#ifdef DEBUG 912130803Smarcel if (ccddebug & CCDB_IO) 913130803Smarcel printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 914130803Smarcel ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 915130803Smarcel cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 916130803Smarcel#endif 917130803Smarcel cb[0] = cbp; 918130803Smarcel if (cs->sc_cflags & CCDF_MIRROR && 919130803Smarcel (cbp->cb_buf.b_flags & B_READ) == 0) { 920130803Smarcel /* mirror, start one more write */ 921130803Smarcel cbp = getccdbuf(); 922130803Smarcel *cbp = *cb[0]; 923130803Smarcel cbp->cb_buf.b_dev = ci2->ci_dev; 924130803Smarcel cbp->cb_buf.b_vp = ci2->ci_vp; 925130803Smarcel cbp->cb_comp = ci2 - cs->sc_cinfo; 926130803Smarcel cb[1] = cbp; 927130803Smarcel /* link together the ccdbuf's and clear "mirror done" flag */ 928130803Smarcel cb[0]->cb_mirror = cb[1]; 929130803Smarcel cb[1]->cb_mirror = cb[0]; 930130803Smarcel cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; 931130803Smarcel cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; 932130803Smarcel } 933130803Smarcel} 934130803Smarcel 935130803Smarcelstatic void 936130803Smarcelccdintr(cs, bp) 937130803Smarcel register struct ccd_softc *cs; 938130803Smarcel register struct buf *bp; 939130803Smarcel{ 940130803Smarcel 941130803Smarcel s = splbio(); 942130803Smarcel#ifdef DEBUG 943130803Smarcel if (ccddebug & CCDB_FOLLOW) 944130803Smarcel printf("ccdintr(%x, %x)\n", cs, bp); 945130803Smarcel#endif 946130803Smarcel /* 947130803Smarcel * Request is done for better or worse, wakeup the top half. 948130803Smarcel */ 949130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 950130803Smarcel --cs->sc_nactive; 951130803Smarcel#ifdef DIAGNOSTIC 952130803Smarcel if (cs->sc_nactive < 0) 953130803Smarcel panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit); 954130803Smarcel#endif 955130803Smarcel 956130803Smarcel if (cs->sc_nactive == 0 && cs->sc_dk >= 0) 957130803Smarcel dk_busy &= ~(1 << cs->sc_dk); 958130803Smarcel#endif 959130803Smarcel if (bp->b_flags & B_ERROR) 960130803Smarcel bp->b_resid = bp->b_bcount; 961130803Smarcel biodone(bp); 962130803Smarcel} 963130803Smarcel 964130803Smarcel/* 965130803Smarcel * Called at interrupt time. 966130803Smarcel * Mark the component as done and if all components are done, 967130803Smarcel * take a ccd interrupt. 968130803Smarcel */ 969130803Smarcelstatic void 970130803Smarcelccdiodone(cbp) 971130803Smarcel struct ccdbuf *cbp; 972130803Smarcel{ 973130803Smarcel register struct buf *bp = cbp->cb_obp; 974130803Smarcel register int unit = cbp->cb_unit; 975130803Smarcel int count, s; 976130803Smarcel 977130803Smarcel s = splbio(); 978130803Smarcel#ifdef DEBUG 979130803Smarcel if (ccddebug & CCDB_FOLLOW) 980130803Smarcel printf("ccdiodone(%x)\n", cbp); 981130803Smarcel if (ccddebug & CCDB_IO) { 982130803Smarcel printf("ccdiodone: bp %x bcount %d resid %d\n", 983130803Smarcel bp, bp->b_bcount, bp->b_resid); 984130803Smarcel printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 985130803Smarcel cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 986130803Smarcel cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 987130803Smarcel cbp->cb_buf.b_bcount); 988130803Smarcel } 989130803Smarcel#endif 990130803Smarcel 991130803Smarcel if (cbp->cb_buf.b_flags & B_ERROR) { 992130803Smarcel bp->b_flags |= B_ERROR; 993130803Smarcel bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO; 994130803Smarcel#ifdef DEBUG 995130803Smarcel printf("ccd%d: error %d on component %d\n", 996130803Smarcel unit, bp->b_error, cbp->cb_comp); 997130803Smarcel#endif 998130803Smarcel } 999130803Smarcel 1000130803Smarcel if (ccd_softc[unit].sc_cflags & CCDF_MIRROR && 1001130803Smarcel (cbp->cb_buf.b_flags & B_READ) == 0) 1002130803Smarcel if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 1003130803Smarcel /* I'm done before my counterpart, so just set 1004130803Smarcel partner's flag and return */ 1005130803Smarcel cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; 1006130803Smarcel putccdbuf(cbp); 1007130803Smarcel splx(s); 1008130803Smarcel return; 1009130803Smarcel } 1010130803Smarcel 1011130803Smarcel count = cbp->cb_buf.b_bcount; 1012130803Smarcel putccdbuf(cbp); 1013130803Smarcel 1014130803Smarcel /* 1015130803Smarcel * If all done, "interrupt". 1016130803Smarcel */ 1017130803Smarcel bp->b_resid -= count; 1018130803Smarcel if (bp->b_resid < 0) 1019130803Smarcel panic("ccdiodone: count"); 1020130803Smarcel if (bp->b_resid == 0) 1021130803Smarcel ccdintr(&ccd_softc[unit], bp); 1022130803Smarcel splx(s); 1023130803Smarcel} 1024130803Smarcel 1025130803Smarcelstatic int 1026130803Smarcelccdioctl(dev, cmd, data, flag, p) 1027130803Smarcel dev_t dev; 1028130803Smarcel int cmd; 1029130803Smarcel caddr_t data; 1030130803Smarcel int flag; 1031130803Smarcel struct proc *p; 1032130803Smarcel{ 1033130803Smarcel int unit = ccdunit(dev); 1034130803Smarcel int i, j, lookedup = 0, error = 0; 1035130803Smarcel int part, pmask, s; 1036130803Smarcel struct ccd_softc *cs; 1037130803Smarcel struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1038130803Smarcel struct ccddevice ccd; 1039130803Smarcel char **cpp; 1040130803Smarcel struct vnode **vpp; 1041130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1042130803Smarcel extern int dkn; 1043130803Smarcel#endif 1044130803Smarcel 1045130803Smarcel if (unit >= numccd) 1046130803Smarcel return (ENXIO); 1047130803Smarcel cs = &ccd_softc[unit]; 1048130803Smarcel 1049130803Smarcel bzero(&ccd, sizeof(ccd)); 1050130803Smarcel 1051130803Smarcel switch (cmd) { 1052130803Smarcel case CCDIOCSET: 1053130803Smarcel if (cs->sc_flags & CCDF_INITED) 1054130803Smarcel return (EBUSY); 1055130803Smarcel 1056130803Smarcel if ((flag & FWRITE) == 0) 1057130803Smarcel return (EBADF); 1058130803Smarcel 1059130803Smarcel if (error = ccdlock(cs)) 1060130803Smarcel return (error); 1061130803Smarcel 1062130803Smarcel /* Fill in some important bits. */ 1063130803Smarcel ccd.ccd_unit = unit; 1064130803Smarcel ccd.ccd_interleave = ccio->ccio_ileave; 1065130803Smarcel if (ccd.ccd_interleave == 0 && 1066130803Smarcel ((ccio->ccio_flags & CCDF_MIRROR) || 1067130803Smarcel (ccio->ccio_flags & CCDF_PARITY))) { 1068130803Smarcel printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit); 1069130803Smarcel ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY); 1070130803Smarcel } 1071130803Smarcel if ((ccio->ccio_flags & CCDF_MIRROR) && 1072130803Smarcel (ccio->ccio_flags & CCDF_PARITY)) { 1073130803Smarcel printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit); 1074130803Smarcel ccio->ccio_flags &= ~CCDF_PARITY; 1075130803Smarcel } 1076130803Smarcel if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) && 1077130803Smarcel !(ccio->ccio_flags & CCDF_UNIFORM)) { 1078130803Smarcel printf("ccd%d: mirror/parity forces uniform flag\n", 1079130803Smarcel unit); 1080130803Smarcel ccio->ccio_flags |= CCDF_UNIFORM; 1081130803Smarcel } 1082130803Smarcel ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; 1083130803Smarcel 1084130803Smarcel /* 1085130803Smarcel * Allocate space for and copy in the array of 1086130803Smarcel * componet pathnames and device numbers. 1087130803Smarcel */ 1088130803Smarcel cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1089130803Smarcel M_DEVBUF, M_WAITOK); 1090130803Smarcel vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1091130803Smarcel M_DEVBUF, M_WAITOK); 1092130803Smarcel 1093130803Smarcel error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1094130803Smarcel ccio->ccio_ndisks * sizeof(char **)); 1095130803Smarcel if (error) { 1096130803Smarcel free(vpp, M_DEVBUF); 1097130803Smarcel free(cpp, M_DEVBUF); 1098130803Smarcel ccdunlock(cs); 1099130803Smarcel return (error); 1100130803Smarcel } 1101130803Smarcel 1102130803Smarcel#ifdef DEBUG 1103130803Smarcel if (ccddebug & CCDB_INIT) 1104130803Smarcel for (i = 0; i < ccio->ccio_ndisks; ++i) 1105130803Smarcel printf("ccdioctl: component %d: 0x%x\n", 1106130803Smarcel i, cpp[i]); 1107130803Smarcel#endif 1108130803Smarcel 1109130803Smarcel for (i = 0; i < ccio->ccio_ndisks; ++i) { 1110130803Smarcel#ifdef DEBUG 1111130803Smarcel if (ccddebug & CCDB_INIT) 1112130803Smarcel printf("ccdioctl: lookedup = %d\n", lookedup); 1113130803Smarcel#endif 1114130803Smarcel if (error = ccdlookup(cpp[i], p, &vpp[i])) { 1115130803Smarcel for (j = 0; j < lookedup; ++j) 1116130803Smarcel (void)vn_close(vpp[j], FREAD|FWRITE, 1117130803Smarcel p->p_ucred, p); 1118130803Smarcel free(vpp, M_DEVBUF); 1119130803Smarcel free(cpp, M_DEVBUF); 1120130803Smarcel ccdunlock(cs); 1121130803Smarcel return (error); 1122130803Smarcel } 1123130803Smarcel ++lookedup; 1124130803Smarcel } 1125130803Smarcel ccd.ccd_cpp = cpp; 1126130803Smarcel ccd.ccd_vpp = vpp; 1127130803Smarcel ccd.ccd_ndev = ccio->ccio_ndisks; 1128130803Smarcel 1129130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1130130803Smarcel /* 1131130803Smarcel * Assign disk index first so that init routine 1132130803Smarcel * can use it (saves having the driver drag around 1133130803Smarcel * the ccddevice pointer just to set up the dk_* 1134130803Smarcel * info in the open routine). 1135130803Smarcel */ 1136130803Smarcel if (dkn < DK_NDRIVE) 1137130803Smarcel ccd.ccd_dk = dkn++; 1138130803Smarcel else 1139130803Smarcel ccd.ccd_dk = -1; 1140130803Smarcel#endif 1141130803Smarcel 1142130803Smarcel /* 1143130803Smarcel * Initialize the ccd. Fills in the softc for us. 1144130803Smarcel */ 1145130803Smarcel if (error = ccdinit(&ccd, cpp, p)) { 1146130803Smarcel#ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1147130803Smarcel if (ccd.ccd_dk >= 0) 1148130803Smarcel --dkn; 1149130803Smarcel#endif 1150130803Smarcel for (j = 0; j < lookedup; ++j) 1151130803Smarcel (void)vn_close(vpp[j], FREAD|FWRITE, 1152130803Smarcel p->p_ucred, p); 1153130803Smarcel bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); 1154130803Smarcel free(vpp, M_DEVBUF); 1155130803Smarcel free(cpp, M_DEVBUF); 1156130803Smarcel ccdunlock(cs); 1157130803Smarcel return (error); 1158130803Smarcel } 1159130803Smarcel 1160130803Smarcel /* 1161130803Smarcel * The ccd has been successfully initialized, so 1162130803Smarcel * we can place it into the array and read the disklabel. 1163130803Smarcel */ 1164130803Smarcel bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1165130803Smarcel ccio->ccio_unit = unit; 1166130803Smarcel ccio->ccio_size = cs->sc_size; 1167130803Smarcel ccdgetdisklabel(dev); 1168130803Smarcel 1169130803Smarcel ccdunlock(cs); 1170130803Smarcel 1171130803Smarcel break; 1172130803Smarcel 1173130803Smarcel case CCDIOCCLR: 1174130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) 1175130803Smarcel return (ENXIO); 1176130803Smarcel 1177130803Smarcel if ((flag & FWRITE) == 0) 1178130803Smarcel return (EBADF); 1179130803Smarcel 1180130803Smarcel if (error = ccdlock(cs)) 1181130803Smarcel return (error); 1182130803Smarcel 1183130803Smarcel /* 1184130803Smarcel * Don't unconfigure if any other partitions are open 1185130803Smarcel * or if both the character and block flavors of this 1186130803Smarcel * partition are open. 1187130803Smarcel */ 1188130803Smarcel part = ccdpart(dev); 1189130803Smarcel pmask = (1 << part); 1190130803Smarcel if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1191130803Smarcel ((cs->sc_dkdev.dk_bopenmask & pmask) && 1192130803Smarcel (cs->sc_dkdev.dk_copenmask & pmask))) { 1193130803Smarcel ccdunlock(cs); 1194130803Smarcel return (EBUSY); 1195130803Smarcel } 1196130803Smarcel 1197130803Smarcel /* 1198130803Smarcel * Free ccd_softc information and clear entry. 1199130803Smarcel */ 1200130803Smarcel 1201130803Smarcel /* Close the components and free their pathnames. */ 1202130803Smarcel for (i = 0; i < cs->sc_nccdisks; ++i) { 1203130803Smarcel /* 1204130803Smarcel * XXX: this close could potentially fail and 1205130803Smarcel * cause Bad Things. Maybe we need to force 1206130803Smarcel * the close to happen? 1207130803Smarcel */ 1208130803Smarcel#ifdef DEBUG 1209130803Smarcel if (ccddebug & CCDB_VNODE) 1210130803Smarcel vprint("CCDIOCCLR: vnode info", 1211130803Smarcel cs->sc_cinfo[i].ci_vp); 1212130803Smarcel#endif 1213130803Smarcel (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1214130803Smarcel p->p_ucred, p); 1215130803Smarcel free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1216130803Smarcel } 1217130803Smarcel 1218130803Smarcel /* Free interleave index. */ 1219130803Smarcel for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1220130803Smarcel free(cs->sc_itable[i].ii_index, M_DEVBUF); 1221130803Smarcel 1222130803Smarcel /* Free component info and interleave table. */ 1223130803Smarcel free(cs->sc_cinfo, M_DEVBUF); 1224130803Smarcel free(cs->sc_itable, M_DEVBUF); 1225130803Smarcel cs->sc_flags &= ~CCDF_INITED; 1226130803Smarcel 1227130803Smarcel /* 1228130803Smarcel * Free ccddevice information and clear entry. 1229130803Smarcel */ 1230130803Smarcel free(ccddevs[unit].ccd_cpp, M_DEVBUF); 1231130803Smarcel free(ccddevs[unit].ccd_vpp, M_DEVBUF); 1232130803Smarcel ccd.ccd_dk = -1; 1233130803Smarcel bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1234130803Smarcel 1235130803Smarcel /* This must be atomic. */ 1236130803Smarcel s = splhigh(); 1237130803Smarcel ccdunlock(cs); 1238130803Smarcel bzero(cs, sizeof(struct ccd_softc)); 1239130803Smarcel splx(s); 1240130803Smarcel 1241130803Smarcel break; 1242130803Smarcel 1243130803Smarcel case DIOCGDINFO: 1244130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) 1245130803Smarcel return (ENXIO); 1246130803Smarcel 1247130803Smarcel *(struct disklabel *)data = cs->sc_dkdev.dk_label; 1248130803Smarcel break; 1249130803Smarcel 1250130803Smarcel case DIOCGPART: 1251130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) 1252130803Smarcel return (ENXIO); 1253130803Smarcel 1254130803Smarcel ((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label; 1255130803Smarcel ((struct partinfo *)data)->part = 1256130803Smarcel &cs->sc_dkdev.dk_label.d_partitions[ccdpart(dev)]; 1257130803Smarcel break; 1258130803Smarcel 1259130803Smarcel case DIOCWDINFO: 1260130803Smarcel case DIOCSDINFO: 1261130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) 1262130803Smarcel return (ENXIO); 1263130803Smarcel 1264130803Smarcel if ((flag & FWRITE) == 0) 1265130803Smarcel return (EBADF); 1266130803Smarcel 1267130803Smarcel if (error = ccdlock(cs)) 1268130803Smarcel return (error); 1269130803Smarcel 1270130803Smarcel cs->sc_flags |= CCDF_LABELLING; 1271130803Smarcel 1272130803Smarcel error = setdisklabel(&cs->sc_dkdev.dk_label, 1273130803Smarcel (struct disklabel *)data, 0); 1274130803Smarcel /*, &cs->sc_dkdev.dk_cpulabel); */ 1275130803Smarcel if (error == 0) { 1276130803Smarcel if (cmd == DIOCWDINFO) 1277130803Smarcel error = writedisklabel(CCDLABELDEV(dev), 1278130803Smarcel ccdstrategy, &cs->sc_dkdev.dk_label); 1279130803Smarcel /* 1280130803Smarcel &cs->sc_dkdev.dk_cpulabel); */ 1281130803Smarcel } 1282130803Smarcel 1283130803Smarcel cs->sc_flags &= ~CCDF_LABELLING; 1284130803Smarcel 1285130803Smarcel ccdunlock(cs); 1286130803Smarcel 1287130803Smarcel if (error) 1288130803Smarcel return (error); 1289130803Smarcel break; 1290130803Smarcel 1291130803Smarcel case DIOCWLABEL: 1292130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) 1293130803Smarcel return (ENXIO); 1294130803Smarcel 1295130803Smarcel if ((flag & FWRITE) == 0) 1296130803Smarcel return (EBADF); 1297130803Smarcel if (*(int *)data != 0) 1298130803Smarcel cs->sc_flags |= CCDF_WLABEL; 1299130803Smarcel else 1300130803Smarcel cs->sc_flags &= ~CCDF_WLABEL; 1301130803Smarcel break; 1302130803Smarcel 1303130803Smarcel default: 1304130803Smarcel return (ENOTTY); 1305130803Smarcel } 1306130803Smarcel 1307130803Smarcel return (0); 1308130803Smarcel} 1309130803Smarcel 1310130803Smarcelstatic int 1311130803Smarcelccdsize(dev) 1312130803Smarcel dev_t dev; 1313130803Smarcel{ 1314130803Smarcel struct ccd_softc *cs; 1315130803Smarcel int part, size; 1316130803Smarcel 1317130803Smarcel if (ccdopen(dev, 0, S_IFBLK, curproc)) 1318130803Smarcel return (-1); 1319130803Smarcel 1320130803Smarcel cs = &ccd_softc[ccdunit(dev)]; 1321130803Smarcel part = ccdpart(dev); 1322130803Smarcel 1323130803Smarcel if ((cs->sc_flags & CCDF_INITED) == 0) 1324130803Smarcel return (-1); 1325130803Smarcel 1326130803Smarcel if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP) 1327130803Smarcel size = -1; 1328130803Smarcel else 1329130803Smarcel size = cs->sc_dkdev.dk_label.d_partitions[part].p_size; 1330130803Smarcel 1331130803Smarcel if (ccdclose(dev, 0, S_IFBLK, curproc)) 1332130803Smarcel return (-1); 1333130803Smarcel 1334130803Smarcel return (size); 1335130803Smarcel} 1336130803Smarcel 1337130803Smarcelstatic int 1338130803Smarcelccddump(dev) 1339130803Smarcel dev_t dev; 1340130803Smarcel{ 1341130803Smarcel 1342130803Smarcel /* Not implemented. */ 1343130803Smarcel return ENXIO; 1344130803Smarcel} 1345130803Smarcel 1346130803Smarcel/* 1347130803Smarcel * Lookup the provided name in the filesystem. If the file exists, 1348130803Smarcel * is a valid block device, and isn't being used by anyone else, 1349130803Smarcel * set *vpp to the file's vnode. 1350130803Smarcel */ 1351130803Smarcelstatic int 1352130803Smarcelccdlookup(path, p, vpp) 1353130803Smarcel char *path; 1354130803Smarcel struct proc *p; 1355130803Smarcel struct vnode **vpp; /* result */ 1356130803Smarcel{ 1357130803Smarcel struct nameidata nd; 1358130803Smarcel struct vnode *vp; 1359130803Smarcel struct vattr va; 1360130803Smarcel int error; 1361130803Smarcel 1362130803Smarcel NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1363130803Smarcel if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 1364130803Smarcel#ifdef DEBUG 1365130803Smarcel if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1366130803Smarcel printf("ccdlookup: vn_open error = %d\n", error); 1367130803Smarcel#endif 1368130803Smarcel return (error); 1369130803Smarcel } 1370130803Smarcel vp = nd.ni_vp; 1371130803Smarcel 1372130803Smarcel if (vp->v_usecount > 1) { 1373130803Smarcel VOP_UNLOCK(vp, 0, p); 1374130803Smarcel (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1375130803Smarcel return (EBUSY); 1376130803Smarcel } 1377130803Smarcel 1378130803Smarcel if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { 1379130803Smarcel#ifdef DEBUG 1380130803Smarcel if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1381130803Smarcel printf("ccdlookup: getattr error = %d\n", error); 1382130803Smarcel#endif 1383130803Smarcel VOP_UNLOCK(vp, 0, p); 1384130803Smarcel (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1385130803Smarcel return (error); 1386130803Smarcel } 1387130803Smarcel 1388130803Smarcel /* XXX: eventually we should handle VREG, too. */ 1389130803Smarcel if (va.va_type != VBLK) { 1390130803Smarcel VOP_UNLOCK(vp, 0, p); 1391130803Smarcel (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1392130803Smarcel return (ENOTBLK); 1393130803Smarcel } 1394130803Smarcel 1395130803Smarcel#ifdef DEBUG 1396130803Smarcel if (ccddebug & CCDB_VNODE) 1397130803Smarcel vprint("ccdlookup: vnode info", vp); 1398130803Smarcel#endif 1399130803Smarcel 1400130803Smarcel VOP_UNLOCK(vp, 0, p); 1401130803Smarcel *vpp = vp; 1402130803Smarcel return (0); 1403130803Smarcel} 1404130803Smarcel 1405130803Smarcel/* 1406130803Smarcel * Read the disklabel from the ccd. If one is not present, fake one 1407130803Smarcel * up. 1408130803Smarcel */ 1409130803Smarcelstatic void 1410130803Smarcelccdgetdisklabel(dev) 1411130803Smarcel dev_t dev; 1412130803Smarcel{ 1413130803Smarcel int unit = ccdunit(dev); 1414130803Smarcel struct ccd_softc *cs = &ccd_softc[unit]; 1415130803Smarcel char *errstring; 1416130803Smarcel struct disklabel *lp = &cs->sc_dkdev.dk_label; 1417130803Smarcel struct ccdgeom *ccg = &cs->sc_geom; 1418130803Smarcel 1419130803Smarcel bzero(lp, sizeof(*lp)); 1420130803Smarcel 1421130803Smarcel lp->d_secperunit = cs->sc_size; 1422130803Smarcel lp->d_secsize = ccg->ccg_secsize; 1423130803Smarcel lp->d_nsectors = ccg->ccg_nsectors; 1424130803Smarcel lp->d_ntracks = ccg->ccg_ntracks; 1425130803Smarcel lp->d_ncylinders = ccg->ccg_ncylinders; 1426130803Smarcel lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1427130803Smarcel 1428130803Smarcel strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1429130803Smarcel lp->d_type = DTYPE_CCD; 1430130803Smarcel strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1431130803Smarcel lp->d_rpm = 3600; 1432130803Smarcel lp->d_interleave = 1; 1433130803Smarcel lp->d_flags = 0; 1434130803Smarcel 1435130803Smarcel lp->d_partitions[RAW_PART].p_offset = 0; 1436130803Smarcel lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1437130803Smarcel lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1438130803Smarcel lp->d_npartitions = RAW_PART + 1; 1439130803Smarcel 1440130803Smarcel lp->d_bbsize = BBSIZE; /* XXX */ 1441130803Smarcel lp->d_sbsize = SBSIZE; /* XXX */ 1442130803Smarcel 1443130803Smarcel lp->d_magic = DISKMAGIC; 1444130803Smarcel lp->d_magic2 = DISKMAGIC; 1445130803Smarcel lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label); 1446130803Smarcel 1447130803Smarcel /* 1448130803Smarcel * Call the generic disklabel extraction routine. 1449130803Smarcel */ 1450130803Smarcel if (errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1451130803Smarcel &cs->sc_dkdev.dk_label)) 1452130803Smarcel ccdmakedisklabel(cs); 1453130803Smarcel 1454130803Smarcel#ifdef DEBUG 1455130803Smarcel /* It's actually extremely common to have unlabeled ccds. */ 1456130803Smarcel if (ccddebug & CCDB_LABEL) 1457130803Smarcel if (errstring != NULL) 1458130803Smarcel printf("ccd%d: %s\n", unit, errstring); 1459130803Smarcel#endif 1460130803Smarcel} 1461130803Smarcel 1462130803Smarcel/* 1463130803Smarcel * Take care of things one might want to take care of in the event 1464130803Smarcel * that a disklabel isn't present. 1465130803Smarcel */ 1466130803Smarcelstatic void 1467130803Smarcelccdmakedisklabel(cs) 1468130803Smarcel struct ccd_softc *cs; 1469130803Smarcel{ 1470130803Smarcel struct disklabel *lp = &cs->sc_dkdev.dk_label; 1471130803Smarcel 1472130803Smarcel /* 1473130803Smarcel * For historical reasons, if there's no disklabel present 1474130803Smarcel * the raw partition must be marked FS_BSDFFS. 1475130803Smarcel */ 1476130803Smarcel lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1477130803Smarcel 1478130803Smarcel strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1479130803Smarcel} 1480130803Smarcel 1481130803Smarcel/* 1482130803Smarcel * Wait interruptibly for an exclusive lock. 1483130803Smarcel * 1484130803Smarcel * XXX 1485130803Smarcel * Several drivers do this; it should be abstracted and made MP-safe. 1486130803Smarcel */ 1487130803Smarcelstatic int 1488130803Smarcelccdlock(cs) 1489130803Smarcel struct ccd_softc *cs; 1490130803Smarcel{ 1491130803Smarcel int error; 1492130803Smarcel 1493130803Smarcel while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1494130803Smarcel cs->sc_flags |= CCDF_WANTED; 1495130803Smarcel if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1496130803Smarcel return (error); 1497130803Smarcel } 1498130803Smarcel cs->sc_flags |= CCDF_LOCKED; 1499130803Smarcel return (0); 1500130803Smarcel} 1501130803Smarcel 1502130803Smarcel/* 1503130803Smarcel * Unlock and wake up any waiters. 1504130803Smarcel */ 1505130803Smarcelstatic void 1506130803Smarcelccdunlock(cs) 1507130803Smarcel struct ccd_softc *cs; 1508130803Smarcel{ 1509130803Smarcel 1510130803Smarcel cs->sc_flags &= ~CCDF_LOCKED; 1511130803Smarcel if ((cs->sc_flags & CCDF_WANTED) != 0) { 1512130803Smarcel cs->sc_flags &= ~CCDF_WANTED; 1513130803Smarcel wakeup(cs); 1514130803Smarcel } 1515130803Smarcel} 1516130803Smarcel 1517130803Smarcel#ifdef DEBUG 1518130803Smarcelstatic void 1519130803Smarcelprintiinfo(ii) 1520130803Smarcel struct ccdiinfo *ii; 1521130803Smarcel{ 1522130803Smarcel register int ix, i; 1523130803Smarcel 1524130803Smarcel for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1525130803Smarcel printf(" itab[%d]: #dk %d sblk %d soff %d", 1526130803Smarcel ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1527130803Smarcel for (i = 0; i < ii->ii_ndisk; i++) 1528130803Smarcel printf(" %d", ii->ii_index[i]); 1529130803Smarcel printf("\n"); 1530130803Smarcel } 1531130803Smarcel} 1532130803Smarcel#endif 1533130803Smarcel 1534130803Smarcel#endif /* NCCD > 0 */ 1535130803Smarcel 1536130803Smarcel/* Local Variables: */ 1537130803Smarcel/* c-argdecl-indent: 8 */ 1538130803Smarcel/* c-continued-statement-offset: 8 */ 1539130803Smarcel/* c-indent-level: 8 */ 1540130803Smarcel/* End: */ 1541130803Smarcel