1a56bb8a5SSatoshi Asami /* 23b1746dfSPoul-Henning Kamp * Copyright (c) 2003 Poul-Henning Kamp. 3a56bb8a5SSatoshi Asami * Copyright (c) 1995 Jason R. Thorpe. 4a56bb8a5SSatoshi Asami * Copyright (c) 1990, 1993 5a56bb8a5SSatoshi Asami * The Regents of the University of California. All rights reserved. 63b1746dfSPoul-Henning Kamp * All rights reserved. 73b1746dfSPoul-Henning Kamp * Copyright (c) 1988 University of Utah. 8a56bb8a5SSatoshi Asami * 9a56bb8a5SSatoshi Asami * This code is derived from software contributed to Berkeley by 10a56bb8a5SSatoshi Asami * the Systems Programming Group of the University of Utah Computer 11a56bb8a5SSatoshi Asami * Science Department. 12a56bb8a5SSatoshi Asami * 13a56bb8a5SSatoshi Asami * Redistribution and use in source and binary forms, with or without 14a56bb8a5SSatoshi Asami * modification, are permitted provided that the following conditions 15a56bb8a5SSatoshi Asami * are met: 16a56bb8a5SSatoshi Asami * 1. Redistributions of source code must retain the above copyright 17a56bb8a5SSatoshi Asami * notice, this list of conditions and the following disclaimer. 18a56bb8a5SSatoshi Asami * 2. Redistributions in binary form must reproduce the above copyright 19a56bb8a5SSatoshi Asami * notice, this list of conditions and the following disclaimer in the 20a56bb8a5SSatoshi Asami * documentation and/or other materials provided with the distribution. 21a56bb8a5SSatoshi Asami * 3. All advertising materials mentioning features or use of this software 22a56bb8a5SSatoshi Asami * must display the following acknowledgement: 233b1746dfSPoul-Henning Kamp * This product includes software developed for the NetBSD Project 243b1746dfSPoul-Henning Kamp * by Jason R. Thorpe. 253b1746dfSPoul-Henning Kamp * 4. The names of the authors may not be used to endorse or promote products 263b1746dfSPoul-Henning Kamp * derived from this software without specific prior written permission. 27a56bb8a5SSatoshi Asami * 283b1746dfSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 293b1746dfSPoul-Henning Kamp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 303b1746dfSPoul-Henning Kamp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 313b1746dfSPoul-Henning Kamp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 323b1746dfSPoul-Henning Kamp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 333b1746dfSPoul-Henning Kamp * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 343b1746dfSPoul-Henning Kamp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 353b1746dfSPoul-Henning Kamp * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 363b1746dfSPoul-Henning Kamp * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37a56bb8a5SSatoshi Asami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38a56bb8a5SSatoshi Asami * SUCH DAMAGE. 39a56bb8a5SSatoshi Asami * 40a56bb8a5SSatoshi Asami * Dynamic configuration and disklabel support by: 41a56bb8a5SSatoshi Asami * Jason R. Thorpe <thorpej@nas.nasa.gov> 42a56bb8a5SSatoshi Asami * Numerical Aerodynamic Simulation Facility 43a56bb8a5SSatoshi Asami * Mail Stop 258-6 44a56bb8a5SSatoshi Asami * NASA Ames Research Center 45a56bb8a5SSatoshi Asami * Moffett Field, CA 94035 463b1746dfSPoul-Henning Kamp * 473b1746dfSPoul-Henning Kamp * from: Utah $Hdr: cd.c 1.6 90/11/28$ 483b1746dfSPoul-Henning Kamp * 493b1746dfSPoul-Henning Kamp * @(#)cd.c 8.2 (Berkeley) 11/16/93 503b1746dfSPoul-Henning Kamp * 513b1746dfSPoul-Henning Kamp * $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ 523b1746dfSPoul-Henning Kamp * 533b1746dfSPoul-Henning Kamp * $FreeBSD$ 54a56bb8a5SSatoshi Asami */ 55a56bb8a5SSatoshi Asami 56a56bb8a5SSatoshi Asami #include <sys/param.h> 57a56bb8a5SSatoshi Asami #include <sys/systm.h> 58e2a13e8cSSatoshi Asami #include <sys/kernel.h> 59b7b98418SPeter Wemm #include <sys/module.h> 60a56bb8a5SSatoshi Asami #include <sys/proc.h> 619626b608SPoul-Henning Kamp #include <sys/bio.h> 62a56bb8a5SSatoshi Asami #include <sys/malloc.h> 63a56bb8a5SSatoshi Asami #include <sys/namei.h> 64a56bb8a5SSatoshi Asami #include <sys/conf.h> 65a56bb8a5SSatoshi Asami #include <sys/stat.h> 66f368af93SMaxime Henrion #include <sys/stdint.h> 67e2738b4fSPoul-Henning Kamp #include <sys/sysctl.h> 682dd527b3SPoul-Henning Kamp #include <sys/disk.h> 697812d86fSPoul-Henning Kamp #include <sys/disklabel.h> 70b2dfb1f9SJustin T. Gibbs #include <sys/devicestat.h> 71a56bb8a5SSatoshi Asami #include <sys/fcntl.h> 72a56bb8a5SSatoshi Asami #include <sys/vnode.h> 73a56bb8a5SSatoshi Asami 74d8594dfbSSatoshi Asami #include <sys/ccdvar.h> 75a56bb8a5SSatoshi Asami 7601706d20SPoul-Henning Kamp MALLOC_DEFINE(M_CCD, "CCD driver", "Concatenated Disk driver"); 7701706d20SPoul-Henning Kamp 78a56bb8a5SSatoshi Asami #if defined(CCDDEBUG) && !defined(DEBUG) 79a56bb8a5SSatoshi Asami #define DEBUG 80a56bb8a5SSatoshi Asami #endif 81a56bb8a5SSatoshi Asami 82a56bb8a5SSatoshi Asami #ifdef DEBUG 83a56bb8a5SSatoshi Asami #define CCDB_FOLLOW 0x01 84a56bb8a5SSatoshi Asami #define CCDB_INIT 0x02 85a56bb8a5SSatoshi Asami #define CCDB_IO 0x04 86a56bb8a5SSatoshi Asami #define CCDB_LABEL 0x08 87a56bb8a5SSatoshi Asami #define CCDB_VNODE 0x10 88e2738b4fSPoul-Henning Kamp static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | 89e2738b4fSPoul-Henning Kamp CCDB_VNODE; 90e2738b4fSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, ""); 91a56bb8a5SSatoshi Asami #endif 92a56bb8a5SSatoshi Asami 93ddbf51afSPoul-Henning Kamp static u_int 94ddbf51afSPoul-Henning Kamp ccdunit(dev_t dev) 95ddbf51afSPoul-Henning Kamp { 96ddbf51afSPoul-Henning Kamp return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f)); 97ddbf51afSPoul-Henning Kamp } 98ddbf51afSPoul-Henning Kamp 99ddbf51afSPoul-Henning Kamp #define ccdpart(x) (minor(x) & 7) 100a56bb8a5SSatoshi Asami 101e7322872SSatoshi Asami /* 102e7322872SSatoshi Asami This is how mirroring works (only writes are special): 103e7322872SSatoshi Asami 104e7322872SSatoshi Asami When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s 105e7322872SSatoshi Asami linked together by the cb_mirror field. "cb_pflags & 106e7322872SSatoshi Asami CCDPF_MIRROR_DONE" is set to 0 on both of them. 107e7322872SSatoshi Asami 108e7322872SSatoshi Asami When a component returns to ccdiodone(), it checks if "cb_pflags & 109e7322872SSatoshi Asami CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's 110e7322872SSatoshi Asami flag and returns. If it is, it means its partner has already 111e7322872SSatoshi Asami returned, so it will go to the regular cleanup. 112e7322872SSatoshi Asami 113e7322872SSatoshi Asami */ 114e7322872SSatoshi Asami 115a56bb8a5SSatoshi Asami struct ccdbuf { 1169d7f7369SPoul-Henning Kamp struct bio cb_buf; /* new I/O buf */ 1179d7f7369SPoul-Henning Kamp struct bio *cb_obp; /* ptr. to original I/O buf */ 1181464240eSMatthew Dillon struct ccdbuf *cb_freenext; /* free list link */ 119a56bb8a5SSatoshi Asami int cb_unit; /* target unit */ 120a56bb8a5SSatoshi Asami int cb_comp; /* target component */ 121e7322872SSatoshi Asami int cb_pflags; /* mirror/parity status flag */ 122e7322872SSatoshi Asami struct ccdbuf *cb_mirror; /* mirror counterpart */ 123a56bb8a5SSatoshi Asami }; 124a56bb8a5SSatoshi Asami 125e7322872SSatoshi Asami /* bits in cb_pflags */ 126e7322872SSatoshi Asami #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ 127e7322872SSatoshi Asami 128a56bb8a5SSatoshi Asami #define CCDLABELDEV(dev) \ 129d8594dfbSSatoshi Asami (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART))) 130a56bb8a5SSatoshi Asami 13101706d20SPoul-Henning Kamp /* convinient macros for often-used statements */ 13201706d20SPoul-Henning Kamp #define IS_ALLOCATED(unit) (ccdfind(unit) != NULL) 13301706d20SPoul-Henning Kamp #define IS_INITED(cs) (((cs)->sc_flags & CCDF_INITED) != 0) 13401706d20SPoul-Henning Kamp 135ddbf51afSPoul-Henning Kamp 136ddbf51afSPoul-Henning Kamp static dev_t ccdctldev; 137ddbf51afSPoul-Henning Kamp 138ddbf51afSPoul-Henning Kamp 139e2738b4fSPoul-Henning Kamp static d_open_t ccdopen; 140e2738b4fSPoul-Henning Kamp static d_close_t ccdclose; 141e2738b4fSPoul-Henning Kamp static d_strategy_t ccdstrategy; 142e2738b4fSPoul-Henning Kamp static d_ioctl_t ccdioctl; 143ddbf51afSPoul-Henning Kamp static d_ioctl_t ccdioctltoo; 144e2738b4fSPoul-Henning Kamp static d_psize_t ccdsize; 145d8594dfbSSatoshi Asami 1461464240eSMatthew Dillon #define NCCDFREEHIWAT 16 1471464240eSMatthew Dillon 148e2a13e8cSSatoshi Asami #define CDEV_MAJOR 74 149a56bb8a5SSatoshi Asami 150f7ea2f55SJulian Elischer static struct cdevsw ccd_cdevsw = { 1514e2f199eSPoul-Henning Kamp /* open */ ccdopen, 1524e2f199eSPoul-Henning Kamp /* close */ ccdclose, 1534e2f199eSPoul-Henning Kamp /* read */ physread, 1544e2f199eSPoul-Henning Kamp /* write */ physwrite, 1554e2f199eSPoul-Henning Kamp /* ioctl */ ccdioctl, 1564e2f199eSPoul-Henning Kamp /* poll */ nopoll, 1574e2f199eSPoul-Henning Kamp /* mmap */ nommap, 1584e2f199eSPoul-Henning Kamp /* strategy */ ccdstrategy, 1594e2f199eSPoul-Henning Kamp /* name */ "ccd", 1604e2f199eSPoul-Henning Kamp /* maj */ CDEV_MAJOR, 1616ede0accSPoul-Henning Kamp /* dump */ nodump, 1624e2f199eSPoul-Henning Kamp /* psize */ ccdsize, 1634e2f199eSPoul-Henning Kamp /* flags */ D_DISK, 1644e2f199eSPoul-Henning Kamp }; 16501706d20SPoul-Henning Kamp static LIST_HEAD(, ccd_s) ccd_softc_list = LIST_HEAD_INITIALIZER(&ccd_softc_list); 16601706d20SPoul-Henning Kamp 16701706d20SPoul-Henning Kamp static struct ccd_s *ccdfind(int); 16801706d20SPoul-Henning Kamp static struct ccd_s *ccdnew(int); 16901706d20SPoul-Henning Kamp static int ccddestroy(struct ccd_s *, struct proc *); 170e2a13e8cSSatoshi Asami 171b7b98418SPeter Wemm /* called during module initialization */ 17201706d20SPoul-Henning Kamp static void ccdattach(void); 17301706d20SPoul-Henning Kamp static int ccd_modevent(module_t, int, void *); 174a56bb8a5SSatoshi Asami 175a56bb8a5SSatoshi Asami /* called by biodone() at interrupt time */ 17601706d20SPoul-Henning Kamp static void ccdiodone(struct bio *bp); 177a56bb8a5SSatoshi Asami 17801706d20SPoul-Henning Kamp static void ccdstart(struct ccd_s *, struct bio *); 17901706d20SPoul-Henning Kamp static void ccdinterleave(struct ccd_s *, int); 18001706d20SPoul-Henning Kamp static void ccdintr(struct ccd_s *, struct bio *); 181b40ce416SJulian Elischer static int ccdinit(struct ccd_s *, char **, struct thread *); 182b40ce416SJulian Elischer static int ccdlookup(char *, struct thread *p, struct vnode **); 18301706d20SPoul-Henning Kamp static void ccdbuffer(struct ccdbuf **ret, struct ccd_s *, 18401706d20SPoul-Henning Kamp struct bio *, daddr_t, caddr_t, long); 18501706d20SPoul-Henning Kamp static void ccdgetdisklabel(dev_t); 18601706d20SPoul-Henning Kamp static void ccdmakedisklabel(struct ccd_s *); 18701706d20SPoul-Henning Kamp static int ccdlock(struct ccd_s *); 18801706d20SPoul-Henning Kamp static void ccdunlock(struct ccd_s *); 189a56bb8a5SSatoshi Asami 190a56bb8a5SSatoshi Asami #ifdef DEBUG 19101706d20SPoul-Henning Kamp static void printiinfo(struct ccdiinfo *); 192a56bb8a5SSatoshi Asami #endif 193a56bb8a5SSatoshi Asami 194a56bb8a5SSatoshi Asami /* Non-private for the benefit of libkvm. */ 1951464240eSMatthew Dillon struct ccdbuf *ccdfreebufs; 1961464240eSMatthew Dillon static int numccdfreebufs; 197a56bb8a5SSatoshi Asami 198a56bb8a5SSatoshi Asami /* 1991464240eSMatthew Dillon * getccdbuf() - Allocate and zero a ccd buffer. 2001464240eSMatthew Dillon * 2011464240eSMatthew Dillon * This routine is called at splbio(). 2021464240eSMatthew Dillon */ 2031464240eSMatthew Dillon 2041464240eSMatthew Dillon static __inline 2051464240eSMatthew Dillon struct ccdbuf * 2061464240eSMatthew Dillon getccdbuf(struct ccdbuf *cpy) 2071464240eSMatthew Dillon { 2081464240eSMatthew Dillon struct ccdbuf *cbp; 2091464240eSMatthew Dillon 2101464240eSMatthew Dillon /* 2111464240eSMatthew Dillon * Allocate from freelist or malloc as necessary 2121464240eSMatthew Dillon */ 2131464240eSMatthew Dillon if ((cbp = ccdfreebufs) != NULL) { 2141464240eSMatthew Dillon ccdfreebufs = cbp->cb_freenext; 2151464240eSMatthew Dillon --numccdfreebufs; 2161464240eSMatthew Dillon } else { 2171464240eSMatthew Dillon cbp = malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK); 2181464240eSMatthew Dillon } 2191464240eSMatthew Dillon 2201464240eSMatthew Dillon /* 2211464240eSMatthew Dillon * Used by mirroring code 2221464240eSMatthew Dillon */ 2231464240eSMatthew Dillon if (cpy) 2241464240eSMatthew Dillon bcopy(cpy, cbp, sizeof(struct ccdbuf)); 2251464240eSMatthew Dillon else 2261464240eSMatthew Dillon bzero(cbp, sizeof(struct ccdbuf)); 2271464240eSMatthew Dillon 2281464240eSMatthew Dillon /* 2299d7f7369SPoul-Henning Kamp * independant struct bio initialization 2301464240eSMatthew Dillon */ 2311464240eSMatthew Dillon 2321464240eSMatthew Dillon return(cbp); 2331464240eSMatthew Dillon } 2341464240eSMatthew Dillon 2351464240eSMatthew Dillon /* 2361441456fSGreg Lehey * putccdbuf() - Free a ccd buffer. 2371464240eSMatthew Dillon * 2381464240eSMatthew Dillon * This routine is called at splbio(). 2391464240eSMatthew Dillon */ 2401464240eSMatthew Dillon 2411464240eSMatthew Dillon static __inline 2421464240eSMatthew Dillon void 2431464240eSMatthew Dillon putccdbuf(struct ccdbuf *cbp) 2441464240eSMatthew Dillon { 24574427f90SMatthew Dillon 2461464240eSMatthew Dillon if (numccdfreebufs < NCCDFREEHIWAT) { 2471464240eSMatthew Dillon cbp->cb_freenext = ccdfreebufs; 2481464240eSMatthew Dillon ccdfreebufs = cbp; 2491464240eSMatthew Dillon ++numccdfreebufs; 2501464240eSMatthew Dillon } else { 2511464240eSMatthew Dillon free((caddr_t)cbp, M_DEVBUF); 2521464240eSMatthew Dillon } 2531464240eSMatthew Dillon } 2541464240eSMatthew Dillon 2551464240eSMatthew Dillon 2561464240eSMatthew Dillon /* 2570d88ef07SSatoshi Asami * Number of blocks to untouched in front of a component partition. 2580d88ef07SSatoshi Asami * This is to avoid violating its disklabel area when it starts at the 2590d88ef07SSatoshi Asami * beginning of the slice. 2600d88ef07SSatoshi Asami */ 2611af0e025SSatoshi Asami #if !defined(CCD_OFFSET) 2620d88ef07SSatoshi Asami #define CCD_OFFSET 16 2631af0e025SSatoshi Asami #endif 2640d88ef07SSatoshi Asami 26501706d20SPoul-Henning Kamp static struct ccd_s * 26601706d20SPoul-Henning Kamp ccdfind(int unit) 26701706d20SPoul-Henning Kamp { 26801706d20SPoul-Henning Kamp struct ccd_s *sc = NULL; 26901706d20SPoul-Henning Kamp 27001706d20SPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 27101706d20SPoul-Henning Kamp LIST_FOREACH(sc, &ccd_softc_list, list) { 27201706d20SPoul-Henning Kamp if (sc->sc_unit == unit) 27301706d20SPoul-Henning Kamp break; 27401706d20SPoul-Henning Kamp } 27501706d20SPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 27601706d20SPoul-Henning Kamp return ((sc == NULL) || (sc->sc_unit != unit) ? NULL : sc); 27701706d20SPoul-Henning Kamp } 27801706d20SPoul-Henning Kamp 27901706d20SPoul-Henning Kamp static struct ccd_s * 28001706d20SPoul-Henning Kamp ccdnew(int unit) 28101706d20SPoul-Henning Kamp { 28201706d20SPoul-Henning Kamp struct ccd_s *sc; 28301706d20SPoul-Henning Kamp 28401706d20SPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 28501706d20SPoul-Henning Kamp if (IS_ALLOCATED(unit) || unit > DKMAXUNIT) 28601706d20SPoul-Henning Kamp return (NULL); 28701706d20SPoul-Henning Kamp 28801706d20SPoul-Henning Kamp MALLOC(sc, struct ccd_s *, sizeof(*sc), M_CCD, M_WAITOK | M_ZERO); 28901706d20SPoul-Henning Kamp sc->sc_unit = unit; 29001706d20SPoul-Henning Kamp LIST_INSERT_HEAD(&ccd_softc_list, sc, list); 29101706d20SPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 29201706d20SPoul-Henning Kamp return (sc); 29301706d20SPoul-Henning Kamp } 29401706d20SPoul-Henning Kamp 29501706d20SPoul-Henning Kamp static int 29601706d20SPoul-Henning Kamp ccddestroy(struct ccd_s *sc, struct proc *p) 29701706d20SPoul-Henning Kamp { 29801706d20SPoul-Henning Kamp 29901706d20SPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 30001706d20SPoul-Henning Kamp LIST_REMOVE(sc, list); 30101706d20SPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 30201706d20SPoul-Henning Kamp FREE(sc, M_CCD); 30301706d20SPoul-Henning Kamp return (0); 30401706d20SPoul-Henning Kamp } 30501706d20SPoul-Henning Kamp 306a6b1634eSPoul-Henning Kamp static void 307a6b1634eSPoul-Henning Kamp ccd_clone(void *arg, char *name, int namelen, dev_t *dev) 308a6b1634eSPoul-Henning Kamp { 309a6b1634eSPoul-Henning Kamp int i, u; 310a6b1634eSPoul-Henning Kamp char *s; 311a6b1634eSPoul-Henning Kamp 312a6b1634eSPoul-Henning Kamp if (*dev != NODEV) 313a6b1634eSPoul-Henning Kamp return; 314db901281SPoul-Henning Kamp i = dev_stdclone(name, &s, "ccd", &u); 315a6b1634eSPoul-Henning Kamp if (i != 2) 316a6b1634eSPoul-Henning Kamp return; 317896dba5aSPoul-Henning Kamp if (*s < 'a' || *s > 'h') 318a6b1634eSPoul-Henning Kamp return; 319a6b1634eSPoul-Henning Kamp if (s[1] != '\0') 320a6b1634eSPoul-Henning Kamp return; 321a6b1634eSPoul-Henning Kamp *dev = make_dev(&ccd_cdevsw, u * 8 + *s - 'a', 322a6b1634eSPoul-Henning Kamp UID_ROOT, GID_OPERATOR, 0640, name); 323a6b1634eSPoul-Henning Kamp } 324a6b1634eSPoul-Henning Kamp 3250d88ef07SSatoshi Asami /* 326a56bb8a5SSatoshi Asami * Called by main() during pseudo-device attachment. All we need 32701706d20SPoul-Henning Kamp * to do is to add devsw entries. 328a56bb8a5SSatoshi Asami */ 329e2738b4fSPoul-Henning Kamp static void 330b7b98418SPeter Wemm ccdattach() 331a56bb8a5SSatoshi Asami { 332a56bb8a5SSatoshi Asami 333ddbf51afSPoul-Henning Kamp ccdctldev = make_dev(&ccd_cdevsw, 0xffff00ff, 334ddbf51afSPoul-Henning Kamp UID_ROOT, GID_OPERATOR, 0640, "ccd.ctl"); 335ddbf51afSPoul-Henning Kamp ccdctldev->si_drv1 = ccdctldev; 336db901281SPoul-Henning Kamp EVENTHANDLER_REGISTER(dev_clone, ccd_clone, 0, 1000); 337b7b98418SPeter Wemm } 338d8594dfbSSatoshi Asami 339b7b98418SPeter Wemm static int 34001706d20SPoul-Henning Kamp ccd_modevent(module_t mod, int type, void *data) 341b7b98418SPeter Wemm { 342b7b98418SPeter Wemm int error = 0; 343b7b98418SPeter Wemm 344b7b98418SPeter Wemm switch (type) { 345b7b98418SPeter Wemm case MOD_LOAD: 346b7b98418SPeter Wemm ccdattach(); 347b7b98418SPeter Wemm break; 348b7b98418SPeter Wemm 349b7b98418SPeter Wemm case MOD_UNLOAD: 350b7b98418SPeter Wemm printf("ccd0: Unload not supported!\n"); 351b7b98418SPeter Wemm error = EOPNOTSUPP; 352b7b98418SPeter Wemm break; 353b7b98418SPeter Wemm 35455a13f7dSIan Dowse case MOD_SHUTDOWN: 355b7b98418SPeter Wemm break; 35655a13f7dSIan Dowse 35755a13f7dSIan Dowse default: 35855a13f7dSIan Dowse error = EOPNOTSUPP; 359e2a13e8cSSatoshi Asami } 360b7b98418SPeter Wemm return (error); 361e2a13e8cSSatoshi Asami } 362b7b98418SPeter Wemm 363d53dedeeSPoul-Henning Kamp DEV_MODULE(ccd, ccd_modevent, NULL); 364a56bb8a5SSatoshi Asami 365a56bb8a5SSatoshi Asami static int 366b40ce416SJulian Elischer ccdinit(struct ccd_s *cs, char **cpaths, struct thread *td) 367a56bb8a5SSatoshi Asami { 3681464240eSMatthew Dillon struct ccdcinfo *ci = NULL; /* XXX */ 3691464240eSMatthew Dillon size_t size; 3701464240eSMatthew Dillon int ix; 371a56bb8a5SSatoshi Asami struct vnode *vp; 372a56bb8a5SSatoshi Asami size_t minsize; 373a56bb8a5SSatoshi Asami int maxsecsize; 374a56bb8a5SSatoshi Asami struct ccdgeom *ccg = &cs->sc_geom; 375e3f4d3b5SPoul-Henning Kamp char *tmppath = NULL; 3761464240eSMatthew Dillon int error = 0; 377ffee6e99SPoul-Henning Kamp off_t mediasize; 378ffee6e99SPoul-Henning Kamp u_int sectorsize; 379a56bb8a5SSatoshi Asami 380a56bb8a5SSatoshi Asami #ifdef DEBUG 381a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 38201706d20SPoul-Henning Kamp printf("ccdinit: unit %d\n", cs->sc_unit); 383a56bb8a5SSatoshi Asami #endif 384a56bb8a5SSatoshi Asami 385a56bb8a5SSatoshi Asami cs->sc_size = 0; 386a56bb8a5SSatoshi Asami 387a56bb8a5SSatoshi Asami /* Allocate space for the component info. */ 388a56bb8a5SSatoshi Asami cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), 389a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 390a56bb8a5SSatoshi Asami 391a56bb8a5SSatoshi Asami /* 392a56bb8a5SSatoshi Asami * Verify that each component piece exists and record 393a56bb8a5SSatoshi Asami * relevant information about it. 394a56bb8a5SSatoshi Asami */ 395a56bb8a5SSatoshi Asami maxsecsize = 0; 396a56bb8a5SSatoshi Asami minsize = 0; 397e3f4d3b5SPoul-Henning Kamp tmppath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK); 398a56bb8a5SSatoshi Asami for (ix = 0; ix < cs->sc_nccdisks; ix++) { 39901706d20SPoul-Henning Kamp vp = cs->sc_vpp[ix]; 400a56bb8a5SSatoshi Asami ci = &cs->sc_cinfo[ix]; 401a56bb8a5SSatoshi Asami ci->ci_vp = vp; 402a56bb8a5SSatoshi Asami 403a56bb8a5SSatoshi Asami /* 404a56bb8a5SSatoshi Asami * Copy in the pathname of the component. 405a56bb8a5SSatoshi Asami */ 406b4e36adfSMatthew Dillon if ((error = copyinstr(cpaths[ix], tmppath, 407b4e36adfSMatthew Dillon MAXPATHLEN, &ci->ci_pathlen)) != 0) { 408a56bb8a5SSatoshi Asami #ifdef DEBUG 409a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 410a56bb8a5SSatoshi Asami printf("ccd%d: can't copy path, error = %d\n", 41101706d20SPoul-Henning Kamp cs->sc_unit, error); 412a56bb8a5SSatoshi Asami #endif 4131464240eSMatthew Dillon goto fail; 414a56bb8a5SSatoshi Asami } 415a56bb8a5SSatoshi Asami ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); 416a56bb8a5SSatoshi Asami bcopy(tmppath, ci->ci_path, ci->ci_pathlen); 417a56bb8a5SSatoshi Asami 418684adedeSPoul-Henning Kamp ci->ci_dev = vn_todev(vp); 419a56bb8a5SSatoshi Asami 420a56bb8a5SSatoshi Asami /* 421a56bb8a5SSatoshi Asami * Get partition information for the component. 422a56bb8a5SSatoshi Asami */ 423ffee6e99SPoul-Henning Kamp error = VOP_IOCTL(vp, DIOCGMEDIASIZE, (caddr_t)&mediasize, 424ffee6e99SPoul-Henning Kamp FREAD, td->td_ucred, td); 425ffee6e99SPoul-Henning Kamp if (error != 0) { 426a56bb8a5SSatoshi Asami #ifdef DEBUG 427a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 428a56bb8a5SSatoshi Asami printf("ccd%d: %s: ioctl failed, error = %d\n", 42901706d20SPoul-Henning Kamp cs->sc_unit, ci->ci_path, error); 430a56bb8a5SSatoshi Asami #endif 4311464240eSMatthew Dillon goto fail; 432a56bb8a5SSatoshi Asami } 433ffee6e99SPoul-Henning Kamp /* 434ffee6e99SPoul-Henning Kamp * Get partition information for the component. 435ffee6e99SPoul-Henning Kamp */ 436ffee6e99SPoul-Henning Kamp error = VOP_IOCTL(vp, DIOCGSECTORSIZE, (caddr_t)§orsize, 437ffee6e99SPoul-Henning Kamp FREAD, td->td_ucred, td); 438ffee6e99SPoul-Henning Kamp if (error != 0) { 439a56bb8a5SSatoshi Asami #ifdef DEBUG 440a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 441ffee6e99SPoul-Henning Kamp printf("ccd%d: %s: ioctl failed, error = %d\n", 442ffee6e99SPoul-Henning Kamp cs->sc_unit, ci->ci_path, error); 443a56bb8a5SSatoshi Asami #endif 4441464240eSMatthew Dillon goto fail; 445a56bb8a5SSatoshi Asami } 446ffee6e99SPoul-Henning Kamp if (sectorsize > maxsecsize) 447ffee6e99SPoul-Henning Kamp maxsecsize = sectorsize; 448ffee6e99SPoul-Henning Kamp size = mediasize / DEV_BSIZE - CCD_OFFSET; 449a56bb8a5SSatoshi Asami 450a56bb8a5SSatoshi Asami /* 451a56bb8a5SSatoshi Asami * Calculate the size, truncating to an interleave 452a56bb8a5SSatoshi Asami * boundary if necessary. 453a56bb8a5SSatoshi Asami */ 454a56bb8a5SSatoshi Asami 455a56bb8a5SSatoshi Asami if (cs->sc_ileave > 1) 456a56bb8a5SSatoshi Asami size -= size % cs->sc_ileave; 457a56bb8a5SSatoshi Asami 458a56bb8a5SSatoshi Asami if (size == 0) { 459a56bb8a5SSatoshi Asami #ifdef DEBUG 460a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 461a56bb8a5SSatoshi Asami printf("ccd%d: %s: size == 0\n", 46201706d20SPoul-Henning Kamp cs->sc_unit, ci->ci_path); 463a56bb8a5SSatoshi Asami #endif 4641464240eSMatthew Dillon error = ENODEV; 4651464240eSMatthew Dillon goto fail; 466a56bb8a5SSatoshi Asami } 467a56bb8a5SSatoshi Asami 468a56bb8a5SSatoshi Asami if (minsize == 0 || size < minsize) 469a56bb8a5SSatoshi Asami minsize = size; 470a56bb8a5SSatoshi Asami ci->ci_size = size; 471a56bb8a5SSatoshi Asami cs->sc_size += size; 472a56bb8a5SSatoshi Asami } 473a56bb8a5SSatoshi Asami 474e3f4d3b5SPoul-Henning Kamp free(tmppath, M_DEVBUF); 475e3f4d3b5SPoul-Henning Kamp tmppath = NULL; 476e3f4d3b5SPoul-Henning Kamp 477a56bb8a5SSatoshi Asami /* 478a56bb8a5SSatoshi Asami * Don't allow the interleave to be smaller than 479a56bb8a5SSatoshi Asami * the biggest component sector. 480a56bb8a5SSatoshi Asami */ 481a56bb8a5SSatoshi Asami if ((cs->sc_ileave > 0) && 482a56bb8a5SSatoshi Asami (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 483a56bb8a5SSatoshi Asami #ifdef DEBUG 484a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 485a56bb8a5SSatoshi Asami printf("ccd%d: interleave must be at least %d\n", 48601706d20SPoul-Henning Kamp cs->sc_unit, (maxsecsize / DEV_BSIZE)); 487a56bb8a5SSatoshi Asami #endif 4881464240eSMatthew Dillon error = EINVAL; 4891464240eSMatthew Dillon goto fail; 490a56bb8a5SSatoshi Asami } 491a56bb8a5SSatoshi Asami 492a56bb8a5SSatoshi Asami /* 493a56bb8a5SSatoshi Asami * If uniform interleave is desired set all sizes to that of 4941464240eSMatthew Dillon * the smallest component. This will guarentee that a single 4951464240eSMatthew Dillon * interleave table is generated. 4961464240eSMatthew Dillon * 4971464240eSMatthew Dillon * Lost space must be taken into account when calculating the 4981464240eSMatthew Dillon * overall size. Half the space is lost when CCDF_MIRROR is 499ddbf51afSPoul-Henning Kamp * specified. 500a56bb8a5SSatoshi Asami */ 50101706d20SPoul-Henning Kamp if (cs->sc_flags & CCDF_UNIFORM) { 502a56bb8a5SSatoshi Asami for (ci = cs->sc_cinfo; 5031464240eSMatthew Dillon ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) { 504a56bb8a5SSatoshi Asami ci->ci_size = minsize; 5051464240eSMatthew Dillon } 50601706d20SPoul-Henning Kamp if (cs->sc_flags & CCDF_MIRROR) { 50734f35216SSatoshi Asami /* 50834f35216SSatoshi Asami * Check to see if an even number of components 5091464240eSMatthew Dillon * have been specified. The interleave must also 5101464240eSMatthew Dillon * be non-zero in order for us to be able to 5111464240eSMatthew Dillon * guarentee the topology. 51234f35216SSatoshi Asami */ 51309b59204SSatoshi Asami if (cs->sc_nccdisks % 2) { 51401706d20SPoul-Henning Kamp printf("ccd%d: mirroring requires an even number of disks\n", cs->sc_unit ); 5151464240eSMatthew Dillon error = EINVAL; 5161464240eSMatthew Dillon goto fail; 51734f35216SSatoshi Asami } 5181464240eSMatthew Dillon if (cs->sc_ileave == 0) { 51901706d20SPoul-Henning Kamp printf("ccd%d: an interleave must be specified when mirroring\n", cs->sc_unit); 5201464240eSMatthew Dillon error = EINVAL; 5211464240eSMatthew Dillon goto fail; 52209b59204SSatoshi Asami } 52309b59204SSatoshi Asami cs->sc_size = (cs->sc_nccdisks/2) * minsize; 5241464240eSMatthew Dillon } else { 5251464240eSMatthew Dillon if (cs->sc_ileave == 0) { 52601706d20SPoul-Henning Kamp printf("ccd%d: an interleave must be specified when using parity\n", cs->sc_unit); 5271464240eSMatthew Dillon error = EINVAL; 5281464240eSMatthew Dillon goto fail; 5291464240eSMatthew Dillon } 530a56bb8a5SSatoshi Asami cs->sc_size = cs->sc_nccdisks * minsize; 531a56bb8a5SSatoshi Asami } 5321464240eSMatthew Dillon } 533a56bb8a5SSatoshi Asami 534a56bb8a5SSatoshi Asami /* 535a56bb8a5SSatoshi Asami * Construct the interleave table. 536a56bb8a5SSatoshi Asami */ 53701706d20SPoul-Henning Kamp ccdinterleave(cs, cs->sc_unit); 538a56bb8a5SSatoshi Asami 539a56bb8a5SSatoshi Asami /* 540a56bb8a5SSatoshi Asami * Create pseudo-geometry based on 1MB cylinders. It's 541a56bb8a5SSatoshi Asami * pretty close. 542a56bb8a5SSatoshi Asami */ 543e59f3105SSøren Schmidt ccg->ccg_secsize = maxsecsize; 544a56bb8a5SSatoshi Asami ccg->ccg_ntracks = 1; 545e322ec4cSMatthew Dillon ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize; 546a56bb8a5SSatoshi Asami ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 547a56bb8a5SSatoshi Asami 548b2dfb1f9SJustin T. Gibbs /* 549d64ada50SJens Schweikhardt * Add a devstat entry for this device. 550b2dfb1f9SJustin T. Gibbs */ 55101706d20SPoul-Henning Kamp devstat_add_entry(&cs->device_stats, "ccd", cs->sc_unit, 552b2dfb1f9SJustin T. Gibbs ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED, 55386b2c846SKenneth D. Merry DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER, 55486b2c846SKenneth D. Merry DEVSTAT_PRIORITY_ARRAY); 555a56bb8a5SSatoshi Asami 556a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_INITED; 55701706d20SPoul-Henning Kamp cs->sc_cflags = cs->sc_flags; /* So we can find out later... */ 558a56bb8a5SSatoshi Asami return (0); 5591464240eSMatthew Dillon fail: 5601464240eSMatthew Dillon while (ci > cs->sc_cinfo) { 5611464240eSMatthew Dillon ci--; 5621464240eSMatthew Dillon free(ci->ci_path, M_DEVBUF); 5631464240eSMatthew Dillon } 564e3f4d3b5SPoul-Henning Kamp if (tmppath != NULL) 565e3f4d3b5SPoul-Henning Kamp free(tmppath, M_DEVBUF); 5661464240eSMatthew Dillon free(cs->sc_cinfo, M_DEVBUF); 5671464240eSMatthew Dillon return (error); 568a56bb8a5SSatoshi Asami } 569a56bb8a5SSatoshi Asami 570a56bb8a5SSatoshi Asami static void 57101706d20SPoul-Henning Kamp ccdinterleave(struct ccd_s *cs, int unit) 572a56bb8a5SSatoshi Asami { 5731464240eSMatthew Dillon struct ccdcinfo *ci, *smallci; 5741464240eSMatthew Dillon struct ccdiinfo *ii; 5751464240eSMatthew Dillon daddr_t bn, lbn; 5761464240eSMatthew Dillon int ix; 577a56bb8a5SSatoshi Asami u_long size; 578a56bb8a5SSatoshi Asami 579a56bb8a5SSatoshi Asami #ifdef DEBUG 580a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 5816a5a4d0aSAndrew Gallatin printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave); 582a56bb8a5SSatoshi Asami #endif 5831464240eSMatthew Dillon 584a56bb8a5SSatoshi Asami /* 5851464240eSMatthew Dillon * Allocate an interleave table. The worst case occurs when each 5861464240eSMatthew Dillon * of N disks is of a different size, resulting in N interleave 5871464240eSMatthew Dillon * tables. 5881464240eSMatthew Dillon * 589a56bb8a5SSatoshi Asami * Chances are this is too big, but we don't care. 590a56bb8a5SSatoshi Asami */ 591a56bb8a5SSatoshi Asami size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 5927cc0979fSDavid Malone cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, 5937cc0979fSDavid Malone M_WAITOK | M_ZERO); 594a56bb8a5SSatoshi Asami 595a56bb8a5SSatoshi Asami /* 596a56bb8a5SSatoshi Asami * Trivial case: no interleave (actually interleave of disk size). 597a56bb8a5SSatoshi Asami * Each table entry represents a single component in its entirety. 5981464240eSMatthew Dillon * 599ddbf51afSPoul-Henning Kamp * An interleave of 0 may not be used with a mirror setup. 600a56bb8a5SSatoshi Asami */ 601a56bb8a5SSatoshi Asami if (cs->sc_ileave == 0) { 602a56bb8a5SSatoshi Asami bn = 0; 603a56bb8a5SSatoshi Asami ii = cs->sc_itable; 604a56bb8a5SSatoshi Asami 605a56bb8a5SSatoshi Asami for (ix = 0; ix < cs->sc_nccdisks; ix++) { 606a56bb8a5SSatoshi Asami /* Allocate space for ii_index. */ 607a56bb8a5SSatoshi Asami ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); 608a56bb8a5SSatoshi Asami ii->ii_ndisk = 1; 609a56bb8a5SSatoshi Asami ii->ii_startblk = bn; 610a56bb8a5SSatoshi Asami ii->ii_startoff = 0; 611a56bb8a5SSatoshi Asami ii->ii_index[0] = ix; 612a56bb8a5SSatoshi Asami bn += cs->sc_cinfo[ix].ci_size; 613a56bb8a5SSatoshi Asami ii++; 614a56bb8a5SSatoshi Asami } 615a56bb8a5SSatoshi Asami ii->ii_ndisk = 0; 616a56bb8a5SSatoshi Asami #ifdef DEBUG 617a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 618a56bb8a5SSatoshi Asami printiinfo(cs->sc_itable); 619a56bb8a5SSatoshi Asami #endif 620a56bb8a5SSatoshi Asami return; 621a56bb8a5SSatoshi Asami } 622a56bb8a5SSatoshi Asami 623a56bb8a5SSatoshi Asami /* 624a56bb8a5SSatoshi Asami * The following isn't fast or pretty; it doesn't have to be. 625a56bb8a5SSatoshi Asami */ 626a56bb8a5SSatoshi Asami size = 0; 627a56bb8a5SSatoshi Asami bn = lbn = 0; 628a56bb8a5SSatoshi Asami for (ii = cs->sc_itable; ; ii++) { 6291464240eSMatthew Dillon /* 6301464240eSMatthew Dillon * Allocate space for ii_index. We might allocate more then 6311464240eSMatthew Dillon * we use. 6321464240eSMatthew Dillon */ 633a56bb8a5SSatoshi Asami ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), 634a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 635a56bb8a5SSatoshi Asami 636a56bb8a5SSatoshi Asami /* 637a56bb8a5SSatoshi Asami * Locate the smallest of the remaining components 638a56bb8a5SSatoshi Asami */ 639a56bb8a5SSatoshi Asami smallci = NULL; 6401464240eSMatthew Dillon for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; 6411464240eSMatthew Dillon ci++) { 642a56bb8a5SSatoshi Asami if (ci->ci_size > size && 643a56bb8a5SSatoshi Asami (smallci == NULL || 6441464240eSMatthew Dillon ci->ci_size < smallci->ci_size)) { 645a56bb8a5SSatoshi Asami smallci = ci; 6461464240eSMatthew Dillon } 6471464240eSMatthew Dillon } 648a56bb8a5SSatoshi Asami 649a56bb8a5SSatoshi Asami /* 650a56bb8a5SSatoshi Asami * Nobody left, all done 651a56bb8a5SSatoshi Asami */ 652a56bb8a5SSatoshi Asami if (smallci == NULL) { 653a56bb8a5SSatoshi Asami ii->ii_ndisk = 0; 654a56bb8a5SSatoshi Asami break; 655a56bb8a5SSatoshi Asami } 656a56bb8a5SSatoshi Asami 657a56bb8a5SSatoshi Asami /* 6581464240eSMatthew Dillon * Record starting logical block using an sc_ileave blocksize. 659a56bb8a5SSatoshi Asami */ 660a56bb8a5SSatoshi Asami ii->ii_startblk = bn / cs->sc_ileave; 6611464240eSMatthew Dillon 6621464240eSMatthew Dillon /* 6631464240eSMatthew Dillon * Record starting comopnent block using an sc_ileave 6641464240eSMatthew Dillon * blocksize. This value is relative to the beginning of 6651464240eSMatthew Dillon * a component disk. 6661464240eSMatthew Dillon */ 667a56bb8a5SSatoshi Asami ii->ii_startoff = lbn; 668a56bb8a5SSatoshi Asami 669a56bb8a5SSatoshi Asami /* 670a56bb8a5SSatoshi Asami * Determine how many disks take part in this interleave 671a56bb8a5SSatoshi Asami * and record their indices. 672a56bb8a5SSatoshi Asami */ 673a56bb8a5SSatoshi Asami ix = 0; 674a56bb8a5SSatoshi Asami for (ci = cs->sc_cinfo; 6751464240eSMatthew Dillon ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) { 6761464240eSMatthew Dillon if (ci->ci_size >= smallci->ci_size) { 677a56bb8a5SSatoshi Asami ii->ii_index[ix++] = ci - cs->sc_cinfo; 6781464240eSMatthew Dillon } 6791464240eSMatthew Dillon } 680a56bb8a5SSatoshi Asami ii->ii_ndisk = ix; 681a56bb8a5SSatoshi Asami bn += ix * (smallci->ci_size - size); 682a56bb8a5SSatoshi Asami lbn = smallci->ci_size / cs->sc_ileave; 683a56bb8a5SSatoshi Asami size = smallci->ci_size; 684a56bb8a5SSatoshi Asami } 685a56bb8a5SSatoshi Asami #ifdef DEBUG 686a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 687a56bb8a5SSatoshi Asami printiinfo(cs->sc_itable); 688a56bb8a5SSatoshi Asami #endif 689a56bb8a5SSatoshi Asami } 690a56bb8a5SSatoshi Asami 691a56bb8a5SSatoshi Asami /* ARGSUSED */ 692e2738b4fSPoul-Henning Kamp static int 693b40ce416SJulian Elischer ccdopen(dev_t dev, int flags, int fmt, struct thread *td) 694a56bb8a5SSatoshi Asami { 695a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 69601706d20SPoul-Henning Kamp struct ccd_s *cs; 697a56bb8a5SSatoshi Asami struct disklabel *lp; 698a56bb8a5SSatoshi Asami int error = 0, part, pmask; 699a56bb8a5SSatoshi Asami 700ddbf51afSPoul-Henning Kamp if (dev->si_drv1 == dev) 701ddbf51afSPoul-Henning Kamp return (0); 702a56bb8a5SSatoshi Asami #ifdef DEBUG 703a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 7046a5a4d0aSAndrew Gallatin printf("ccdopen(%p, %x)\n", dev, flags); 705a56bb8a5SSatoshi Asami #endif 70601706d20SPoul-Henning Kamp 70701706d20SPoul-Henning Kamp cs = IS_ALLOCATED(unit) ? ccdfind(unit) : ccdnew(unit); 708a56bb8a5SSatoshi Asami 709b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 710a56bb8a5SSatoshi Asami return (error); 711a56bb8a5SSatoshi Asami 7126cc5a722SPoul-Henning Kamp lp = &cs->sc_label; 713a56bb8a5SSatoshi Asami 714d8594dfbSSatoshi Asami part = ccdpart(dev); 715a56bb8a5SSatoshi Asami pmask = (1 << part); 716a56bb8a5SSatoshi Asami 717a56bb8a5SSatoshi Asami /* 718a56bb8a5SSatoshi Asami * If we're initialized, check to see if there are any other 719a56bb8a5SSatoshi Asami * open partitions. If not, then it's safe to update 720a56bb8a5SSatoshi Asami * the in-core disklabel. 721a56bb8a5SSatoshi Asami */ 72201706d20SPoul-Henning Kamp if (IS_INITED(cs) && (cs->sc_openmask == 0)) 723a56bb8a5SSatoshi Asami ccdgetdisklabel(dev); 724a56bb8a5SSatoshi Asami 725a56bb8a5SSatoshi Asami /* Check that the partition exists. */ 7267d15435cSJordan K. Hubbard if (part != RAW_PART && ((part >= lp->d_npartitions) || 727a56bb8a5SSatoshi Asami (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 728a56bb8a5SSatoshi Asami error = ENXIO; 729a56bb8a5SSatoshi Asami goto done; 730a56bb8a5SSatoshi Asami } 731a56bb8a5SSatoshi Asami 732af8862e4SPoul-Henning Kamp cs->sc_openmask |= pmask; 733a56bb8a5SSatoshi Asami done: 734a56bb8a5SSatoshi Asami ccdunlock(cs); 735a56bb8a5SSatoshi Asami return (0); 736a56bb8a5SSatoshi Asami } 737a56bb8a5SSatoshi Asami 738a56bb8a5SSatoshi Asami /* ARGSUSED */ 739e2738b4fSPoul-Henning Kamp static int 740b40ce416SJulian Elischer ccdclose(dev_t dev, int flags, int fmt, struct thread *td) 741a56bb8a5SSatoshi Asami { 742a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 74301706d20SPoul-Henning Kamp struct ccd_s *cs; 744a56bb8a5SSatoshi Asami int error = 0, part; 745a56bb8a5SSatoshi Asami 746ddbf51afSPoul-Henning Kamp if (dev->si_drv1 == dev) 747ddbf51afSPoul-Henning Kamp return (0); 748a56bb8a5SSatoshi Asami #ifdef DEBUG 749a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 7506a5a4d0aSAndrew Gallatin printf("ccdclose(%p, %x)\n", dev, flags); 751a56bb8a5SSatoshi Asami #endif 752a56bb8a5SSatoshi Asami 75301706d20SPoul-Henning Kamp if (!IS_ALLOCATED(unit)) 754a56bb8a5SSatoshi Asami return (ENXIO); 75501706d20SPoul-Henning Kamp cs = ccdfind(unit); 756a56bb8a5SSatoshi Asami 757b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 758a56bb8a5SSatoshi Asami return (error); 759a56bb8a5SSatoshi Asami 760d8594dfbSSatoshi Asami part = ccdpart(dev); 761a56bb8a5SSatoshi Asami 762a56bb8a5SSatoshi Asami /* ...that much closer to allowing unconfiguration... */ 763af8862e4SPoul-Henning Kamp cs->sc_openmask &= ~(1 << part); 76401706d20SPoul-Henning Kamp /* collect "garbage" if possible */ 76501706d20SPoul-Henning Kamp if (!IS_INITED(cs) && (cs->sc_flags & CCDF_WANTED) == 0) 766b40ce416SJulian Elischer ccddestroy(cs, td->td_proc); 76701706d20SPoul-Henning Kamp else 768a56bb8a5SSatoshi Asami ccdunlock(cs); 769a56bb8a5SSatoshi Asami return (0); 770a56bb8a5SSatoshi Asami } 771a56bb8a5SSatoshi Asami 772e2738b4fSPoul-Henning Kamp static void 77301706d20SPoul-Henning Kamp ccdstrategy(struct bio *bp) 774a56bb8a5SSatoshi Asami { 7759d7f7369SPoul-Henning Kamp int unit = ccdunit(bp->bio_dev); 77601706d20SPoul-Henning Kamp struct ccd_s *cs = ccdfind(unit); 7771464240eSMatthew Dillon int s; 778a56bb8a5SSatoshi Asami int wlabel; 779a56bb8a5SSatoshi Asami struct disklabel *lp; 780a56bb8a5SSatoshi Asami 781ddbf51afSPoul-Henning Kamp if (bp->bio_dev->si_drv1 == bp->bio_dev) { 782ddbf51afSPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 783ddbf51afSPoul-Henning Kamp return; 784ddbf51afSPoul-Henning Kamp } 785a56bb8a5SSatoshi Asami #ifdef DEBUG 786a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 7876a5a4d0aSAndrew Gallatin printf("ccdstrategy(%p): unit %d\n", bp, unit); 788a56bb8a5SSatoshi Asami #endif 78901706d20SPoul-Henning Kamp if (!IS_INITED(cs)) { 790724682d2SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 791724682d2SPoul-Henning Kamp return; 792a56bb8a5SSatoshi Asami } 793a56bb8a5SSatoshi Asami 794a56bb8a5SSatoshi Asami /* If it's a nil transfer, wake up the top half now. */ 795724682d2SPoul-Henning Kamp if (bp->bio_bcount == 0) { 796724682d2SPoul-Henning Kamp biodone(bp); 797724682d2SPoul-Henning Kamp return; 798724682d2SPoul-Henning Kamp } 799a56bb8a5SSatoshi Asami 8006cc5a722SPoul-Henning Kamp lp = &cs->sc_label; 801a56bb8a5SSatoshi Asami 802a56bb8a5SSatoshi Asami /* 803a56bb8a5SSatoshi Asami * Do bounds checking and adjust transfer. If there's an 804a56bb8a5SSatoshi Asami * error, the bounds check will flag that for us. 805a56bb8a5SSatoshi Asami */ 806a56bb8a5SSatoshi Asami wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 8079d7f7369SPoul-Henning Kamp if (ccdpart(bp->bio_dev) != RAW_PART) { 808724682d2SPoul-Henning Kamp if (bounds_check_with_label(bp, lp, wlabel) <= 0) { 809724682d2SPoul-Henning Kamp biodone(bp); 810724682d2SPoul-Henning Kamp return; 811724682d2SPoul-Henning Kamp } 81274427f90SMatthew Dillon } else { 81374427f90SMatthew Dillon int pbn; /* in sc_secsize chunks */ 81474427f90SMatthew Dillon long sz; /* in sc_secsize chunks */ 81574427f90SMatthew Dillon 8169d7f7369SPoul-Henning Kamp pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE); 8179d7f7369SPoul-Henning Kamp sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize); 81874427f90SMatthew Dillon 81974427f90SMatthew Dillon /* 82074427f90SMatthew Dillon * If out of bounds return an error. If at the EOF point, 82174427f90SMatthew Dillon * simply read or write less. 82274427f90SMatthew Dillon */ 82374427f90SMatthew Dillon 82474427f90SMatthew Dillon if (pbn < 0 || pbn >= cs->sc_size) { 8259d7f7369SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 826724682d2SPoul-Henning Kamp if (pbn != cs->sc_size) 827724682d2SPoul-Henning Kamp biofinish(bp, NULL, EINVAL); 828724682d2SPoul-Henning Kamp else 829724682d2SPoul-Henning Kamp biodone(bp); 830724682d2SPoul-Henning Kamp return; 83174427f90SMatthew Dillon } 83274427f90SMatthew Dillon 83374427f90SMatthew Dillon /* 83474427f90SMatthew Dillon * If the request crosses EOF, truncate the request. 83574427f90SMatthew Dillon */ 83674427f90SMatthew Dillon if (pbn + sz > cs->sc_size) { 8379d7f7369SPoul-Henning Kamp bp->bio_bcount = (cs->sc_size - pbn) * 83874427f90SMatthew Dillon cs->sc_geom.ccg_secsize; 83974427f90SMatthew Dillon } 84074427f90SMatthew Dillon } 841a56bb8a5SSatoshi Asami 8429d7f7369SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 843a56bb8a5SSatoshi Asami 844a56bb8a5SSatoshi Asami /* 845a56bb8a5SSatoshi Asami * "Start" the unit. 846a56bb8a5SSatoshi Asami */ 847a56bb8a5SSatoshi Asami s = splbio(); 848a56bb8a5SSatoshi Asami ccdstart(cs, bp); 849a56bb8a5SSatoshi Asami splx(s); 850a56bb8a5SSatoshi Asami return; 851a56bb8a5SSatoshi Asami } 852a56bb8a5SSatoshi Asami 853a56bb8a5SSatoshi Asami static void 85401706d20SPoul-Henning Kamp ccdstart(struct ccd_s *cs, struct bio *bp) 855a56bb8a5SSatoshi Asami { 8561464240eSMatthew Dillon long bcount, rcount; 8573bc746beSSatoshi Asami struct ccdbuf *cbp[4]; 8583bc746beSSatoshi Asami /* XXX! : 2 reads and 2 writes for RAID 4/5 */ 859a56bb8a5SSatoshi Asami caddr_t addr; 860a56bb8a5SSatoshi Asami daddr_t bn; 861a56bb8a5SSatoshi Asami struct partition *pp; 862a56bb8a5SSatoshi Asami 863a56bb8a5SSatoshi Asami #ifdef DEBUG 864a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 8656a5a4d0aSAndrew Gallatin printf("ccdstart(%p, %p)\n", cs, bp); 866a56bb8a5SSatoshi Asami #endif 867a56bb8a5SSatoshi Asami 868b2dfb1f9SJustin T. Gibbs /* Record the transaction start */ 869b2dfb1f9SJustin T. Gibbs devstat_start_transaction(&cs->device_stats); 870a56bb8a5SSatoshi Asami 871a56bb8a5SSatoshi Asami /* 872a56bb8a5SSatoshi Asami * Translate the partition-relative block number to an absolute. 873a56bb8a5SSatoshi Asami */ 8749d7f7369SPoul-Henning Kamp bn = bp->bio_blkno; 8759d7f7369SPoul-Henning Kamp if (ccdpart(bp->bio_dev) != RAW_PART) { 8769d7f7369SPoul-Henning Kamp pp = &cs->sc_label.d_partitions[ccdpart(bp->bio_dev)]; 877a56bb8a5SSatoshi Asami bn += pp->p_offset; 878a56bb8a5SSatoshi Asami } 879a56bb8a5SSatoshi Asami 880a56bb8a5SSatoshi Asami /* 881a56bb8a5SSatoshi Asami * Allocate component buffers and fire off the requests 882a56bb8a5SSatoshi Asami */ 8839d7f7369SPoul-Henning Kamp addr = bp->bio_data; 8849d7f7369SPoul-Henning Kamp for (bcount = bp->bio_bcount; bcount > 0; bcount -= rcount) { 8853bc746beSSatoshi Asami ccdbuffer(cbp, cs, bp, bn, addr, bcount); 8869d7f7369SPoul-Henning Kamp rcount = cbp[0]->cb_buf.bio_bcount; 8871464240eSMatthew Dillon 8881464240eSMatthew Dillon if (cs->sc_cflags & CCDF_MIRROR) { 8891464240eSMatthew Dillon /* 8901464240eSMatthew Dillon * Mirroring. Writes go to both disks, reads are 8911464240eSMatthew Dillon * taken from whichever disk seems most appropriate. 8921464240eSMatthew Dillon * 8931464240eSMatthew Dillon * We attempt to localize reads to the disk whos arm 8941464240eSMatthew Dillon * is nearest the read request. We ignore seeks due 8951464240eSMatthew Dillon * to writes when making this determination and we 8961464240eSMatthew Dillon * also try to avoid hogging. 8971464240eSMatthew Dillon */ 8989d7f7369SPoul-Henning Kamp if (cbp[0]->cb_buf.bio_cmd == BIO_WRITE) { 899d616ee08SPoul-Henning Kamp BIO_STRATEGY(&cbp[0]->cb_buf); 900d616ee08SPoul-Henning Kamp BIO_STRATEGY(&cbp[1]->cb_buf); 9011464240eSMatthew Dillon } else { 9021464240eSMatthew Dillon int pick = cs->sc_pick; 9031464240eSMatthew Dillon daddr_t range = cs->sc_size / 16; 9041464240eSMatthew Dillon 9051464240eSMatthew Dillon if (bn < cs->sc_blk[pick] - range || 9061464240eSMatthew Dillon bn > cs->sc_blk[pick] + range 9071464240eSMatthew Dillon ) { 9081464240eSMatthew Dillon cs->sc_pick = pick = 1 - pick; 9091464240eSMatthew Dillon } 9101464240eSMatthew Dillon cs->sc_blk[pick] = bn + btodb(rcount); 911d616ee08SPoul-Henning Kamp BIO_STRATEGY(&cbp[pick]->cb_buf); 9121464240eSMatthew Dillon } 9131464240eSMatthew Dillon } else { 9141464240eSMatthew Dillon /* 9151464240eSMatthew Dillon * Not mirroring 9161464240eSMatthew Dillon */ 917d616ee08SPoul-Henning Kamp BIO_STRATEGY(&cbp[0]->cb_buf); 9183bc746beSSatoshi Asami } 919a56bb8a5SSatoshi Asami bn += btodb(rcount); 920a56bb8a5SSatoshi Asami addr += rcount; 921a56bb8a5SSatoshi Asami } 922a56bb8a5SSatoshi Asami } 923a56bb8a5SSatoshi Asami 924a56bb8a5SSatoshi Asami /* 925a56bb8a5SSatoshi Asami * Build a component buffer header. 926a56bb8a5SSatoshi Asami */ 927e2738b4fSPoul-Henning Kamp static void 92801706d20SPoul-Henning Kamp ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, caddr_t addr, long bcount) 929a56bb8a5SSatoshi Asami { 9301464240eSMatthew Dillon struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ 9311464240eSMatthew Dillon struct ccdbuf *cbp; 9321464240eSMatthew Dillon daddr_t cbn, cboff; 9331464240eSMatthew Dillon off_t cbc; 934a56bb8a5SSatoshi Asami 935a56bb8a5SSatoshi Asami #ifdef DEBUG 936a56bb8a5SSatoshi Asami if (ccddebug & CCDB_IO) 937ff8cc2ebSBruce Evans printf("ccdbuffer(%p, %p, %lld, %p, %ld)\n", 938ff8cc2ebSBruce Evans (void *)cs, (void *)bp, (long long)bn, (void *)addr, 939ff8cc2ebSBruce Evans bcount); 940a56bb8a5SSatoshi Asami #endif 941a56bb8a5SSatoshi Asami /* 942a56bb8a5SSatoshi Asami * Determine which component bn falls in. 943a56bb8a5SSatoshi Asami */ 944a56bb8a5SSatoshi Asami cbn = bn; 945a56bb8a5SSatoshi Asami cboff = 0; 946a56bb8a5SSatoshi Asami 947a56bb8a5SSatoshi Asami if (cs->sc_ileave == 0) { 9481464240eSMatthew Dillon /* 9491464240eSMatthew Dillon * Serially concatenated and neither a mirror nor a parity 9501464240eSMatthew Dillon * config. This is a special case. 9511464240eSMatthew Dillon */ 9521464240eSMatthew Dillon daddr_t sblk; 953a56bb8a5SSatoshi Asami 954a56bb8a5SSatoshi Asami sblk = 0; 955a56bb8a5SSatoshi Asami for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 956a56bb8a5SSatoshi Asami sblk += ci->ci_size; 957a56bb8a5SSatoshi Asami cbn -= sblk; 9581464240eSMatthew Dillon } else { 9591464240eSMatthew Dillon struct ccdiinfo *ii; 960a56bb8a5SSatoshi Asami int ccdisk, off; 961a56bb8a5SSatoshi Asami 9621464240eSMatthew Dillon /* 9631464240eSMatthew Dillon * Calculate cbn, the logical superblock (sc_ileave chunks), 9641464240eSMatthew Dillon * and cboff, a normal block offset (DEV_BSIZE chunks) relative 9651464240eSMatthew Dillon * to cbn. 9661464240eSMatthew Dillon */ 9671464240eSMatthew Dillon cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */ 9681464240eSMatthew Dillon cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */ 9691464240eSMatthew Dillon 9701464240eSMatthew Dillon /* 9711464240eSMatthew Dillon * Figure out which interleave table to use. 9721464240eSMatthew Dillon */ 9731464240eSMatthew Dillon for (ii = cs->sc_itable; ii->ii_ndisk; ii++) { 974a56bb8a5SSatoshi Asami if (ii->ii_startblk > cbn) 975a56bb8a5SSatoshi Asami break; 9761464240eSMatthew Dillon } 977a56bb8a5SSatoshi Asami ii--; 9781464240eSMatthew Dillon 9791464240eSMatthew Dillon /* 9801464240eSMatthew Dillon * off is the logical superblock relative to the beginning 9811464240eSMatthew Dillon * of this interleave block. 9821464240eSMatthew Dillon */ 983a56bb8a5SSatoshi Asami off = cbn - ii->ii_startblk; 9841464240eSMatthew Dillon 9851464240eSMatthew Dillon /* 9861464240eSMatthew Dillon * We must calculate which disk component to use (ccdisk), 9871464240eSMatthew Dillon * and recalculate cbn to be the superblock relative to 9881464240eSMatthew Dillon * the beginning of the component. This is typically done by 9891464240eSMatthew Dillon * adding 'off' and ii->ii_startoff together. However, 'off' 9901464240eSMatthew Dillon * must typically be divided by the number of components in 9911464240eSMatthew Dillon * this interleave array to be properly convert it from a 9921464240eSMatthew Dillon * CCD-relative logical superblock number to a 9931464240eSMatthew Dillon * component-relative superblock number. 9941464240eSMatthew Dillon */ 995a56bb8a5SSatoshi Asami if (ii->ii_ndisk == 1) { 9961464240eSMatthew Dillon /* 9971464240eSMatthew Dillon * When we have just one disk, it can't be a mirror 9981464240eSMatthew Dillon * or a parity config. 9991464240eSMatthew Dillon */ 1000a56bb8a5SSatoshi Asami ccdisk = ii->ii_index[0]; 1001a56bb8a5SSatoshi Asami cbn = ii->ii_startoff + off; 1002a56bb8a5SSatoshi Asami } else { 100309b59204SSatoshi Asami if (cs->sc_cflags & CCDF_MIRROR) { 10041464240eSMatthew Dillon /* 10051464240eSMatthew Dillon * We have forced a uniform mapping, resulting 10061464240eSMatthew Dillon * in a single interleave array. We double 10071464240eSMatthew Dillon * up on the first half of the available 10081464240eSMatthew Dillon * components and our mirror is in the second 10091464240eSMatthew Dillon * half. This only works with a single 10101464240eSMatthew Dillon * interleave array because doubling up 10111464240eSMatthew Dillon * doubles the number of sectors, so there 10121464240eSMatthew Dillon * cannot be another interleave array because 10131464240eSMatthew Dillon * the next interleave array's calculations 10141464240eSMatthew Dillon * would be off. 10151464240eSMatthew Dillon */ 10161464240eSMatthew Dillon int ndisk2 = ii->ii_ndisk / 2; 10171464240eSMatthew Dillon ccdisk = ii->ii_index[off % ndisk2]; 10181464240eSMatthew Dillon cbn = ii->ii_startoff + off / ndisk2; 10191464240eSMatthew Dillon ci2 = &cs->sc_cinfo[ccdisk + ndisk2]; 10201464240eSMatthew Dillon } else { 1021a56bb8a5SSatoshi Asami ccdisk = ii->ii_index[off % ii->ii_ndisk]; 1022a56bb8a5SSatoshi Asami cbn = ii->ii_startoff + off / ii->ii_ndisk; 1023a56bb8a5SSatoshi Asami } 10247ecb65faSSatoshi Asami } 10251464240eSMatthew Dillon 1026a56bb8a5SSatoshi Asami ci = &cs->sc_cinfo[ccdisk]; 10271464240eSMatthew Dillon 10281464240eSMatthew Dillon /* 10291464240eSMatthew Dillon * Convert cbn from a superblock to a normal block so it 10301464240eSMatthew Dillon * can be used to calculate (along with cboff) the normal 10311464240eSMatthew Dillon * block index into this particular disk. 10321464240eSMatthew Dillon */ 10331464240eSMatthew Dillon cbn *= cs->sc_ileave; 1034a56bb8a5SSatoshi Asami } 1035a56bb8a5SSatoshi Asami 1036a56bb8a5SSatoshi Asami /* 1037a56bb8a5SSatoshi Asami * Fill in the component buf structure. 1038a56bb8a5SSatoshi Asami */ 10391464240eSMatthew Dillon cbp = getccdbuf(NULL); 10409d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_cmd = bp->bio_cmd; 10419d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_done = ccdiodone; 10429d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_dev = ci->ci_dev; /* XXX */ 10439d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_blkno = cbn + cboff + CCD_OFFSET; 10449d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_offset = dbtob(cbn + cboff + CCD_OFFSET); 10459d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_data = addr; 1046a56bb8a5SSatoshi Asami if (cs->sc_ileave == 0) 104740969e38SDavid Greenman cbc = dbtob((off_t)(ci->ci_size - cbn)); 1048a56bb8a5SSatoshi Asami else 104940969e38SDavid Greenman cbc = dbtob((off_t)(cs->sc_ileave - cboff)); 10509d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_bcount = (cbc < bcount) ? cbc : bcount; 10519d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_caller1 = (void*)cbp->cb_buf.bio_bcount; 1052c0b89506SJohn Dyson 1053a56bb8a5SSatoshi Asami /* 1054a56bb8a5SSatoshi Asami * context for ccdiodone 1055a56bb8a5SSatoshi Asami */ 1056a56bb8a5SSatoshi Asami cbp->cb_obp = bp; 105701706d20SPoul-Henning Kamp cbp->cb_unit = cs->sc_unit; 1058a56bb8a5SSatoshi Asami cbp->cb_comp = ci - cs->sc_cinfo; 1059a56bb8a5SSatoshi Asami 1060a56bb8a5SSatoshi Asami #ifdef DEBUG 1061a56bb8a5SSatoshi Asami if (ccddebug & CCDB_IO) 10622dfbcdd4SMaxime Henrion printf(" dev %p(u%ld): cbp %p bn %jd addr %p bcnt %ld\n", 10636a5a4d0aSAndrew Gallatin ci->ci_dev, (unsigned long)(ci-cs->sc_cinfo), cbp, 10642dfbcdd4SMaxime Henrion (intmax_t)cbp->cb_buf.bio_blkno, cbp->cb_buf.bio_data, 10656a5a4d0aSAndrew Gallatin cbp->cb_buf.bio_bcount); 1066a56bb8a5SSatoshi Asami #endif 10673bc746beSSatoshi Asami cb[0] = cbp; 10681464240eSMatthew Dillon 10691464240eSMatthew Dillon /* 10701464240eSMatthew Dillon * Note: both I/O's setup when reading from mirror, but only one 10711464240eSMatthew Dillon * will be executed. 10721464240eSMatthew Dillon */ 10731464240eSMatthew Dillon if (cs->sc_cflags & CCDF_MIRROR) { 10741464240eSMatthew Dillon /* mirror, setup second I/O */ 10751464240eSMatthew Dillon cbp = getccdbuf(cb[0]); 10769d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_dev = ci2->ci_dev; 10773bc746beSSatoshi Asami cbp->cb_comp = ci2 - cs->sc_cinfo; 10783bc746beSSatoshi Asami cb[1] = cbp; 1079e7322872SSatoshi Asami /* link together the ccdbuf's and clear "mirror done" flag */ 1080e7322872SSatoshi Asami cb[0]->cb_mirror = cb[1]; 1081e7322872SSatoshi Asami cb[1]->cb_mirror = cb[0]; 1082e7322872SSatoshi Asami cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; 1083e7322872SSatoshi Asami cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; 10843bc746beSSatoshi Asami } 1085a56bb8a5SSatoshi Asami } 1086a56bb8a5SSatoshi Asami 1087a56bb8a5SSatoshi Asami static void 108801706d20SPoul-Henning Kamp ccdintr(struct ccd_s *cs, struct bio *bp) 1089a56bb8a5SSatoshi Asami { 1090a56bb8a5SSatoshi Asami #ifdef DEBUG 1091a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 10926a5a4d0aSAndrew Gallatin printf("ccdintr(%p, %p)\n", cs, bp); 1093a56bb8a5SSatoshi Asami #endif 1094a56bb8a5SSatoshi Asami /* 1095a56bb8a5SSatoshi Asami * Request is done for better or worse, wakeup the top half. 1096a56bb8a5SSatoshi Asami */ 10979d7f7369SPoul-Henning Kamp if (bp->bio_flags & BIO_ERROR) 10989d7f7369SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 1099a468031cSPoul-Henning Kamp biofinish(bp, &cs->device_stats, 0); 1100a56bb8a5SSatoshi Asami } 1101a56bb8a5SSatoshi Asami 1102a56bb8a5SSatoshi Asami /* 1103a56bb8a5SSatoshi Asami * Called at interrupt time. 1104a56bb8a5SSatoshi Asami * Mark the component as done and if all components are done, 1105a56bb8a5SSatoshi Asami * take a ccd interrupt. 1106a56bb8a5SSatoshi Asami */ 1107e2738b4fSPoul-Henning Kamp static void 110801706d20SPoul-Henning Kamp ccdiodone(struct bio *ibp) 1109a56bb8a5SSatoshi Asami { 111021144e3bSPoul-Henning Kamp struct ccdbuf *cbp = (struct ccdbuf *)ibp; 11119d7f7369SPoul-Henning Kamp struct bio *bp = cbp->cb_obp; 11121464240eSMatthew Dillon int unit = cbp->cb_unit; 1113a56bb8a5SSatoshi Asami int count, s; 1114a56bb8a5SSatoshi Asami 1115a56bb8a5SSatoshi Asami s = splbio(); 1116a56bb8a5SSatoshi Asami #ifdef DEBUG 1117a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 11186a5a4d0aSAndrew Gallatin printf("ccdiodone(%p)\n", cbp); 1119a56bb8a5SSatoshi Asami if (ccddebug & CCDB_IO) { 11206a5a4d0aSAndrew Gallatin printf("ccdiodone: bp %p bcount %ld resid %ld\n", 11219d7f7369SPoul-Henning Kamp bp, bp->bio_bcount, bp->bio_resid); 11222dfbcdd4SMaxime Henrion printf(" dev %p(u%d), cbp %p bn %jd addr %p bcnt %ld\n", 11239d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_dev, cbp->cb_comp, cbp, 11242dfbcdd4SMaxime Henrion (intmax_t)cbp->cb_buf.bio_blkno, cbp->cb_buf.bio_data, 11259d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_bcount); 1126a56bb8a5SSatoshi Asami } 1127a56bb8a5SSatoshi Asami #endif 11281464240eSMatthew Dillon /* 11291464240eSMatthew Dillon * If an error occured, report it. If this is a mirrored 11301464240eSMatthew Dillon * configuration and the first of two possible reads, do not 11311464240eSMatthew Dillon * set the error in the bp yet because the second read may 11321464240eSMatthew Dillon * succeed. 11331464240eSMatthew Dillon */ 1134a56bb8a5SSatoshi Asami 11359d7f7369SPoul-Henning Kamp if (cbp->cb_buf.bio_flags & BIO_ERROR) { 11361464240eSMatthew Dillon const char *msg = ""; 11371464240eSMatthew Dillon 113801706d20SPoul-Henning Kamp if ((ccdfind(unit)->sc_cflags & CCDF_MIRROR) && 11399d7f7369SPoul-Henning Kamp (cbp->cb_buf.bio_cmd == BIO_READ) && 11401464240eSMatthew Dillon (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 11411464240eSMatthew Dillon /* 11421464240eSMatthew Dillon * We will try our read on the other disk down 11431464240eSMatthew Dillon * below, also reverse the default pick so if we 11441464240eSMatthew Dillon * are doing a scan we do not keep hitting the 11451464240eSMatthew Dillon * bad disk first. 11461464240eSMatthew Dillon */ 114701706d20SPoul-Henning Kamp struct ccd_s *cs = ccdfind(unit); 11481464240eSMatthew Dillon 11491464240eSMatthew Dillon msg = ", trying other disk"; 11501464240eSMatthew Dillon cs->sc_pick = 1 - cs->sc_pick; 11519d7f7369SPoul-Henning Kamp cs->sc_blk[cs->sc_pick] = bp->bio_blkno; 11521464240eSMatthew Dillon } else { 11539d7f7369SPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 11549d7f7369SPoul-Henning Kamp bp->bio_error = cbp->cb_buf.bio_error ? 11559d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_error : EIO; 11561464240eSMatthew Dillon } 115792faa7b5SMaxime Henrion printf("ccd%d: error %d on component %d block %jd " 1158f368af93SMaxime Henrion "(ccd block %jd)%s\n", unit, bp->bio_error, cbp->cb_comp, 115992faa7b5SMaxime Henrion (intmax_t)cbp->cb_buf.bio_blkno, (intmax_t)bp->bio_blkno, 116092faa7b5SMaxime Henrion msg); 1161a56bb8a5SSatoshi Asami } 1162e7322872SSatoshi Asami 11631464240eSMatthew Dillon /* 11641464240eSMatthew Dillon * Process mirror. If we are writing, I/O has been initiated on both 11651464240eSMatthew Dillon * buffers and we fall through only after both are finished. 11661464240eSMatthew Dillon * 11671464240eSMatthew Dillon * If we are reading only one I/O is initiated at a time. If an 11681464240eSMatthew Dillon * error occurs we initiate the second I/O and return, otherwise 11691464240eSMatthew Dillon * we free the second I/O without initiating it. 11701464240eSMatthew Dillon */ 11711464240eSMatthew Dillon 117201706d20SPoul-Henning Kamp if (ccdfind(unit)->sc_cflags & CCDF_MIRROR) { 11739d7f7369SPoul-Henning Kamp if (cbp->cb_buf.bio_cmd == BIO_WRITE) { 11741464240eSMatthew Dillon /* 11751464240eSMatthew Dillon * When writing, handshake with the second buffer 11761464240eSMatthew Dillon * to determine when both are done. If both are not 11771464240eSMatthew Dillon * done, return here. 11781464240eSMatthew Dillon */ 1179e7322872SSatoshi Asami if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 1180e7322872SSatoshi Asami cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; 1181e7322872SSatoshi Asami putccdbuf(cbp); 1182e7322872SSatoshi Asami splx(s); 1183e7322872SSatoshi Asami return; 1184e7322872SSatoshi Asami } 11851464240eSMatthew Dillon } else { 11861464240eSMatthew Dillon /* 11871464240eSMatthew Dillon * When reading, either dispose of the second buffer 11881464240eSMatthew Dillon * or initiate I/O on the second buffer if an error 11891464240eSMatthew Dillon * occured with this one. 11901464240eSMatthew Dillon */ 11911464240eSMatthew Dillon if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 11929d7f7369SPoul-Henning Kamp if (cbp->cb_buf.bio_flags & BIO_ERROR) { 11931464240eSMatthew Dillon cbp->cb_mirror->cb_pflags |= 11941464240eSMatthew Dillon CCDPF_MIRROR_DONE; 1195d616ee08SPoul-Henning Kamp BIO_STRATEGY(&cbp->cb_mirror->cb_buf); 11961464240eSMatthew Dillon putccdbuf(cbp); 11971464240eSMatthew Dillon splx(s); 11981464240eSMatthew Dillon return; 11991464240eSMatthew Dillon } else { 12001464240eSMatthew Dillon putccdbuf(cbp->cb_mirror); 12011464240eSMatthew Dillon /* fall through */ 12021464240eSMatthew Dillon } 12031464240eSMatthew Dillon } 12041464240eSMatthew Dillon } 12051464240eSMatthew Dillon } 1206e7322872SSatoshi Asami 120725d1a00bSMatthew Dillon /* 12089d7f7369SPoul-Henning Kamp * use bio_caller1 to determine how big the original request was rather 12099d7f7369SPoul-Henning Kamp * then bio_bcount, because bio_bcount may have been truncated for EOF. 121025d1a00bSMatthew Dillon * 121125d1a00bSMatthew Dillon * XXX We check for an error, but we do not test the resid for an 121225d1a00bSMatthew Dillon * aligned EOF condition. This may result in character & block 121325d1a00bSMatthew Dillon * device access not recognizing EOF properly when read or written 121425d1a00bSMatthew Dillon * sequentially, but will not effect filesystems. 121525d1a00bSMatthew Dillon */ 12169d7f7369SPoul-Henning Kamp count = (long)cbp->cb_buf.bio_caller1; 1217a56bb8a5SSatoshi Asami putccdbuf(cbp); 1218a56bb8a5SSatoshi Asami 1219a56bb8a5SSatoshi Asami /* 1220a56bb8a5SSatoshi Asami * If all done, "interrupt". 1221a56bb8a5SSatoshi Asami */ 12229d7f7369SPoul-Henning Kamp bp->bio_resid -= count; 12239d7f7369SPoul-Henning Kamp if (bp->bio_resid < 0) 1224a56bb8a5SSatoshi Asami panic("ccdiodone: count"); 12259d7f7369SPoul-Henning Kamp if (bp->bio_resid == 0) 122601706d20SPoul-Henning Kamp ccdintr(ccdfind(unit), bp); 1227a56bb8a5SSatoshi Asami splx(s); 1228a56bb8a5SSatoshi Asami } 1229a56bb8a5SSatoshi Asami 1230e2738b4fSPoul-Henning Kamp static int 1231b40ce416SJulian Elischer ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1232a56bb8a5SSatoshi Asami { 1233ddbf51afSPoul-Henning Kamp struct ccd_ioctl *ccio; 1234ddbf51afSPoul-Henning Kamp u_int unit; 1235ddbf51afSPoul-Henning Kamp dev_t dev2; 1236ddbf51afSPoul-Henning Kamp int error; 1237ddbf51afSPoul-Henning Kamp 1238ddbf51afSPoul-Henning Kamp if (dev->si_drv1 != dev) { 1239ddbf51afSPoul-Henning Kamp switch (cmd) { 1240ddbf51afSPoul-Henning Kamp case CCDIOCSET: 1241ddbf51afSPoul-Henning Kamp case CCDIOCCLR: 1242ddbf51afSPoul-Henning Kamp case CCDCONFINFO: 1243ddbf51afSPoul-Henning Kamp case CCDCPPINFO: 1244ddbf51afSPoul-Henning Kamp printf("*** WARNING: upgrade your ccdconfig(8) binary\n"); 1245ddbf51afSPoul-Henning Kamp printf("*** WARNING: continuing in 30 seconds\n"); 1246ddbf51afSPoul-Henning Kamp tsleep(dev, PRIBIO, "ccdbug", hz * 30); 1247ddbf51afSPoul-Henning Kamp break; 1248ddbf51afSPoul-Henning Kamp } 1249ddbf51afSPoul-Henning Kamp return ccdioctltoo(dev, cmd, data, flag, td); 1250ddbf51afSPoul-Henning Kamp } 1251ddbf51afSPoul-Henning Kamp switch (cmd) { 1252ddbf51afSPoul-Henning Kamp case CCDIOCSET: 1253ddbf51afSPoul-Henning Kamp case CCDIOCCLR: 1254ddbf51afSPoul-Henning Kamp ccio = (struct ccd_ioctl *)data; 1255ddbf51afSPoul-Henning Kamp unit = ccio->ccio_size; 1256ddbf51afSPoul-Henning Kamp dev2 = makedev(CDEV_MAJOR, unit * 8 + 2); 1257ddbf51afSPoul-Henning Kamp if (!(dev2->si_flags & SI_NAMED)) { 1258ddbf51afSPoul-Henning Kamp dev2 = make_dev(&ccd_cdevsw, unit * 8 + 2, 1259ddbf51afSPoul-Henning Kamp UID_ROOT, GID_OPERATOR, 0640, "ccd%dc", unit); 1260ddbf51afSPoul-Henning Kamp ccdnew(unit); 1261ddbf51afSPoul-Henning Kamp } 1262ddbf51afSPoul-Henning Kamp return (ccdioctltoo(dev2, cmd, data, flag, td)); 1263ddbf51afSPoul-Henning Kamp case CCDCONFINFO: 1264ddbf51afSPoul-Henning Kamp { 1265ddbf51afSPoul-Henning Kamp int ninit = 0; 1266ddbf51afSPoul-Henning Kamp struct ccdconf *conf = (struct ccdconf *)data; 1267ddbf51afSPoul-Henning Kamp struct ccd_s *tmpcs; 1268ddbf51afSPoul-Henning Kamp struct ccd_s *ubuf = conf->buffer; 1269ddbf51afSPoul-Henning Kamp 1270ddbf51afSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 1271ddbf51afSPoul-Henning Kamp LIST_FOREACH(tmpcs, &ccd_softc_list, list) 1272ddbf51afSPoul-Henning Kamp if (IS_INITED(tmpcs)) 1273ddbf51afSPoul-Henning Kamp ninit++; 1274ddbf51afSPoul-Henning Kamp 1275ddbf51afSPoul-Henning Kamp if (conf->size == 0) { 1276ddbf51afSPoul-Henning Kamp conf->size = sizeof(struct ccd_s) * ninit; 1277ddbf51afSPoul-Henning Kamp return (0); 1278ddbf51afSPoul-Henning Kamp } else if ((conf->size / sizeof(struct ccd_s) != ninit) || 1279ddbf51afSPoul-Henning Kamp (conf->size % sizeof(struct ccd_s) != 0)) { 1280ddbf51afSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 1281ddbf51afSPoul-Henning Kamp return (EINVAL); 1282ddbf51afSPoul-Henning Kamp } 1283ddbf51afSPoul-Henning Kamp 1284ddbf51afSPoul-Henning Kamp ubuf += ninit; 1285ddbf51afSPoul-Henning Kamp LIST_FOREACH(tmpcs, &ccd_softc_list, list) { 1286ddbf51afSPoul-Henning Kamp if (!IS_INITED(tmpcs)) 1287ddbf51afSPoul-Henning Kamp continue; 1288ddbf51afSPoul-Henning Kamp error = copyout(tmpcs, --ubuf, 1289ddbf51afSPoul-Henning Kamp sizeof(struct ccd_s)); 1290ddbf51afSPoul-Henning Kamp if (error != 0) 1291ddbf51afSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 1292ddbf51afSPoul-Henning Kamp return (error); 1293ddbf51afSPoul-Henning Kamp } 1294ddbf51afSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 1295ddbf51afSPoul-Henning Kamp return (0); 1296ddbf51afSPoul-Henning Kamp } 1297ddbf51afSPoul-Henning Kamp 1298ddbf51afSPoul-Henning Kamp case CCDCPPINFO: 1299ddbf51afSPoul-Henning Kamp { 1300ddbf51afSPoul-Henning Kamp struct ccdcpps *cpps = (struct ccdcpps *)data; 1301ddbf51afSPoul-Henning Kamp char *ubuf = cpps->buffer; 1302ddbf51afSPoul-Henning Kamp 1303ddbf51afSPoul-Henning Kamp 1304ddbf51afSPoul-Henning Kamp error = copyin(ubuf, &unit, sizeof (unit)); 1305ddbf51afSPoul-Henning Kamp if (error) 1306ddbf51afSPoul-Henning Kamp return (error); 1307ddbf51afSPoul-Henning Kamp 1308ddbf51afSPoul-Henning Kamp if (!IS_ALLOCATED(unit)) 1309ddbf51afSPoul-Henning Kamp return (ENXIO); 1310ddbf51afSPoul-Henning Kamp dev2 = makedev(CDEV_MAJOR, unit * 8 + 2); 1311ddbf51afSPoul-Henning Kamp return (ccdioctltoo(dev2, cmd, data, flag, td)); 1312ddbf51afSPoul-Henning Kamp } 1313ddbf51afSPoul-Henning Kamp 1314ddbf51afSPoul-Henning Kamp default: 1315ddbf51afSPoul-Henning Kamp return (ENXIO); 1316ddbf51afSPoul-Henning Kamp } 1317ddbf51afSPoul-Henning Kamp } 1318ddbf51afSPoul-Henning Kamp 1319ddbf51afSPoul-Henning Kamp static int 1320ddbf51afSPoul-Henning Kamp ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1321ddbf51afSPoul-Henning Kamp { 1322ddbf51afSPoul-Henning Kamp int unit; 1323a56bb8a5SSatoshi Asami int i, j, lookedup = 0, error = 0; 1324a56bb8a5SSatoshi Asami int part, pmask, s; 132501706d20SPoul-Henning Kamp struct ccd_s *cs; 1326a56bb8a5SSatoshi Asami struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1327a56bb8a5SSatoshi Asami char **cpp; 1328a56bb8a5SSatoshi Asami struct vnode **vpp; 1329a56bb8a5SSatoshi Asami 1330ddbf51afSPoul-Henning Kamp unit = ccdunit(dev); 133101706d20SPoul-Henning Kamp if (!IS_ALLOCATED(unit)) 1332a56bb8a5SSatoshi Asami return (ENXIO); 133301706d20SPoul-Henning Kamp cs = ccdfind(unit); 1334a56bb8a5SSatoshi Asami 1335a56bb8a5SSatoshi Asami switch (cmd) { 1336a56bb8a5SSatoshi Asami case CCDIOCSET: 133701706d20SPoul-Henning Kamp if (IS_INITED(cs)) 1338a56bb8a5SSatoshi Asami return (EBUSY); 1339a56bb8a5SSatoshi Asami 1340a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1341a56bb8a5SSatoshi Asami return (EBADF); 1342a56bb8a5SSatoshi Asami 1343b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 1344a56bb8a5SSatoshi Asami return (error); 1345a56bb8a5SSatoshi Asami 1346bf61e266SKris Kennaway if (ccio->ccio_ndisks > CCD_MAXNDISKS) 1347bf61e266SKris Kennaway return (EINVAL); 1348bf61e266SKris Kennaway 1349a56bb8a5SSatoshi Asami /* Fill in some important bits. */ 135001706d20SPoul-Henning Kamp cs->sc_ileave = ccio->ccio_ileave; 1351f05f44f0SPoul-Henning Kamp if (cs->sc_ileave == 0 && (ccio->ccio_flags & CCDF_MIRROR)) { 1352f05f44f0SPoul-Henning Kamp printf("ccd%d: disabling mirror, interleave is 0\n", 1353f05f44f0SPoul-Henning Kamp unit); 1354f05f44f0SPoul-Henning Kamp ccio->ccio_flags &= ~(CCDF_MIRROR); 1355b8e29b55SSatoshi Asami } 135609b59204SSatoshi Asami if ((ccio->ccio_flags & CCDF_MIRROR) && 13577ecb65faSSatoshi Asami !(ccio->ccio_flags & CCDF_UNIFORM)) { 135809b59204SSatoshi Asami printf("ccd%d: mirror/parity forces uniform flag\n", 135909b59204SSatoshi Asami unit); 13607ecb65faSSatoshi Asami ccio->ccio_flags |= CCDF_UNIFORM; 13617ecb65faSSatoshi Asami } 136201706d20SPoul-Henning Kamp cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK; 1363a56bb8a5SSatoshi Asami 1364a56bb8a5SSatoshi Asami /* 1365a56bb8a5SSatoshi Asami * Allocate space for and copy in the array of 1366a56bb8a5SSatoshi Asami * componet pathnames and device numbers. 1367a56bb8a5SSatoshi Asami */ 1368a56bb8a5SSatoshi Asami cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1369a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 1370a56bb8a5SSatoshi Asami vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1371a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 1372a56bb8a5SSatoshi Asami 1373a56bb8a5SSatoshi Asami error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1374a56bb8a5SSatoshi Asami ccio->ccio_ndisks * sizeof(char **)); 1375a56bb8a5SSatoshi Asami if (error) { 1376a56bb8a5SSatoshi Asami free(vpp, M_DEVBUF); 1377a56bb8a5SSatoshi Asami free(cpp, M_DEVBUF); 1378a56bb8a5SSatoshi Asami ccdunlock(cs); 1379a56bb8a5SSatoshi Asami return (error); 1380a56bb8a5SSatoshi Asami } 1381a56bb8a5SSatoshi Asami 1382a56bb8a5SSatoshi Asami #ifdef DEBUG 1383a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 1384a56bb8a5SSatoshi Asami for (i = 0; i < ccio->ccio_ndisks; ++i) 13856a5a4d0aSAndrew Gallatin printf("ccdioctl: component %d: %p\n", 1386a56bb8a5SSatoshi Asami i, cpp[i]); 1387a56bb8a5SSatoshi Asami #endif 1388a56bb8a5SSatoshi Asami 1389a56bb8a5SSatoshi Asami for (i = 0; i < ccio->ccio_ndisks; ++i) { 1390a56bb8a5SSatoshi Asami #ifdef DEBUG 1391a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 1392a56bb8a5SSatoshi Asami printf("ccdioctl: lookedup = %d\n", lookedup); 1393a56bb8a5SSatoshi Asami #endif 1394b40ce416SJulian Elischer if ((error = ccdlookup(cpp[i], td, &vpp[i])) != 0) { 1395a56bb8a5SSatoshi Asami for (j = 0; j < lookedup; ++j) 1396a56bb8a5SSatoshi Asami (void)vn_close(vpp[j], FREAD|FWRITE, 1397a854ed98SJohn Baldwin td->td_ucred, td); 1398a56bb8a5SSatoshi Asami free(vpp, M_DEVBUF); 1399a56bb8a5SSatoshi Asami free(cpp, M_DEVBUF); 1400a56bb8a5SSatoshi Asami ccdunlock(cs); 1401a56bb8a5SSatoshi Asami return (error); 1402a56bb8a5SSatoshi Asami } 1403a56bb8a5SSatoshi Asami ++lookedup; 1404a56bb8a5SSatoshi Asami } 140501706d20SPoul-Henning Kamp cs->sc_vpp = vpp; 140601706d20SPoul-Henning Kamp cs->sc_nccdisks = ccio->ccio_ndisks; 1407a56bb8a5SSatoshi Asami 1408a56bb8a5SSatoshi Asami /* 1409a56bb8a5SSatoshi Asami * Initialize the ccd. Fills in the softc for us. 1410a56bb8a5SSatoshi Asami */ 1411b40ce416SJulian Elischer if ((error = ccdinit(cs, cpp, td)) != 0) { 1412a56bb8a5SSatoshi Asami for (j = 0; j < lookedup; ++j) 1413ba88dfc7SJohn Baldwin (void)vn_close(vpp[j], FREAD|FWRITE, 1414a854ed98SJohn Baldwin td->td_ucred, td); 141501706d20SPoul-Henning Kamp /* 141601706d20SPoul-Henning Kamp * We can't ccddestroy() cs just yet, because nothing 141701706d20SPoul-Henning Kamp * prevents user-level app to do another ioctl() 141801706d20SPoul-Henning Kamp * without closing the device first, therefore 141901706d20SPoul-Henning Kamp * declare unit null and void and let ccdclose() 142001706d20SPoul-Henning Kamp * destroy it when it is safe to do so. 142101706d20SPoul-Henning Kamp */ 142201706d20SPoul-Henning Kamp cs->sc_flags &= (CCDF_WANTED | CCDF_LOCKED); 1423a56bb8a5SSatoshi Asami free(vpp, M_DEVBUF); 1424a56bb8a5SSatoshi Asami free(cpp, M_DEVBUF); 1425a56bb8a5SSatoshi Asami ccdunlock(cs); 1426a56bb8a5SSatoshi Asami return (error); 1427a56bb8a5SSatoshi Asami } 1428a56bb8a5SSatoshi Asami 1429a56bb8a5SSatoshi Asami /* 1430a56bb8a5SSatoshi Asami * The ccd has been successfully initialized, so 1431a56bb8a5SSatoshi Asami * we can place it into the array and read the disklabel. 1432a56bb8a5SSatoshi Asami */ 1433a56bb8a5SSatoshi Asami ccio->ccio_unit = unit; 1434a56bb8a5SSatoshi Asami ccio->ccio_size = cs->sc_size; 1435a56bb8a5SSatoshi Asami ccdgetdisklabel(dev); 1436a56bb8a5SSatoshi Asami 1437a56bb8a5SSatoshi Asami ccdunlock(cs); 1438a56bb8a5SSatoshi Asami 1439a56bb8a5SSatoshi Asami break; 1440a56bb8a5SSatoshi Asami 1441a56bb8a5SSatoshi Asami case CCDIOCCLR: 144201706d20SPoul-Henning Kamp if (!IS_INITED(cs)) 1443a56bb8a5SSatoshi Asami return (ENXIO); 1444a56bb8a5SSatoshi Asami 1445a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1446a56bb8a5SSatoshi Asami return (EBADF); 1447a56bb8a5SSatoshi Asami 1448b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 1449a56bb8a5SSatoshi Asami return (error); 1450a56bb8a5SSatoshi Asami 1451af8862e4SPoul-Henning Kamp /* Don't unconfigure if any other partitions are open */ 1452d8594dfbSSatoshi Asami part = ccdpart(dev); 1453a56bb8a5SSatoshi Asami pmask = (1 << part); 1454af8862e4SPoul-Henning Kamp if ((cs->sc_openmask & ~pmask)) { 1455a56bb8a5SSatoshi Asami ccdunlock(cs); 1456a56bb8a5SSatoshi Asami return (EBUSY); 1457a56bb8a5SSatoshi Asami } 1458a56bb8a5SSatoshi Asami 145901706d20SPoul-Henning Kamp /* Declare unit null and void (reset all flags) */ 146001706d20SPoul-Henning Kamp cs->sc_flags &= (CCDF_WANTED | CCDF_LOCKED); 1461a56bb8a5SSatoshi Asami 1462a56bb8a5SSatoshi Asami /* Close the components and free their pathnames. */ 1463a56bb8a5SSatoshi Asami for (i = 0; i < cs->sc_nccdisks; ++i) { 1464a56bb8a5SSatoshi Asami /* 1465a56bb8a5SSatoshi Asami * XXX: this close could potentially fail and 1466a56bb8a5SSatoshi Asami * cause Bad Things. Maybe we need to force 1467a56bb8a5SSatoshi Asami * the close to happen? 1468a56bb8a5SSatoshi Asami */ 1469a56bb8a5SSatoshi Asami #ifdef DEBUG 1470a56bb8a5SSatoshi Asami if (ccddebug & CCDB_VNODE) 1471a56bb8a5SSatoshi Asami vprint("CCDIOCCLR: vnode info", 1472a56bb8a5SSatoshi Asami cs->sc_cinfo[i].ci_vp); 1473a56bb8a5SSatoshi Asami #endif 1474a56bb8a5SSatoshi Asami (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1475a854ed98SJohn Baldwin td->td_ucred, td); 1476a56bb8a5SSatoshi Asami free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1477a56bb8a5SSatoshi Asami } 1478a56bb8a5SSatoshi Asami 1479a56bb8a5SSatoshi Asami /* Free interleave index. */ 1480a56bb8a5SSatoshi Asami for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1481a56bb8a5SSatoshi Asami free(cs->sc_itable[i].ii_index, M_DEVBUF); 1482a56bb8a5SSatoshi Asami 1483a56bb8a5SSatoshi Asami /* Free component info and interleave table. */ 1484a56bb8a5SSatoshi Asami free(cs->sc_cinfo, M_DEVBUF); 1485a56bb8a5SSatoshi Asami free(cs->sc_itable, M_DEVBUF); 148601706d20SPoul-Henning Kamp free(cs->sc_vpp, M_DEVBUF); 1487a56bb8a5SSatoshi Asami 148801706d20SPoul-Henning Kamp /* And remove the devstat entry. */ 148921c3b31eSMatt Jacob devstat_remove_entry(&cs->device_stats); 149021c3b31eSMatt Jacob 1491a56bb8a5SSatoshi Asami /* This must be atomic. */ 1492a56bb8a5SSatoshi Asami s = splhigh(); 1493a56bb8a5SSatoshi Asami ccdunlock(cs); 1494a56bb8a5SSatoshi Asami splx(s); 1495a56bb8a5SSatoshi Asami 1496a56bb8a5SSatoshi Asami break; 1497a56bb8a5SSatoshi Asami 149801706d20SPoul-Henning Kamp case CCDCONFINFO: 149901706d20SPoul-Henning Kamp { 150001706d20SPoul-Henning Kamp int ninit = 0; 150101706d20SPoul-Henning Kamp struct ccdconf *conf = (struct ccdconf *)data; 150201706d20SPoul-Henning Kamp struct ccd_s *tmpcs; 150301706d20SPoul-Henning Kamp struct ccd_s *ubuf = conf->buffer; 150401706d20SPoul-Henning Kamp 150501706d20SPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 150601706d20SPoul-Henning Kamp LIST_FOREACH(tmpcs, &ccd_softc_list, list) 150701706d20SPoul-Henning Kamp if (IS_INITED(tmpcs)) 150801706d20SPoul-Henning Kamp ninit++; 150901706d20SPoul-Henning Kamp 151001706d20SPoul-Henning Kamp if (conf->size == 0) { 151101706d20SPoul-Henning Kamp conf->size = sizeof(struct ccd_s) * ninit; 151201706d20SPoul-Henning Kamp break; 151301706d20SPoul-Henning Kamp } else if ((conf->size / sizeof(struct ccd_s) != ninit) || 151401706d20SPoul-Henning Kamp (conf->size % sizeof(struct ccd_s) != 0)) { 151501706d20SPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 151601706d20SPoul-Henning Kamp return (EINVAL); 151701706d20SPoul-Henning Kamp } 151801706d20SPoul-Henning Kamp 151901706d20SPoul-Henning Kamp ubuf += ninit; 152001706d20SPoul-Henning Kamp LIST_FOREACH(tmpcs, &ccd_softc_list, list) { 152101706d20SPoul-Henning Kamp if (!IS_INITED(tmpcs)) 152201706d20SPoul-Henning Kamp continue; 152301706d20SPoul-Henning Kamp error = copyout(tmpcs, --ubuf, 152401706d20SPoul-Henning Kamp sizeof(struct ccd_s)); 152501706d20SPoul-Henning Kamp if (error != 0) 152601706d20SPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 152701706d20SPoul-Henning Kamp return (error); 152801706d20SPoul-Henning Kamp } 152901706d20SPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 153001706d20SPoul-Henning Kamp } 153101706d20SPoul-Henning Kamp break; 153201706d20SPoul-Henning Kamp 153301706d20SPoul-Henning Kamp case CCDCPPINFO: 153401706d20SPoul-Henning Kamp if (!IS_INITED(cs)) 153501706d20SPoul-Henning Kamp return (ENXIO); 153601706d20SPoul-Henning Kamp 153701706d20SPoul-Henning Kamp { 153801706d20SPoul-Henning Kamp int len = 0; 153901706d20SPoul-Henning Kamp struct ccdcpps *cpps = (struct ccdcpps *)data; 154001706d20SPoul-Henning Kamp char *ubuf = cpps->buffer; 154101706d20SPoul-Henning Kamp 154201706d20SPoul-Henning Kamp 154301706d20SPoul-Henning Kamp for (i = 0; i < cs->sc_nccdisks; ++i) 154401706d20SPoul-Henning Kamp len += cs->sc_cinfo[i].ci_pathlen; 154501706d20SPoul-Henning Kamp 154601706d20SPoul-Henning Kamp if (cpps->size == 0) { 154701706d20SPoul-Henning Kamp cpps->size = len; 154801706d20SPoul-Henning Kamp break; 1549ddbf51afSPoul-Henning Kamp } else if (cpps->size < len) { 1550ddbf51afSPoul-Henning Kamp return (ENOMEM); 155101706d20SPoul-Henning Kamp } 155201706d20SPoul-Henning Kamp 155301706d20SPoul-Henning Kamp for (i = 0; i < cs->sc_nccdisks; ++i) { 155401706d20SPoul-Henning Kamp len = cs->sc_cinfo[i].ci_pathlen; 155501706d20SPoul-Henning Kamp error = copyout(cs->sc_cinfo[i].ci_path, ubuf, 155601706d20SPoul-Henning Kamp len); 155701706d20SPoul-Henning Kamp if (error != 0) 155801706d20SPoul-Henning Kamp return (error); 155901706d20SPoul-Henning Kamp ubuf += len; 156001706d20SPoul-Henning Kamp } 1561ddbf51afSPoul-Henning Kamp return(copyout("", ubuf, 1)); 156201706d20SPoul-Henning Kamp } 156301706d20SPoul-Henning Kamp break; 156401706d20SPoul-Henning Kamp 1565a56bb8a5SSatoshi Asami case DIOCGDINFO: 156601706d20SPoul-Henning Kamp if (!IS_INITED(cs)) 1567a56bb8a5SSatoshi Asami return (ENXIO); 1568a56bb8a5SSatoshi Asami 15696cc5a722SPoul-Henning Kamp *(struct disklabel *)data = cs->sc_label; 1570a56bb8a5SSatoshi Asami break; 1571a56bb8a5SSatoshi Asami 1572a56bb8a5SSatoshi Asami case DIOCWDINFO: 1573a56bb8a5SSatoshi Asami case DIOCSDINFO: 157401706d20SPoul-Henning Kamp if (!IS_INITED(cs)) 1575a56bb8a5SSatoshi Asami return (ENXIO); 1576a56bb8a5SSatoshi Asami 1577a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1578a56bb8a5SSatoshi Asami return (EBADF); 1579a56bb8a5SSatoshi Asami 1580b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 1581a56bb8a5SSatoshi Asami return (error); 1582a56bb8a5SSatoshi Asami 1583a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_LABELLING; 1584a56bb8a5SSatoshi Asami 15856cc5a722SPoul-Henning Kamp error = setdisklabel(&cs->sc_label, 1586d8594dfbSSatoshi Asami (struct disklabel *)data, 0); 1587a56bb8a5SSatoshi Asami if (error == 0) { 1588a56bb8a5SSatoshi Asami if (cmd == DIOCWDINFO) 1589e2a13e8cSSatoshi Asami error = writedisklabel(CCDLABELDEV(dev), 159049ff4debSPoul-Henning Kamp &cs->sc_label); 1591a56bb8a5SSatoshi Asami } 1592a56bb8a5SSatoshi Asami 1593a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_LABELLING; 1594a56bb8a5SSatoshi Asami 1595a56bb8a5SSatoshi Asami ccdunlock(cs); 1596a56bb8a5SSatoshi Asami 1597a56bb8a5SSatoshi Asami if (error) 1598a56bb8a5SSatoshi Asami return (error); 1599a56bb8a5SSatoshi Asami break; 1600a56bb8a5SSatoshi Asami 1601a56bb8a5SSatoshi Asami case DIOCWLABEL: 160201706d20SPoul-Henning Kamp if (!IS_INITED(cs)) 1603a56bb8a5SSatoshi Asami return (ENXIO); 1604a56bb8a5SSatoshi Asami 1605a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1606a56bb8a5SSatoshi Asami return (EBADF); 1607a56bb8a5SSatoshi Asami if (*(int *)data != 0) 1608a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_WLABEL; 1609a56bb8a5SSatoshi Asami else 1610a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_WLABEL; 1611a56bb8a5SSatoshi Asami break; 1612a56bb8a5SSatoshi Asami 1613a56bb8a5SSatoshi Asami default: 1614a56bb8a5SSatoshi Asami return (ENOTTY); 1615a56bb8a5SSatoshi Asami } 1616a56bb8a5SSatoshi Asami 1617a56bb8a5SSatoshi Asami return (0); 1618a56bb8a5SSatoshi Asami } 1619a56bb8a5SSatoshi Asami 1620e2738b4fSPoul-Henning Kamp static int 162101706d20SPoul-Henning Kamp ccdsize(dev_t dev) 1622a56bb8a5SSatoshi Asami { 162301706d20SPoul-Henning Kamp struct ccd_s *cs; 1624a56bb8a5SSatoshi Asami int part, size; 1625a56bb8a5SSatoshi Asami 1626ddbf51afSPoul-Henning Kamp if (dev->si_drv1 == dev) 1627ddbf51afSPoul-Henning Kamp return (-1); 1628ddbf51afSPoul-Henning Kamp 1629b40ce416SJulian Elischer if (ccdopen(dev, 0, S_IFCHR, curthread)) 1630a56bb8a5SSatoshi Asami return (-1); 1631a56bb8a5SSatoshi Asami 163201706d20SPoul-Henning Kamp cs = ccdfind(ccdunit(dev)); 1633d8594dfbSSatoshi Asami part = ccdpart(dev); 1634a56bb8a5SSatoshi Asami 163501706d20SPoul-Henning Kamp if (!IS_INITED(cs)) 1636a56bb8a5SSatoshi Asami return (-1); 1637a56bb8a5SSatoshi Asami 16386cc5a722SPoul-Henning Kamp if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP) 1639a56bb8a5SSatoshi Asami size = -1; 1640a56bb8a5SSatoshi Asami else 16416cc5a722SPoul-Henning Kamp size = cs->sc_label.d_partitions[part].p_size; 1642a56bb8a5SSatoshi Asami 1643b40ce416SJulian Elischer if (ccdclose(dev, 0, S_IFCHR, curthread)) 1644a56bb8a5SSatoshi Asami return (-1); 1645a56bb8a5SSatoshi Asami 1646a56bb8a5SSatoshi Asami return (size); 1647a56bb8a5SSatoshi Asami } 1648a56bb8a5SSatoshi Asami 1649a56bb8a5SSatoshi Asami /* 1650a56bb8a5SSatoshi Asami * Lookup the provided name in the filesystem. If the file exists, 1651a56bb8a5SSatoshi Asami * is a valid block device, and isn't being used by anyone else, 1652a56bb8a5SSatoshi Asami * set *vpp to the file's vnode. 1653a56bb8a5SSatoshi Asami */ 1654a56bb8a5SSatoshi Asami static int 1655b40ce416SJulian Elischer ccdlookup(char *path, struct thread *td, struct vnode **vpp) 1656a56bb8a5SSatoshi Asami { 1657a56bb8a5SSatoshi Asami struct nameidata nd; 1658a56bb8a5SSatoshi Asami struct vnode *vp; 1659e6796b67SKirk McKusick int error, flags; 1660a56bb8a5SSatoshi Asami 1661b40ce416SJulian Elischer NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, td); 1662e6796b67SKirk McKusick flags = FREAD | FWRITE; 1663e6796b67SKirk McKusick if ((error = vn_open(&nd, &flags, 0)) != 0) { 1664a56bb8a5SSatoshi Asami #ifdef DEBUG 166501706d20SPoul-Henning Kamp if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 1666a56bb8a5SSatoshi Asami printf("ccdlookup: vn_open error = %d\n", error); 1667a56bb8a5SSatoshi Asami #endif 1668a56bb8a5SSatoshi Asami return (error); 1669a56bb8a5SSatoshi Asami } 1670a56bb8a5SSatoshi Asami vp = nd.ni_vp; 1671a56bb8a5SSatoshi Asami 167237ab0e0dSJeff Roberson if (vrefcnt(vp) > 1) { 1673762e6b85SEivind Eklund error = EBUSY; 1674762e6b85SEivind Eklund goto bad; 1675a56bb8a5SSatoshi Asami } 1676a56bb8a5SSatoshi Asami 1677ba4ad1fcSPoul-Henning Kamp if (!vn_isdisk(vp, &error)) 1678762e6b85SEivind Eklund goto bad; 1679a56bb8a5SSatoshi Asami 1680a56bb8a5SSatoshi Asami #ifdef DEBUG 1681a56bb8a5SSatoshi Asami if (ccddebug & CCDB_VNODE) 1682a56bb8a5SSatoshi Asami vprint("ccdlookup: vnode info", vp); 1683a56bb8a5SSatoshi Asami #endif 1684a56bb8a5SSatoshi Asami 1685b40ce416SJulian Elischer VOP_UNLOCK(vp, 0, td); 1686762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 1687a56bb8a5SSatoshi Asami *vpp = vp; 1688a56bb8a5SSatoshi Asami return (0); 1689762e6b85SEivind Eklund bad: 1690b40ce416SJulian Elischer VOP_UNLOCK(vp, 0, td); 1691762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 1692762e6b85SEivind Eklund /* vn_close does vrele() for vp */ 1693a854ed98SJohn Baldwin (void)vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 1694762e6b85SEivind Eklund return (error); 1695a56bb8a5SSatoshi Asami } 1696a56bb8a5SSatoshi Asami 1697a56bb8a5SSatoshi Asami /* 1698a56bb8a5SSatoshi Asami * Read the disklabel from the ccd. If one is not present, fake one 1699a56bb8a5SSatoshi Asami * up. 1700a56bb8a5SSatoshi Asami */ 1701a56bb8a5SSatoshi Asami static void 170201706d20SPoul-Henning Kamp ccdgetdisklabel(dev_t dev) 1703a56bb8a5SSatoshi Asami { 1704a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 170501706d20SPoul-Henning Kamp struct ccd_s *cs = ccdfind(unit); 1706a56bb8a5SSatoshi Asami char *errstring; 17076cc5a722SPoul-Henning Kamp struct disklabel *lp = &cs->sc_label; 1708a56bb8a5SSatoshi Asami struct ccdgeom *ccg = &cs->sc_geom; 1709a56bb8a5SSatoshi Asami 1710a56bb8a5SSatoshi Asami bzero(lp, sizeof(*lp)); 1711a56bb8a5SSatoshi Asami 1712a56bb8a5SSatoshi Asami lp->d_secperunit = cs->sc_size; 1713a56bb8a5SSatoshi Asami lp->d_secsize = ccg->ccg_secsize; 1714a56bb8a5SSatoshi Asami lp->d_nsectors = ccg->ccg_nsectors; 1715a56bb8a5SSatoshi Asami lp->d_ntracks = ccg->ccg_ntracks; 1716a56bb8a5SSatoshi Asami lp->d_ncylinders = ccg->ccg_ncylinders; 1717a56bb8a5SSatoshi Asami lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1718a56bb8a5SSatoshi Asami 1719a56bb8a5SSatoshi Asami strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1720a56bb8a5SSatoshi Asami lp->d_type = DTYPE_CCD; 1721a56bb8a5SSatoshi Asami strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1722a56bb8a5SSatoshi Asami lp->d_rpm = 3600; 1723a56bb8a5SSatoshi Asami lp->d_interleave = 1; 1724a56bb8a5SSatoshi Asami lp->d_flags = 0; 1725a56bb8a5SSatoshi Asami 1726a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_offset = 0; 1727a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1728a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1729a56bb8a5SSatoshi Asami lp->d_npartitions = RAW_PART + 1; 1730a56bb8a5SSatoshi Asami 1731d8594dfbSSatoshi Asami lp->d_bbsize = BBSIZE; /* XXX */ 173277068a7fSPoul-Henning Kamp lp->d_sbsize = 0; 1733d8594dfbSSatoshi Asami 1734a56bb8a5SSatoshi Asami lp->d_magic = DISKMAGIC; 1735a56bb8a5SSatoshi Asami lp->d_magic2 = DISKMAGIC; 17366cc5a722SPoul-Henning Kamp lp->d_checksum = dkcksum(&cs->sc_label); 1737a56bb8a5SSatoshi Asami 1738a56bb8a5SSatoshi Asami /* 1739a56bb8a5SSatoshi Asami * Call the generic disklabel extraction routine. 1740a56bb8a5SSatoshi Asami */ 174149ff4debSPoul-Henning Kamp errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label); 174249ff4debSPoul-Henning Kamp if (errstring != NULL) 1743a56bb8a5SSatoshi Asami ccdmakedisklabel(cs); 1744a56bb8a5SSatoshi Asami 1745a56bb8a5SSatoshi Asami #ifdef DEBUG 1746a56bb8a5SSatoshi Asami /* It's actually extremely common to have unlabeled ccds. */ 1747a56bb8a5SSatoshi Asami if (ccddebug & CCDB_LABEL) 1748a56bb8a5SSatoshi Asami if (errstring != NULL) 1749a56bb8a5SSatoshi Asami printf("ccd%d: %s\n", unit, errstring); 1750a56bb8a5SSatoshi Asami #endif 1751a56bb8a5SSatoshi Asami } 1752a56bb8a5SSatoshi Asami 1753a56bb8a5SSatoshi Asami /* 1754a56bb8a5SSatoshi Asami * Take care of things one might want to take care of in the event 1755a56bb8a5SSatoshi Asami * that a disklabel isn't present. 1756a56bb8a5SSatoshi Asami */ 1757a56bb8a5SSatoshi Asami static void 175801706d20SPoul-Henning Kamp ccdmakedisklabel(struct ccd_s *cs) 1759a56bb8a5SSatoshi Asami { 17606cc5a722SPoul-Henning Kamp struct disklabel *lp = &cs->sc_label; 1761a56bb8a5SSatoshi Asami 1762a56bb8a5SSatoshi Asami /* 1763a56bb8a5SSatoshi Asami * For historical reasons, if there's no disklabel present 1764a56bb8a5SSatoshi Asami * the raw partition must be marked FS_BSDFFS. 1765a56bb8a5SSatoshi Asami */ 1766a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1767a56bb8a5SSatoshi Asami 1768a56bb8a5SSatoshi Asami strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1769a56bb8a5SSatoshi Asami } 1770a56bb8a5SSatoshi Asami 1771a56bb8a5SSatoshi Asami /* 1772a56bb8a5SSatoshi Asami * Wait interruptibly for an exclusive lock. 1773a56bb8a5SSatoshi Asami * 1774a56bb8a5SSatoshi Asami * XXX 1775a56bb8a5SSatoshi Asami * Several drivers do this; it should be abstracted and made MP-safe. 1776a56bb8a5SSatoshi Asami */ 1777a56bb8a5SSatoshi Asami static int 177801706d20SPoul-Henning Kamp ccdlock(struct ccd_s *cs) 1779a56bb8a5SSatoshi Asami { 1780a56bb8a5SSatoshi Asami int error; 1781a56bb8a5SSatoshi Asami 1782a56bb8a5SSatoshi Asami while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1783a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_WANTED; 1784a56bb8a5SSatoshi Asami if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1785a56bb8a5SSatoshi Asami return (error); 1786a56bb8a5SSatoshi Asami } 1787a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_LOCKED; 1788a56bb8a5SSatoshi Asami return (0); 1789a56bb8a5SSatoshi Asami } 1790a56bb8a5SSatoshi Asami 1791a56bb8a5SSatoshi Asami /* 1792a56bb8a5SSatoshi Asami * Unlock and wake up any waiters. 1793a56bb8a5SSatoshi Asami */ 1794a56bb8a5SSatoshi Asami static void 179501706d20SPoul-Henning Kamp ccdunlock(struct ccd_s *cs) 1796a56bb8a5SSatoshi Asami { 1797a56bb8a5SSatoshi Asami 1798a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_LOCKED; 1799a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_WANTED) != 0) { 1800a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_WANTED; 1801a56bb8a5SSatoshi Asami wakeup(cs); 1802a56bb8a5SSatoshi Asami } 1803a56bb8a5SSatoshi Asami } 1804a56bb8a5SSatoshi Asami 1805a56bb8a5SSatoshi Asami #ifdef DEBUG 1806a56bb8a5SSatoshi Asami static void 180701706d20SPoul-Henning Kamp printiinfo(struct ccdiinfo *ii) 1808a56bb8a5SSatoshi Asami { 18091464240eSMatthew Dillon int ix, i; 1810a56bb8a5SSatoshi Asami 1811a56bb8a5SSatoshi Asami for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1812ff8cc2ebSBruce Evans printf(" itab[%d]: #dk %d sblk %lld soff %lld", 1813ff8cc2ebSBruce Evans ix, ii->ii_ndisk, (long long)ii->ii_startblk, 1814ff8cc2ebSBruce Evans (long long)ii->ii_startoff); 1815a56bb8a5SSatoshi Asami for (i = 0; i < ii->ii_ndisk; i++) 1816a56bb8a5SSatoshi Asami printf(" %d", ii->ii_index[i]); 1817a56bb8a5SSatoshi Asami printf("\n"); 1818a56bb8a5SSatoshi Asami } 1819a56bb8a5SSatoshi Asami } 1820a56bb8a5SSatoshi Asami #endif 1821