1c3aac50fSPeter Wemm /* $FreeBSD$ */ 2aa8bdaecSSatoshi Asami 3a56bb8a5SSatoshi Asami /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */ 4a56bb8a5SSatoshi Asami 5a56bb8a5SSatoshi Asami /* 6a56bb8a5SSatoshi Asami * Copyright (c) 1995 Jason R. Thorpe. 7a56bb8a5SSatoshi Asami * All rights reserved. 8a56bb8a5SSatoshi Asami * 9a56bb8a5SSatoshi Asami * Redistribution and use in source and binary forms, with or without 10a56bb8a5SSatoshi Asami * modification, are permitted provided that the following conditions 11a56bb8a5SSatoshi Asami * are met: 12a56bb8a5SSatoshi Asami * 1. Redistributions of source code must retain the above copyright 13a56bb8a5SSatoshi Asami * notice, this list of conditions and the following disclaimer. 14a56bb8a5SSatoshi Asami * 2. Redistributions in binary form must reproduce the above copyright 15a56bb8a5SSatoshi Asami * notice, this list of conditions and the following disclaimer in the 16a56bb8a5SSatoshi Asami * documentation and/or other materials provided with the distribution. 17a56bb8a5SSatoshi Asami * 3. All advertising materials mentioning features or use of this software 18a56bb8a5SSatoshi Asami * must display the following acknowledgement: 19a56bb8a5SSatoshi Asami * This product includes software developed for the NetBSD Project 20a56bb8a5SSatoshi Asami * by Jason R. Thorpe. 21a56bb8a5SSatoshi Asami * 4. The name of the author may not be used to endorse or promote products 22a56bb8a5SSatoshi Asami * derived from this software without specific prior written permission. 23a56bb8a5SSatoshi Asami * 24a56bb8a5SSatoshi Asami * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25a56bb8a5SSatoshi Asami * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26a56bb8a5SSatoshi Asami * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27a56bb8a5SSatoshi Asami * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28a56bb8a5SSatoshi Asami * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29a56bb8a5SSatoshi Asami * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30a56bb8a5SSatoshi Asami * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31a56bb8a5SSatoshi Asami * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32a56bb8a5SSatoshi Asami * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33a56bb8a5SSatoshi Asami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34a56bb8a5SSatoshi Asami * SUCH DAMAGE. 35a56bb8a5SSatoshi Asami */ 36a56bb8a5SSatoshi Asami 37a56bb8a5SSatoshi Asami /* 38a56bb8a5SSatoshi Asami * Copyright (c) 1988 University of Utah. 39a56bb8a5SSatoshi Asami * Copyright (c) 1990, 1993 40a56bb8a5SSatoshi Asami * The Regents of the University of California. All rights reserved. 41a56bb8a5SSatoshi Asami * 42a56bb8a5SSatoshi Asami * This code is derived from software contributed to Berkeley by 43a56bb8a5SSatoshi Asami * the Systems Programming Group of the University of Utah Computer 44a56bb8a5SSatoshi Asami * Science Department. 45a56bb8a5SSatoshi Asami * 46a56bb8a5SSatoshi Asami * Redistribution and use in source and binary forms, with or without 47a56bb8a5SSatoshi Asami * modification, are permitted provided that the following conditions 48a56bb8a5SSatoshi Asami * are met: 49a56bb8a5SSatoshi Asami * 1. Redistributions of source code must retain the above copyright 50a56bb8a5SSatoshi Asami * notice, this list of conditions and the following disclaimer. 51a56bb8a5SSatoshi Asami * 2. Redistributions in binary form must reproduce the above copyright 52a56bb8a5SSatoshi Asami * notice, this list of conditions and the following disclaimer in the 53a56bb8a5SSatoshi Asami * documentation and/or other materials provided with the distribution. 54a56bb8a5SSatoshi Asami * 3. All advertising materials mentioning features or use of this software 55a56bb8a5SSatoshi Asami * must display the following acknowledgement: 56a56bb8a5SSatoshi Asami * This product includes software developed by the University of 57a56bb8a5SSatoshi Asami * California, Berkeley and its contributors. 58a56bb8a5SSatoshi Asami * 4. Neither the name of the University nor the names of its contributors 59a56bb8a5SSatoshi Asami * may be used to endorse or promote products derived from this software 60a56bb8a5SSatoshi Asami * without specific prior written permission. 61a56bb8a5SSatoshi Asami * 62a56bb8a5SSatoshi Asami * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63a56bb8a5SSatoshi Asami * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64a56bb8a5SSatoshi Asami * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65a56bb8a5SSatoshi Asami * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66a56bb8a5SSatoshi Asami * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67a56bb8a5SSatoshi Asami * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68a56bb8a5SSatoshi Asami * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69a56bb8a5SSatoshi Asami * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70a56bb8a5SSatoshi Asami * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71a56bb8a5SSatoshi Asami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72a56bb8a5SSatoshi Asami * SUCH DAMAGE. 73a56bb8a5SSatoshi Asami * 74a56bb8a5SSatoshi Asami * from: Utah $Hdr: cd.c 1.6 90/11/28$ 75a56bb8a5SSatoshi Asami * 76a56bb8a5SSatoshi Asami * @(#)cd.c 8.2 (Berkeley) 11/16/93 77a56bb8a5SSatoshi Asami */ 78a56bb8a5SSatoshi Asami 79a56bb8a5SSatoshi Asami /* 80a56bb8a5SSatoshi Asami * "Concatenated" disk driver. 81a56bb8a5SSatoshi Asami * 82a56bb8a5SSatoshi Asami * Dynamic configuration and disklabel support by: 83a56bb8a5SSatoshi Asami * Jason R. Thorpe <thorpej@nas.nasa.gov> 84a56bb8a5SSatoshi Asami * Numerical Aerodynamic Simulation Facility 85a56bb8a5SSatoshi Asami * Mail Stop 258-6 86a56bb8a5SSatoshi Asami * NASA Ames Research Center 87a56bb8a5SSatoshi Asami * Moffett Field, CA 94035 88a56bb8a5SSatoshi Asami */ 89a56bb8a5SSatoshi Asami 90d8594dfbSSatoshi Asami #include "ccd.h" 91d8594dfbSSatoshi Asami 92a56bb8a5SSatoshi Asami #include <sys/param.h> 93a56bb8a5SSatoshi Asami #include <sys/systm.h> 94e2a13e8cSSatoshi Asami #include <sys/kernel.h> 95b7b98418SPeter Wemm #include <sys/module.h> 96a56bb8a5SSatoshi Asami #include <sys/proc.h> 979626b608SPoul-Henning Kamp #include <sys/bio.h> 98a56bb8a5SSatoshi Asami #include <sys/malloc.h> 99a56bb8a5SSatoshi Asami #include <sys/namei.h> 100a56bb8a5SSatoshi Asami #include <sys/conf.h> 101a56bb8a5SSatoshi Asami #include <sys/stat.h> 102e2738b4fSPoul-Henning Kamp #include <sys/sysctl.h> 103a56bb8a5SSatoshi Asami #include <sys/disklabel.h> 104d8594dfbSSatoshi Asami #include <ufs/ffs/fs.h> 105b2dfb1f9SJustin T. Gibbs #include <sys/devicestat.h> 106a56bb8a5SSatoshi Asami #include <sys/fcntl.h> 107a56bb8a5SSatoshi Asami #include <sys/vnode.h> 108a56bb8a5SSatoshi Asami 109d8594dfbSSatoshi Asami #include <sys/ccdvar.h> 110a56bb8a5SSatoshi Asami 111762e6b85SEivind Eklund 112a56bb8a5SSatoshi Asami #if defined(CCDDEBUG) && !defined(DEBUG) 113a56bb8a5SSatoshi Asami #define DEBUG 114a56bb8a5SSatoshi Asami #endif 115a56bb8a5SSatoshi Asami 116a56bb8a5SSatoshi Asami #ifdef DEBUG 117a56bb8a5SSatoshi Asami #define CCDB_FOLLOW 0x01 118a56bb8a5SSatoshi Asami #define CCDB_INIT 0x02 119a56bb8a5SSatoshi Asami #define CCDB_IO 0x04 120a56bb8a5SSatoshi Asami #define CCDB_LABEL 0x08 121a56bb8a5SSatoshi Asami #define CCDB_VNODE 0x10 122e2738b4fSPoul-Henning Kamp static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | 123e2738b4fSPoul-Henning Kamp CCDB_VNODE; 124e2738b4fSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, ""); 125d8594dfbSSatoshi Asami #undef DEBUG 126a56bb8a5SSatoshi Asami #endif 127a56bb8a5SSatoshi Asami 128d8594dfbSSatoshi Asami #define ccdunit(x) dkunit(x) 129d8594dfbSSatoshi Asami #define ccdpart(x) dkpart(x) 130a56bb8a5SSatoshi Asami 131e7322872SSatoshi Asami /* 132e7322872SSatoshi Asami This is how mirroring works (only writes are special): 133e7322872SSatoshi Asami 134e7322872SSatoshi Asami When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s 135e7322872SSatoshi Asami linked together by the cb_mirror field. "cb_pflags & 136e7322872SSatoshi Asami CCDPF_MIRROR_DONE" is set to 0 on both of them. 137e7322872SSatoshi Asami 138e7322872SSatoshi Asami When a component returns to ccdiodone(), it checks if "cb_pflags & 139e7322872SSatoshi Asami CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's 140e7322872SSatoshi Asami flag and returns. If it is, it means its partner has already 141e7322872SSatoshi Asami returned, so it will go to the regular cleanup. 142e7322872SSatoshi Asami 143e7322872SSatoshi Asami */ 144e7322872SSatoshi Asami 145a56bb8a5SSatoshi Asami struct ccdbuf { 1469d7f7369SPoul-Henning Kamp struct bio cb_buf; /* new I/O buf */ 1479d7f7369SPoul-Henning Kamp struct bio *cb_obp; /* ptr. to original I/O buf */ 1481464240eSMatthew Dillon struct ccdbuf *cb_freenext; /* free list link */ 149a56bb8a5SSatoshi Asami int cb_unit; /* target unit */ 150a56bb8a5SSatoshi Asami int cb_comp; /* target component */ 151e7322872SSatoshi Asami int cb_pflags; /* mirror/parity status flag */ 152e7322872SSatoshi Asami struct ccdbuf *cb_mirror; /* mirror counterpart */ 153a56bb8a5SSatoshi Asami }; 154a56bb8a5SSatoshi Asami 155e7322872SSatoshi Asami /* bits in cb_pflags */ 156e7322872SSatoshi Asami #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ 157e7322872SSatoshi Asami 158a56bb8a5SSatoshi Asami #define CCDLABELDEV(dev) \ 159d8594dfbSSatoshi Asami (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART))) 160a56bb8a5SSatoshi Asami 161e2738b4fSPoul-Henning Kamp static d_open_t ccdopen; 162e2738b4fSPoul-Henning Kamp static d_close_t ccdclose; 163e2738b4fSPoul-Henning Kamp static d_strategy_t ccdstrategy; 164e2738b4fSPoul-Henning Kamp static d_ioctl_t ccdioctl; 165e2738b4fSPoul-Henning Kamp static d_dump_t ccddump; 166e2738b4fSPoul-Henning Kamp static d_psize_t ccdsize; 167d8594dfbSSatoshi Asami 1681464240eSMatthew Dillon #define NCCDFREEHIWAT 16 1691464240eSMatthew Dillon 170e2a13e8cSSatoshi Asami #define CDEV_MAJOR 74 171e2a13e8cSSatoshi Asami #define BDEV_MAJOR 21 172a56bb8a5SSatoshi Asami 173f7ea2f55SJulian Elischer static struct cdevsw ccd_cdevsw = { 1744e2f199eSPoul-Henning Kamp /* open */ ccdopen, 1754e2f199eSPoul-Henning Kamp /* close */ ccdclose, 1764e2f199eSPoul-Henning Kamp /* read */ physread, 1774e2f199eSPoul-Henning Kamp /* write */ physwrite, 1784e2f199eSPoul-Henning Kamp /* ioctl */ ccdioctl, 1794e2f199eSPoul-Henning Kamp /* poll */ nopoll, 1804e2f199eSPoul-Henning Kamp /* mmap */ nommap, 1814e2f199eSPoul-Henning Kamp /* strategy */ ccdstrategy, 1824e2f199eSPoul-Henning Kamp /* name */ "ccd", 1834e2f199eSPoul-Henning Kamp /* maj */ CDEV_MAJOR, 1844e2f199eSPoul-Henning Kamp /* dump */ ccddump, 1854e2f199eSPoul-Henning Kamp /* psize */ ccdsize, 1864e2f199eSPoul-Henning Kamp /* flags */ D_DISK, 1874e2f199eSPoul-Henning Kamp /* bmaj */ BDEV_MAJOR 1884e2f199eSPoul-Henning Kamp }; 189e2a13e8cSSatoshi Asami 190b7b98418SPeter Wemm /* called during module initialization */ 191b7b98418SPeter Wemm static void ccdattach __P((void)); 192b7b98418SPeter Wemm static int ccd_modevent __P((module_t, int, void *)); 193a56bb8a5SSatoshi Asami 194a56bb8a5SSatoshi Asami /* called by biodone() at interrupt time */ 1959d7f7369SPoul-Henning Kamp static void ccdiodone __P((struct bio *bp)); 196a56bb8a5SSatoshi Asami 1979d7f7369SPoul-Henning Kamp static void ccdstart __P((struct ccd_softc *, struct bio *)); 198a56bb8a5SSatoshi Asami static void ccdinterleave __P((struct ccd_softc *, int)); 1999d7f7369SPoul-Henning Kamp static void ccdintr __P((struct ccd_softc *, struct bio *)); 200a56bb8a5SSatoshi Asami static int ccdinit __P((struct ccddevice *, char **, struct proc *)); 201a56bb8a5SSatoshi Asami static int ccdlookup __P((char *, struct proc *p, struct vnode **)); 2023bc746beSSatoshi Asami static void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *, 2039d7f7369SPoul-Henning Kamp struct bio *, daddr_t, caddr_t, long)); 204a56bb8a5SSatoshi Asami static void ccdgetdisklabel __P((dev_t)); 205a56bb8a5SSatoshi Asami static void ccdmakedisklabel __P((struct ccd_softc *)); 206a56bb8a5SSatoshi Asami static int ccdlock __P((struct ccd_softc *)); 207a56bb8a5SSatoshi Asami static void ccdunlock __P((struct ccd_softc *)); 208a56bb8a5SSatoshi Asami 209a56bb8a5SSatoshi Asami #ifdef DEBUG 210a56bb8a5SSatoshi Asami static void printiinfo __P((struct ccdiinfo *)); 211a56bb8a5SSatoshi Asami #endif 212a56bb8a5SSatoshi Asami 213a56bb8a5SSatoshi Asami /* Non-private for the benefit of libkvm. */ 214a56bb8a5SSatoshi Asami struct ccd_softc *ccd_softc; 215a56bb8a5SSatoshi Asami struct ccddevice *ccddevs; 2161464240eSMatthew Dillon struct ccdbuf *ccdfreebufs; 2171464240eSMatthew Dillon static int numccdfreebufs; 218e2738b4fSPoul-Henning Kamp static int numccd = 0; 219a56bb8a5SSatoshi Asami 220a56bb8a5SSatoshi Asami /* 2211464240eSMatthew Dillon * getccdbuf() - Allocate and zero a ccd buffer. 2221464240eSMatthew Dillon * 2231464240eSMatthew Dillon * This routine is called at splbio(). 2241464240eSMatthew Dillon */ 2251464240eSMatthew Dillon 2261464240eSMatthew Dillon static __inline 2271464240eSMatthew Dillon struct ccdbuf * 2281464240eSMatthew Dillon getccdbuf(struct ccdbuf *cpy) 2291464240eSMatthew Dillon { 2301464240eSMatthew Dillon struct ccdbuf *cbp; 2311464240eSMatthew Dillon 2321464240eSMatthew Dillon /* 2331464240eSMatthew Dillon * Allocate from freelist or malloc as necessary 2341464240eSMatthew Dillon */ 2351464240eSMatthew Dillon if ((cbp = ccdfreebufs) != NULL) { 2361464240eSMatthew Dillon ccdfreebufs = cbp->cb_freenext; 2371464240eSMatthew Dillon --numccdfreebufs; 2381464240eSMatthew Dillon } else { 2391464240eSMatthew Dillon cbp = malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK); 2401464240eSMatthew Dillon } 2411464240eSMatthew Dillon 2421464240eSMatthew Dillon /* 2431464240eSMatthew Dillon * Used by mirroring code 2441464240eSMatthew Dillon */ 2451464240eSMatthew Dillon if (cpy) 2461464240eSMatthew Dillon bcopy(cpy, cbp, sizeof(struct ccdbuf)); 2471464240eSMatthew Dillon else 2481464240eSMatthew Dillon bzero(cbp, sizeof(struct ccdbuf)); 2491464240eSMatthew Dillon 2501464240eSMatthew Dillon /* 2519d7f7369SPoul-Henning Kamp * independant struct bio initialization 2521464240eSMatthew Dillon */ 2531464240eSMatthew Dillon 2541464240eSMatthew Dillon return(cbp); 2551464240eSMatthew Dillon } 2561464240eSMatthew Dillon 2571464240eSMatthew Dillon /* 2581441456fSGreg Lehey * putccdbuf() - Free a ccd buffer. 2591464240eSMatthew Dillon * 2601464240eSMatthew Dillon * This routine is called at splbio(). 2611464240eSMatthew Dillon */ 2621464240eSMatthew Dillon 2631464240eSMatthew Dillon static __inline 2641464240eSMatthew Dillon void 2651464240eSMatthew Dillon putccdbuf(struct ccdbuf *cbp) 2661464240eSMatthew Dillon { 26774427f90SMatthew Dillon 2681464240eSMatthew Dillon if (numccdfreebufs < NCCDFREEHIWAT) { 2691464240eSMatthew Dillon cbp->cb_freenext = ccdfreebufs; 2701464240eSMatthew Dillon ccdfreebufs = cbp; 2711464240eSMatthew Dillon ++numccdfreebufs; 2721464240eSMatthew Dillon } else { 2731464240eSMatthew Dillon free((caddr_t)cbp, M_DEVBUF); 2741464240eSMatthew Dillon } 2751464240eSMatthew Dillon } 2761464240eSMatthew Dillon 2771464240eSMatthew Dillon 2781464240eSMatthew Dillon /* 2790d88ef07SSatoshi Asami * Number of blocks to untouched in front of a component partition. 2800d88ef07SSatoshi Asami * This is to avoid violating its disklabel area when it starts at the 2810d88ef07SSatoshi Asami * beginning of the slice. 2820d88ef07SSatoshi Asami */ 2831af0e025SSatoshi Asami #if !defined(CCD_OFFSET) 2840d88ef07SSatoshi Asami #define CCD_OFFSET 16 2851af0e025SSatoshi Asami #endif 2860d88ef07SSatoshi Asami 2870d88ef07SSatoshi Asami /* 288a56bb8a5SSatoshi Asami * Called by main() during pseudo-device attachment. All we need 289e2a13e8cSSatoshi Asami * to do is allocate enough space for devices to be configured later, and 290e2a13e8cSSatoshi Asami * add devsw entries. 291a56bb8a5SSatoshi Asami */ 292e2738b4fSPoul-Henning Kamp static void 293b7b98418SPeter Wemm ccdattach() 294a56bb8a5SSatoshi Asami { 295a56bb8a5SSatoshi Asami int i; 296e2a13e8cSSatoshi Asami int num = NCCD; 297a56bb8a5SSatoshi Asami 298e2a13e8cSSatoshi Asami if (num > 1) 299e2a13e8cSSatoshi Asami printf("ccd0-%d: Concatenated disk drivers\n", num-1); 300d8594dfbSSatoshi Asami else 301e2a13e8cSSatoshi Asami printf("ccd0: Concatenated disk driver\n"); 302d8594dfbSSatoshi Asami 303a56bb8a5SSatoshi Asami ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), 304a56bb8a5SSatoshi Asami M_DEVBUF, M_NOWAIT); 305a56bb8a5SSatoshi Asami ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice), 306a56bb8a5SSatoshi Asami M_DEVBUF, M_NOWAIT); 307a56bb8a5SSatoshi Asami if ((ccd_softc == NULL) || (ccddevs == NULL)) { 308a56bb8a5SSatoshi Asami printf("WARNING: no memory for concatenated disks\n"); 309a56bb8a5SSatoshi Asami if (ccd_softc != NULL) 310a56bb8a5SSatoshi Asami free(ccd_softc, M_DEVBUF); 311a56bb8a5SSatoshi Asami if (ccddevs != NULL) 312a56bb8a5SSatoshi Asami free(ccddevs, M_DEVBUF); 313e2a13e8cSSatoshi Asami return; 314a56bb8a5SSatoshi Asami } 315a56bb8a5SSatoshi Asami numccd = num; 316a56bb8a5SSatoshi Asami bzero(ccd_softc, num * sizeof(struct ccd_softc)); 317a56bb8a5SSatoshi Asami bzero(ccddevs, num * sizeof(struct ccddevice)); 318a56bb8a5SSatoshi Asami 319d53dedeeSPoul-Henning Kamp cdevsw_add(&ccd_cdevsw); 320a56bb8a5SSatoshi Asami /* XXX: is this necessary? */ 321a56bb8a5SSatoshi Asami for (i = 0; i < numccd; ++i) 322a56bb8a5SSatoshi Asami ccddevs[i].ccd_dk = -1; 323b7b98418SPeter Wemm } 324d8594dfbSSatoshi Asami 325b7b98418SPeter Wemm static int 326b7b98418SPeter Wemm ccd_modevent(mod, type, data) 327b7b98418SPeter Wemm module_t mod; 328b7b98418SPeter Wemm int type; 329b7b98418SPeter Wemm void *data; 330b7b98418SPeter Wemm { 331b7b98418SPeter Wemm int error = 0; 332b7b98418SPeter Wemm 333b7b98418SPeter Wemm switch (type) { 334b7b98418SPeter Wemm case MOD_LOAD: 335b7b98418SPeter Wemm ccdattach(); 336b7b98418SPeter Wemm break; 337b7b98418SPeter Wemm 338b7b98418SPeter Wemm case MOD_UNLOAD: 339b7b98418SPeter Wemm printf("ccd0: Unload not supported!\n"); 340b7b98418SPeter Wemm error = EOPNOTSUPP; 341b7b98418SPeter Wemm break; 342b7b98418SPeter Wemm 343b7b98418SPeter Wemm default: /* MOD_SHUTDOWN etc */ 344b7b98418SPeter Wemm break; 345e2a13e8cSSatoshi Asami } 346b7b98418SPeter Wemm return (error); 347e2a13e8cSSatoshi Asami } 348b7b98418SPeter Wemm 349d53dedeeSPoul-Henning Kamp DEV_MODULE(ccd, ccd_modevent, NULL); 350a56bb8a5SSatoshi Asami 351a56bb8a5SSatoshi Asami static int 352a56bb8a5SSatoshi Asami ccdinit(ccd, cpaths, p) 353a56bb8a5SSatoshi Asami struct ccddevice *ccd; 354a56bb8a5SSatoshi Asami char **cpaths; 355a56bb8a5SSatoshi Asami struct proc *p; 356a56bb8a5SSatoshi Asami { 3571464240eSMatthew Dillon struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; 3581464240eSMatthew Dillon struct ccdcinfo *ci = NULL; /* XXX */ 3591464240eSMatthew Dillon size_t size; 3601464240eSMatthew Dillon int ix; 361a56bb8a5SSatoshi Asami struct vnode *vp; 362a56bb8a5SSatoshi Asami size_t minsize; 363a56bb8a5SSatoshi Asami int maxsecsize; 364a56bb8a5SSatoshi Asami struct partinfo dpart; 365a56bb8a5SSatoshi Asami struct ccdgeom *ccg = &cs->sc_geom; 366a56bb8a5SSatoshi Asami char tmppath[MAXPATHLEN]; 3671464240eSMatthew Dillon int error = 0; 368a56bb8a5SSatoshi Asami 369a56bb8a5SSatoshi Asami #ifdef DEBUG 370a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 371a56bb8a5SSatoshi Asami printf("ccdinit: unit %d\n", ccd->ccd_unit); 372a56bb8a5SSatoshi Asami #endif 373a56bb8a5SSatoshi Asami 374a56bb8a5SSatoshi Asami cs->sc_size = 0; 375a56bb8a5SSatoshi Asami cs->sc_ileave = ccd->ccd_interleave; 376a56bb8a5SSatoshi Asami cs->sc_nccdisks = ccd->ccd_ndev; 377a56bb8a5SSatoshi Asami 378a56bb8a5SSatoshi Asami /* Allocate space for the component info. */ 379a56bb8a5SSatoshi Asami cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), 380a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 381a56bb8a5SSatoshi Asami 382a56bb8a5SSatoshi Asami /* 383a56bb8a5SSatoshi Asami * Verify that each component piece exists and record 384a56bb8a5SSatoshi Asami * relevant information about it. 385a56bb8a5SSatoshi Asami */ 386a56bb8a5SSatoshi Asami maxsecsize = 0; 387a56bb8a5SSatoshi Asami minsize = 0; 388a56bb8a5SSatoshi Asami for (ix = 0; ix < cs->sc_nccdisks; ix++) { 389a56bb8a5SSatoshi Asami vp = ccd->ccd_vpp[ix]; 390a56bb8a5SSatoshi Asami ci = &cs->sc_cinfo[ix]; 391a56bb8a5SSatoshi Asami ci->ci_vp = vp; 392a56bb8a5SSatoshi Asami 393a56bb8a5SSatoshi Asami /* 394a56bb8a5SSatoshi Asami * Copy in the pathname of the component. 395a56bb8a5SSatoshi Asami */ 396a56bb8a5SSatoshi Asami bzero(tmppath, sizeof(tmppath)); /* sanity */ 397b4e36adfSMatthew Dillon if ((error = copyinstr(cpaths[ix], tmppath, 398b4e36adfSMatthew Dillon MAXPATHLEN, &ci->ci_pathlen)) != 0) { 399a56bb8a5SSatoshi Asami #ifdef DEBUG 400a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 401a56bb8a5SSatoshi Asami printf("ccd%d: can't copy path, error = %d\n", 402a56bb8a5SSatoshi Asami ccd->ccd_unit, error); 403a56bb8a5SSatoshi Asami #endif 4041464240eSMatthew Dillon goto fail; 405a56bb8a5SSatoshi Asami } 406a56bb8a5SSatoshi Asami ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); 407a56bb8a5SSatoshi Asami bcopy(tmppath, ci->ci_path, ci->ci_pathlen); 408a56bb8a5SSatoshi Asami 409684adedeSPoul-Henning Kamp ci->ci_dev = vn_todev(vp); 410a56bb8a5SSatoshi Asami 411a56bb8a5SSatoshi Asami /* 412a56bb8a5SSatoshi Asami * Get partition information for the component. 413a56bb8a5SSatoshi Asami */ 414b4e36adfSMatthew Dillon if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, 415b4e36adfSMatthew Dillon FREAD, p->p_ucred, p)) != 0) { 416a56bb8a5SSatoshi Asami #ifdef DEBUG 417a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 418a56bb8a5SSatoshi Asami printf("ccd%d: %s: ioctl failed, error = %d\n", 419a56bb8a5SSatoshi Asami ccd->ccd_unit, ci->ci_path, error); 420a56bb8a5SSatoshi Asami #endif 4211464240eSMatthew Dillon goto fail; 422a56bb8a5SSatoshi Asami } 423a56bb8a5SSatoshi Asami if (dpart.part->p_fstype == FS_BSDFFS) { 424a56bb8a5SSatoshi Asami maxsecsize = 425a56bb8a5SSatoshi Asami ((dpart.disklab->d_secsize > maxsecsize) ? 426a56bb8a5SSatoshi Asami dpart.disklab->d_secsize : maxsecsize); 4270d88ef07SSatoshi Asami size = dpart.part->p_size - CCD_OFFSET; 428a56bb8a5SSatoshi Asami } else { 429a56bb8a5SSatoshi Asami #ifdef DEBUG 430a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 431a56bb8a5SSatoshi Asami printf("ccd%d: %s: incorrect partition type\n", 432a56bb8a5SSatoshi Asami ccd->ccd_unit, ci->ci_path); 433a56bb8a5SSatoshi Asami #endif 4341464240eSMatthew Dillon error = EFTYPE; 4351464240eSMatthew Dillon goto fail; 436a56bb8a5SSatoshi Asami } 437a56bb8a5SSatoshi Asami 438a56bb8a5SSatoshi Asami /* 439a56bb8a5SSatoshi Asami * Calculate the size, truncating to an interleave 440a56bb8a5SSatoshi Asami * boundary if necessary. 441a56bb8a5SSatoshi Asami */ 442a56bb8a5SSatoshi Asami 443a56bb8a5SSatoshi Asami if (cs->sc_ileave > 1) 444a56bb8a5SSatoshi Asami size -= size % cs->sc_ileave; 445a56bb8a5SSatoshi Asami 446a56bb8a5SSatoshi Asami if (size == 0) { 447a56bb8a5SSatoshi Asami #ifdef DEBUG 448a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 449a56bb8a5SSatoshi Asami printf("ccd%d: %s: size == 0\n", 450a56bb8a5SSatoshi Asami ccd->ccd_unit, ci->ci_path); 451a56bb8a5SSatoshi Asami #endif 4521464240eSMatthew Dillon error = ENODEV; 4531464240eSMatthew Dillon goto fail; 454a56bb8a5SSatoshi Asami } 455a56bb8a5SSatoshi Asami 456a56bb8a5SSatoshi Asami if (minsize == 0 || size < minsize) 457a56bb8a5SSatoshi Asami minsize = size; 458a56bb8a5SSatoshi Asami ci->ci_size = size; 459a56bb8a5SSatoshi Asami cs->sc_size += size; 460a56bb8a5SSatoshi Asami } 461a56bb8a5SSatoshi Asami 462a56bb8a5SSatoshi Asami /* 463a56bb8a5SSatoshi Asami * Don't allow the interleave to be smaller than 464a56bb8a5SSatoshi Asami * the biggest component sector. 465a56bb8a5SSatoshi Asami */ 466a56bb8a5SSatoshi Asami if ((cs->sc_ileave > 0) && 467a56bb8a5SSatoshi Asami (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 468a56bb8a5SSatoshi Asami #ifdef DEBUG 469a56bb8a5SSatoshi Asami if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 470a56bb8a5SSatoshi Asami printf("ccd%d: interleave must be at least %d\n", 471a56bb8a5SSatoshi Asami ccd->ccd_unit, (maxsecsize / DEV_BSIZE)); 472a56bb8a5SSatoshi Asami #endif 4731464240eSMatthew Dillon error = EINVAL; 4741464240eSMatthew Dillon goto fail; 475a56bb8a5SSatoshi Asami } 476a56bb8a5SSatoshi Asami 477a56bb8a5SSatoshi Asami /* 478a56bb8a5SSatoshi Asami * If uniform interleave is desired set all sizes to that of 4791464240eSMatthew Dillon * the smallest component. This will guarentee that a single 4801464240eSMatthew Dillon * interleave table is generated. 4811464240eSMatthew Dillon * 4821464240eSMatthew Dillon * Lost space must be taken into account when calculating the 4831464240eSMatthew Dillon * overall size. Half the space is lost when CCDF_MIRROR is 4841464240eSMatthew Dillon * specified. One disk is lost when CCDF_PARITY is specified. 485a56bb8a5SSatoshi Asami */ 486a56bb8a5SSatoshi Asami if (ccd->ccd_flags & CCDF_UNIFORM) { 487a56bb8a5SSatoshi Asami for (ci = cs->sc_cinfo; 4881464240eSMatthew Dillon ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) { 489a56bb8a5SSatoshi Asami ci->ci_size = minsize; 4901464240eSMatthew Dillon } 49109b59204SSatoshi Asami if (ccd->ccd_flags & CCDF_MIRROR) { 49234f35216SSatoshi Asami /* 49334f35216SSatoshi Asami * Check to see if an even number of components 4941464240eSMatthew Dillon * have been specified. The interleave must also 4951464240eSMatthew Dillon * be non-zero in order for us to be able to 4961464240eSMatthew Dillon * guarentee the topology. 49734f35216SSatoshi Asami */ 49809b59204SSatoshi Asami if (cs->sc_nccdisks % 2) { 49934f35216SSatoshi Asami printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit ); 5001464240eSMatthew Dillon error = EINVAL; 5011464240eSMatthew Dillon goto fail; 50234f35216SSatoshi Asami } 5031464240eSMatthew Dillon if (cs->sc_ileave == 0) { 5041464240eSMatthew Dillon printf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit); 5051464240eSMatthew Dillon error = EINVAL; 5061464240eSMatthew Dillon goto fail; 50709b59204SSatoshi Asami } 50809b59204SSatoshi Asami cs->sc_size = (cs->sc_nccdisks/2) * minsize; 5091464240eSMatthew Dillon } else if (ccd->ccd_flags & CCDF_PARITY) { 5107ecb65faSSatoshi Asami cs->sc_size = (cs->sc_nccdisks-1) * minsize; 5111464240eSMatthew Dillon } else { 5121464240eSMatthew Dillon if (cs->sc_ileave == 0) { 5131464240eSMatthew Dillon printf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit); 5141464240eSMatthew Dillon error = EINVAL; 5151464240eSMatthew Dillon goto fail; 5161464240eSMatthew Dillon } 517a56bb8a5SSatoshi Asami cs->sc_size = cs->sc_nccdisks * minsize; 518a56bb8a5SSatoshi Asami } 5191464240eSMatthew Dillon } 520a56bb8a5SSatoshi Asami 521a56bb8a5SSatoshi Asami /* 522a56bb8a5SSatoshi Asami * Construct the interleave table. 523a56bb8a5SSatoshi Asami */ 524a56bb8a5SSatoshi Asami ccdinterleave(cs, ccd->ccd_unit); 525a56bb8a5SSatoshi Asami 526a56bb8a5SSatoshi Asami /* 527a56bb8a5SSatoshi Asami * Create pseudo-geometry based on 1MB cylinders. It's 528a56bb8a5SSatoshi Asami * pretty close. 529a56bb8a5SSatoshi Asami */ 530e59f3105SSøren Schmidt ccg->ccg_secsize = maxsecsize; 531a56bb8a5SSatoshi Asami ccg->ccg_ntracks = 1; 532e322ec4cSMatthew Dillon ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize; 533a56bb8a5SSatoshi Asami ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 534a56bb8a5SSatoshi Asami 535b2dfb1f9SJustin T. Gibbs /* 536b2dfb1f9SJustin T. Gibbs * Add an devstat entry for this device. 537b2dfb1f9SJustin T. Gibbs */ 538b2dfb1f9SJustin T. Gibbs devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit, 539b2dfb1f9SJustin T. Gibbs ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED, 54086b2c846SKenneth D. Merry DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER, 54186b2c846SKenneth D. Merry DEVSTAT_PRIORITY_ARRAY); 542a56bb8a5SSatoshi Asami 543a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_INITED; 544a56bb8a5SSatoshi Asami cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */ 545a56bb8a5SSatoshi Asami cs->sc_unit = ccd->ccd_unit; 546a56bb8a5SSatoshi Asami return (0); 5471464240eSMatthew Dillon fail: 5481464240eSMatthew Dillon while (ci > cs->sc_cinfo) { 5491464240eSMatthew Dillon ci--; 5501464240eSMatthew Dillon free(ci->ci_path, M_DEVBUF); 5511464240eSMatthew Dillon } 5521464240eSMatthew Dillon free(cs->sc_cinfo, M_DEVBUF); 5531464240eSMatthew Dillon return (error); 554a56bb8a5SSatoshi Asami } 555a56bb8a5SSatoshi Asami 556a56bb8a5SSatoshi Asami static void 557a56bb8a5SSatoshi Asami ccdinterleave(cs, unit) 5581464240eSMatthew Dillon struct ccd_softc *cs; 559a56bb8a5SSatoshi Asami int unit; 560a56bb8a5SSatoshi Asami { 5611464240eSMatthew Dillon struct ccdcinfo *ci, *smallci; 5621464240eSMatthew Dillon struct ccdiinfo *ii; 5631464240eSMatthew Dillon daddr_t bn, lbn; 5641464240eSMatthew Dillon int ix; 565a56bb8a5SSatoshi Asami u_long size; 566a56bb8a5SSatoshi Asami 567a56bb8a5SSatoshi Asami #ifdef DEBUG 568a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 569a56bb8a5SSatoshi Asami printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); 570a56bb8a5SSatoshi Asami #endif 5711464240eSMatthew Dillon 572a56bb8a5SSatoshi Asami /* 5731464240eSMatthew Dillon * Allocate an interleave table. The worst case occurs when each 5741464240eSMatthew Dillon * of N disks is of a different size, resulting in N interleave 5751464240eSMatthew Dillon * tables. 5761464240eSMatthew Dillon * 577a56bb8a5SSatoshi Asami * Chances are this is too big, but we don't care. 578a56bb8a5SSatoshi Asami */ 579a56bb8a5SSatoshi Asami size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 580a56bb8a5SSatoshi Asami cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 581a56bb8a5SSatoshi Asami bzero((caddr_t)cs->sc_itable, size); 582a56bb8a5SSatoshi Asami 583a56bb8a5SSatoshi Asami /* 584a56bb8a5SSatoshi Asami * Trivial case: no interleave (actually interleave of disk size). 585a56bb8a5SSatoshi Asami * Each table entry represents a single component in its entirety. 5861464240eSMatthew Dillon * 5871464240eSMatthew Dillon * An interleave of 0 may not be used with a mirror or parity setup. 588a56bb8a5SSatoshi Asami */ 589a56bb8a5SSatoshi Asami if (cs->sc_ileave == 0) { 590a56bb8a5SSatoshi Asami bn = 0; 591a56bb8a5SSatoshi Asami ii = cs->sc_itable; 592a56bb8a5SSatoshi Asami 593a56bb8a5SSatoshi Asami for (ix = 0; ix < cs->sc_nccdisks; ix++) { 594a56bb8a5SSatoshi Asami /* Allocate space for ii_index. */ 595a56bb8a5SSatoshi Asami ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); 596a56bb8a5SSatoshi Asami ii->ii_ndisk = 1; 597a56bb8a5SSatoshi Asami ii->ii_startblk = bn; 598a56bb8a5SSatoshi Asami ii->ii_startoff = 0; 599a56bb8a5SSatoshi Asami ii->ii_index[0] = ix; 600a56bb8a5SSatoshi Asami bn += cs->sc_cinfo[ix].ci_size; 601a56bb8a5SSatoshi Asami ii++; 602a56bb8a5SSatoshi Asami } 603a56bb8a5SSatoshi Asami ii->ii_ndisk = 0; 604a56bb8a5SSatoshi Asami #ifdef DEBUG 605a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 606a56bb8a5SSatoshi Asami printiinfo(cs->sc_itable); 607a56bb8a5SSatoshi Asami #endif 608a56bb8a5SSatoshi Asami return; 609a56bb8a5SSatoshi Asami } 610a56bb8a5SSatoshi Asami 611a56bb8a5SSatoshi Asami /* 612a56bb8a5SSatoshi Asami * The following isn't fast or pretty; it doesn't have to be. 613a56bb8a5SSatoshi Asami */ 614a56bb8a5SSatoshi Asami size = 0; 615a56bb8a5SSatoshi Asami bn = lbn = 0; 616a56bb8a5SSatoshi Asami for (ii = cs->sc_itable; ; ii++) { 6171464240eSMatthew Dillon /* 6181464240eSMatthew Dillon * Allocate space for ii_index. We might allocate more then 6191464240eSMatthew Dillon * we use. 6201464240eSMatthew Dillon */ 621a56bb8a5SSatoshi Asami ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), 622a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 623a56bb8a5SSatoshi Asami 624a56bb8a5SSatoshi Asami /* 625a56bb8a5SSatoshi Asami * Locate the smallest of the remaining components 626a56bb8a5SSatoshi Asami */ 627a56bb8a5SSatoshi Asami smallci = NULL; 6281464240eSMatthew Dillon for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; 6291464240eSMatthew Dillon ci++) { 630a56bb8a5SSatoshi Asami if (ci->ci_size > size && 631a56bb8a5SSatoshi Asami (smallci == NULL || 6321464240eSMatthew Dillon ci->ci_size < smallci->ci_size)) { 633a56bb8a5SSatoshi Asami smallci = ci; 6341464240eSMatthew Dillon } 6351464240eSMatthew Dillon } 636a56bb8a5SSatoshi Asami 637a56bb8a5SSatoshi Asami /* 638a56bb8a5SSatoshi Asami * Nobody left, all done 639a56bb8a5SSatoshi Asami */ 640a56bb8a5SSatoshi Asami if (smallci == NULL) { 641a56bb8a5SSatoshi Asami ii->ii_ndisk = 0; 642a56bb8a5SSatoshi Asami break; 643a56bb8a5SSatoshi Asami } 644a56bb8a5SSatoshi Asami 645a56bb8a5SSatoshi Asami /* 6461464240eSMatthew Dillon * Record starting logical block using an sc_ileave blocksize. 647a56bb8a5SSatoshi Asami */ 648a56bb8a5SSatoshi Asami ii->ii_startblk = bn / cs->sc_ileave; 6491464240eSMatthew Dillon 6501464240eSMatthew Dillon /* 6511464240eSMatthew Dillon * Record starting comopnent block using an sc_ileave 6521464240eSMatthew Dillon * blocksize. This value is relative to the beginning of 6531464240eSMatthew Dillon * a component disk. 6541464240eSMatthew Dillon */ 655a56bb8a5SSatoshi Asami ii->ii_startoff = lbn; 656a56bb8a5SSatoshi Asami 657a56bb8a5SSatoshi Asami /* 658a56bb8a5SSatoshi Asami * Determine how many disks take part in this interleave 659a56bb8a5SSatoshi Asami * and record their indices. 660a56bb8a5SSatoshi Asami */ 661a56bb8a5SSatoshi Asami ix = 0; 662a56bb8a5SSatoshi Asami for (ci = cs->sc_cinfo; 6631464240eSMatthew Dillon ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) { 6641464240eSMatthew Dillon if (ci->ci_size >= smallci->ci_size) { 665a56bb8a5SSatoshi Asami ii->ii_index[ix++] = ci - cs->sc_cinfo; 6661464240eSMatthew Dillon } 6671464240eSMatthew Dillon } 668a56bb8a5SSatoshi Asami ii->ii_ndisk = ix; 669a56bb8a5SSatoshi Asami bn += ix * (smallci->ci_size - size); 670a56bb8a5SSatoshi Asami lbn = smallci->ci_size / cs->sc_ileave; 671a56bb8a5SSatoshi Asami size = smallci->ci_size; 672a56bb8a5SSatoshi Asami } 673a56bb8a5SSatoshi Asami #ifdef DEBUG 674a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 675a56bb8a5SSatoshi Asami printiinfo(cs->sc_itable); 676a56bb8a5SSatoshi Asami #endif 677a56bb8a5SSatoshi Asami } 678a56bb8a5SSatoshi Asami 679a56bb8a5SSatoshi Asami /* ARGSUSED */ 680e2738b4fSPoul-Henning Kamp static int 681a56bb8a5SSatoshi Asami ccdopen(dev, flags, fmt, p) 682a56bb8a5SSatoshi Asami dev_t dev; 683a56bb8a5SSatoshi Asami int flags, fmt; 684a56bb8a5SSatoshi Asami struct proc *p; 685a56bb8a5SSatoshi Asami { 686a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 687a56bb8a5SSatoshi Asami struct ccd_softc *cs; 688a56bb8a5SSatoshi Asami struct disklabel *lp; 689a56bb8a5SSatoshi Asami int error = 0, part, pmask; 690a56bb8a5SSatoshi Asami 691a56bb8a5SSatoshi Asami #ifdef DEBUG 692a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 693a56bb8a5SSatoshi Asami printf("ccdopen(%x, %x)\n", dev, flags); 694a56bb8a5SSatoshi Asami #endif 695a56bb8a5SSatoshi Asami if (unit >= numccd) 696a56bb8a5SSatoshi Asami return (ENXIO); 697a56bb8a5SSatoshi Asami cs = &ccd_softc[unit]; 698a56bb8a5SSatoshi Asami 699b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 700a56bb8a5SSatoshi Asami return (error); 701a56bb8a5SSatoshi Asami 7026cc5a722SPoul-Henning Kamp lp = &cs->sc_label; 703a56bb8a5SSatoshi Asami 704d8594dfbSSatoshi Asami part = ccdpart(dev); 705a56bb8a5SSatoshi Asami pmask = (1 << part); 706a56bb8a5SSatoshi Asami 707a56bb8a5SSatoshi Asami /* 708a56bb8a5SSatoshi Asami * If we're initialized, check to see if there are any other 709a56bb8a5SSatoshi Asami * open partitions. If not, then it's safe to update 710a56bb8a5SSatoshi Asami * the in-core disklabel. 711a56bb8a5SSatoshi Asami */ 7126cc5a722SPoul-Henning Kamp if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0)) 713a56bb8a5SSatoshi Asami ccdgetdisklabel(dev); 714a56bb8a5SSatoshi Asami 715a56bb8a5SSatoshi Asami /* Check that the partition exists. */ 7167d15435cSJordan K. Hubbard if (part != RAW_PART && ((part >= lp->d_npartitions) || 717a56bb8a5SSatoshi Asami (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 718a56bb8a5SSatoshi Asami error = ENXIO; 719a56bb8a5SSatoshi Asami goto done; 720a56bb8a5SSatoshi Asami } 721a56bb8a5SSatoshi Asami 722af8862e4SPoul-Henning Kamp cs->sc_openmask |= pmask; 723a56bb8a5SSatoshi Asami done: 724a56bb8a5SSatoshi Asami ccdunlock(cs); 725a56bb8a5SSatoshi Asami return (0); 726a56bb8a5SSatoshi Asami } 727a56bb8a5SSatoshi Asami 728a56bb8a5SSatoshi Asami /* ARGSUSED */ 729e2738b4fSPoul-Henning Kamp static int 730a56bb8a5SSatoshi Asami ccdclose(dev, flags, fmt, p) 731a56bb8a5SSatoshi Asami dev_t dev; 732a56bb8a5SSatoshi Asami int flags, fmt; 733a56bb8a5SSatoshi Asami struct proc *p; 734a56bb8a5SSatoshi Asami { 735a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 736a56bb8a5SSatoshi Asami struct ccd_softc *cs; 737a56bb8a5SSatoshi Asami int error = 0, part; 738a56bb8a5SSatoshi Asami 739a56bb8a5SSatoshi Asami #ifdef DEBUG 740a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 741a56bb8a5SSatoshi Asami printf("ccdclose(%x, %x)\n", dev, flags); 742a56bb8a5SSatoshi Asami #endif 743a56bb8a5SSatoshi Asami 744a56bb8a5SSatoshi Asami if (unit >= numccd) 745a56bb8a5SSatoshi Asami return (ENXIO); 746a56bb8a5SSatoshi Asami cs = &ccd_softc[unit]; 747a56bb8a5SSatoshi Asami 748b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 749a56bb8a5SSatoshi Asami return (error); 750a56bb8a5SSatoshi Asami 751d8594dfbSSatoshi Asami part = ccdpart(dev); 752a56bb8a5SSatoshi Asami 753a56bb8a5SSatoshi Asami /* ...that much closer to allowing unconfiguration... */ 754af8862e4SPoul-Henning Kamp cs->sc_openmask &= ~(1 << part); 755a56bb8a5SSatoshi Asami ccdunlock(cs); 756a56bb8a5SSatoshi Asami return (0); 757a56bb8a5SSatoshi Asami } 758a56bb8a5SSatoshi Asami 759e2738b4fSPoul-Henning Kamp static void 7609d7f7369SPoul-Henning Kamp ccdstrategy(bp) 7619d7f7369SPoul-Henning Kamp struct bio *bp; 762a56bb8a5SSatoshi Asami { 7639d7f7369SPoul-Henning Kamp int unit = ccdunit(bp->bio_dev); 7641464240eSMatthew Dillon struct ccd_softc *cs = &ccd_softc[unit]; 7651464240eSMatthew Dillon int s; 766a56bb8a5SSatoshi Asami int wlabel; 767a56bb8a5SSatoshi Asami struct disklabel *lp; 768a56bb8a5SSatoshi Asami 769a56bb8a5SSatoshi Asami #ifdef DEBUG 770a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 771a56bb8a5SSatoshi Asami printf("ccdstrategy(%x): unit %d\n", bp, unit); 772a56bb8a5SSatoshi Asami #endif 773a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) { 7749d7f7369SPoul-Henning Kamp bp->bio_error = ENXIO; 7759d7f7369SPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 776a56bb8a5SSatoshi Asami goto done; 777a56bb8a5SSatoshi Asami } 778a56bb8a5SSatoshi Asami 779a56bb8a5SSatoshi Asami /* If it's a nil transfer, wake up the top half now. */ 7809d7f7369SPoul-Henning Kamp if (bp->bio_bcount == 0) 781a56bb8a5SSatoshi Asami goto done; 782a56bb8a5SSatoshi Asami 7836cc5a722SPoul-Henning Kamp lp = &cs->sc_label; 784a56bb8a5SSatoshi Asami 785a56bb8a5SSatoshi Asami /* 786a56bb8a5SSatoshi Asami * Do bounds checking and adjust transfer. If there's an 787a56bb8a5SSatoshi Asami * error, the bounds check will flag that for us. 788a56bb8a5SSatoshi Asami */ 789a56bb8a5SSatoshi Asami wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 7909d7f7369SPoul-Henning Kamp if (ccdpart(bp->bio_dev) != RAW_PART) { 7919d7f7369SPoul-Henning Kamp if (bounds_check_with_label(bp, lp, wlabel) <= 0) 792a56bb8a5SSatoshi Asami goto done; 79374427f90SMatthew Dillon } else { 79474427f90SMatthew Dillon int pbn; /* in sc_secsize chunks */ 79574427f90SMatthew Dillon long sz; /* in sc_secsize chunks */ 79674427f90SMatthew Dillon 7979d7f7369SPoul-Henning Kamp pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE); 7989d7f7369SPoul-Henning Kamp sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize); 79974427f90SMatthew Dillon 80074427f90SMatthew Dillon /* 80174427f90SMatthew Dillon * If out of bounds return an error. If at the EOF point, 80274427f90SMatthew Dillon * simply read or write less. 80374427f90SMatthew Dillon */ 80474427f90SMatthew Dillon 80574427f90SMatthew Dillon if (pbn < 0 || pbn >= cs->sc_size) { 8069d7f7369SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 80774427f90SMatthew Dillon if (pbn != cs->sc_size) { 8089d7f7369SPoul-Henning Kamp bp->bio_error = EINVAL; 8099d7f7369SPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 81074427f90SMatthew Dillon } 81174427f90SMatthew Dillon goto done; 81274427f90SMatthew Dillon } 81374427f90SMatthew Dillon 81474427f90SMatthew Dillon /* 81574427f90SMatthew Dillon * If the request crosses EOF, truncate the request. 81674427f90SMatthew Dillon */ 81774427f90SMatthew Dillon if (pbn + sz > cs->sc_size) { 8189d7f7369SPoul-Henning Kamp bp->bio_bcount = (cs->sc_size - pbn) * 81974427f90SMatthew Dillon cs->sc_geom.ccg_secsize; 82074427f90SMatthew Dillon } 82174427f90SMatthew Dillon } 822a56bb8a5SSatoshi Asami 8239d7f7369SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 824a56bb8a5SSatoshi Asami 825a56bb8a5SSatoshi Asami /* 826a56bb8a5SSatoshi Asami * "Start" the unit. 827a56bb8a5SSatoshi Asami */ 828a56bb8a5SSatoshi Asami s = splbio(); 829a56bb8a5SSatoshi Asami ccdstart(cs, bp); 830a56bb8a5SSatoshi Asami splx(s); 831a56bb8a5SSatoshi Asami return; 832a56bb8a5SSatoshi Asami done: 8339d7f7369SPoul-Henning Kamp biodone(bp); 834a56bb8a5SSatoshi Asami } 835a56bb8a5SSatoshi Asami 836a56bb8a5SSatoshi Asami static void 837a56bb8a5SSatoshi Asami ccdstart(cs, bp) 8381464240eSMatthew Dillon struct ccd_softc *cs; 8399d7f7369SPoul-Henning Kamp struct bio *bp; 840a56bb8a5SSatoshi Asami { 8411464240eSMatthew Dillon long bcount, rcount; 8423bc746beSSatoshi Asami struct ccdbuf *cbp[4]; 8433bc746beSSatoshi Asami /* XXX! : 2 reads and 2 writes for RAID 4/5 */ 844a56bb8a5SSatoshi Asami caddr_t addr; 845a56bb8a5SSatoshi Asami daddr_t bn; 846a56bb8a5SSatoshi Asami struct partition *pp; 847a56bb8a5SSatoshi Asami 848a56bb8a5SSatoshi Asami #ifdef DEBUG 849a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 850a56bb8a5SSatoshi Asami printf("ccdstart(%x, %x)\n", cs, bp); 851a56bb8a5SSatoshi Asami #endif 852a56bb8a5SSatoshi Asami 853b2dfb1f9SJustin T. Gibbs /* Record the transaction start */ 854b2dfb1f9SJustin T. Gibbs devstat_start_transaction(&cs->device_stats); 855a56bb8a5SSatoshi Asami 856a56bb8a5SSatoshi Asami /* 857a56bb8a5SSatoshi Asami * Translate the partition-relative block number to an absolute. 858a56bb8a5SSatoshi Asami */ 8599d7f7369SPoul-Henning Kamp bn = bp->bio_blkno; 8609d7f7369SPoul-Henning Kamp if (ccdpart(bp->bio_dev) != RAW_PART) { 8619d7f7369SPoul-Henning Kamp pp = &cs->sc_label.d_partitions[ccdpart(bp->bio_dev)]; 862a56bb8a5SSatoshi Asami bn += pp->p_offset; 863a56bb8a5SSatoshi Asami } 864a56bb8a5SSatoshi Asami 865a56bb8a5SSatoshi Asami /* 866a56bb8a5SSatoshi Asami * Allocate component buffers and fire off the requests 867a56bb8a5SSatoshi Asami */ 8689d7f7369SPoul-Henning Kamp addr = bp->bio_data; 8699d7f7369SPoul-Henning Kamp for (bcount = bp->bio_bcount; bcount > 0; bcount -= rcount) { 8703bc746beSSatoshi Asami ccdbuffer(cbp, cs, bp, bn, addr, bcount); 8719d7f7369SPoul-Henning Kamp rcount = cbp[0]->cb_buf.bio_bcount; 8721464240eSMatthew Dillon 8731464240eSMatthew Dillon if (cs->sc_cflags & CCDF_MIRROR) { 8741464240eSMatthew Dillon /* 8751464240eSMatthew Dillon * Mirroring. Writes go to both disks, reads are 8761464240eSMatthew Dillon * taken from whichever disk seems most appropriate. 8771464240eSMatthew Dillon * 8781464240eSMatthew Dillon * We attempt to localize reads to the disk whos arm 8791464240eSMatthew Dillon * is nearest the read request. We ignore seeks due 8801464240eSMatthew Dillon * to writes when making this determination and we 8811464240eSMatthew Dillon * also try to avoid hogging. 8821464240eSMatthew Dillon */ 8839d7f7369SPoul-Henning Kamp if (cbp[0]->cb_buf.bio_cmd == BIO_WRITE) { 8849d7f7369SPoul-Henning Kamp BIO_STRATEGY(&cbp[0]->cb_buf, 0); 8859d7f7369SPoul-Henning Kamp BIO_STRATEGY(&cbp[1]->cb_buf, 0); 8861464240eSMatthew Dillon } else { 8871464240eSMatthew Dillon int pick = cs->sc_pick; 8881464240eSMatthew Dillon daddr_t range = cs->sc_size / 16; 8891464240eSMatthew Dillon 8901464240eSMatthew Dillon if (bn < cs->sc_blk[pick] - range || 8911464240eSMatthew Dillon bn > cs->sc_blk[pick] + range 8921464240eSMatthew Dillon ) { 8931464240eSMatthew Dillon cs->sc_pick = pick = 1 - pick; 8941464240eSMatthew Dillon } 8951464240eSMatthew Dillon cs->sc_blk[pick] = bn + btodb(rcount); 8969d7f7369SPoul-Henning Kamp BIO_STRATEGY(&cbp[pick]->cb_buf, 0); 8971464240eSMatthew Dillon } 8981464240eSMatthew Dillon } else { 8991464240eSMatthew Dillon /* 9001464240eSMatthew Dillon * Not mirroring 9011464240eSMatthew Dillon */ 9029d7f7369SPoul-Henning Kamp BIO_STRATEGY(&cbp[0]->cb_buf, 0); 9033bc746beSSatoshi Asami } 904a56bb8a5SSatoshi Asami bn += btodb(rcount); 905a56bb8a5SSatoshi Asami addr += rcount; 906a56bb8a5SSatoshi Asami } 907a56bb8a5SSatoshi Asami } 908a56bb8a5SSatoshi Asami 909a56bb8a5SSatoshi Asami /* 910a56bb8a5SSatoshi Asami * Build a component buffer header. 911a56bb8a5SSatoshi Asami */ 912e2738b4fSPoul-Henning Kamp static void 9133bc746beSSatoshi Asami ccdbuffer(cb, cs, bp, bn, addr, bcount) 9141464240eSMatthew Dillon struct ccdbuf **cb; 9151464240eSMatthew Dillon struct ccd_softc *cs; 9169d7f7369SPoul-Henning Kamp struct bio *bp; 917a56bb8a5SSatoshi Asami daddr_t bn; 918a56bb8a5SSatoshi Asami caddr_t addr; 919a56bb8a5SSatoshi Asami long bcount; 920a56bb8a5SSatoshi Asami { 9211464240eSMatthew Dillon struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ 9221464240eSMatthew Dillon struct ccdbuf *cbp; 9231464240eSMatthew Dillon daddr_t cbn, cboff; 9241464240eSMatthew Dillon off_t cbc; 925a56bb8a5SSatoshi Asami 926a56bb8a5SSatoshi Asami #ifdef DEBUG 927a56bb8a5SSatoshi Asami if (ccddebug & CCDB_IO) 928a56bb8a5SSatoshi Asami printf("ccdbuffer(%x, %x, %d, %x, %d)\n", 929a56bb8a5SSatoshi Asami cs, bp, bn, addr, bcount); 930a56bb8a5SSatoshi Asami #endif 931a56bb8a5SSatoshi Asami /* 932a56bb8a5SSatoshi Asami * Determine which component bn falls in. 933a56bb8a5SSatoshi Asami */ 934a56bb8a5SSatoshi Asami cbn = bn; 935a56bb8a5SSatoshi Asami cboff = 0; 936a56bb8a5SSatoshi Asami 937a56bb8a5SSatoshi Asami if (cs->sc_ileave == 0) { 9381464240eSMatthew Dillon /* 9391464240eSMatthew Dillon * Serially concatenated and neither a mirror nor a parity 9401464240eSMatthew Dillon * config. This is a special case. 9411464240eSMatthew Dillon */ 9421464240eSMatthew Dillon daddr_t sblk; 943a56bb8a5SSatoshi Asami 944a56bb8a5SSatoshi Asami sblk = 0; 945a56bb8a5SSatoshi Asami for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 946a56bb8a5SSatoshi Asami sblk += ci->ci_size; 947a56bb8a5SSatoshi Asami cbn -= sblk; 9481464240eSMatthew Dillon } else { 9491464240eSMatthew Dillon struct ccdiinfo *ii; 950a56bb8a5SSatoshi Asami int ccdisk, off; 951a56bb8a5SSatoshi Asami 9521464240eSMatthew Dillon /* 9531464240eSMatthew Dillon * Calculate cbn, the logical superblock (sc_ileave chunks), 9541464240eSMatthew Dillon * and cboff, a normal block offset (DEV_BSIZE chunks) relative 9551464240eSMatthew Dillon * to cbn. 9561464240eSMatthew Dillon */ 9571464240eSMatthew Dillon cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */ 9581464240eSMatthew Dillon cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */ 9591464240eSMatthew Dillon 9601464240eSMatthew Dillon /* 9611464240eSMatthew Dillon * Figure out which interleave table to use. 9621464240eSMatthew Dillon */ 9631464240eSMatthew Dillon for (ii = cs->sc_itable; ii->ii_ndisk; ii++) { 964a56bb8a5SSatoshi Asami if (ii->ii_startblk > cbn) 965a56bb8a5SSatoshi Asami break; 9661464240eSMatthew Dillon } 967a56bb8a5SSatoshi Asami ii--; 9681464240eSMatthew Dillon 9691464240eSMatthew Dillon /* 9701464240eSMatthew Dillon * off is the logical superblock relative to the beginning 9711464240eSMatthew Dillon * of this interleave block. 9721464240eSMatthew Dillon */ 973a56bb8a5SSatoshi Asami off = cbn - ii->ii_startblk; 9741464240eSMatthew Dillon 9751464240eSMatthew Dillon /* 9761464240eSMatthew Dillon * We must calculate which disk component to use (ccdisk), 9771464240eSMatthew Dillon * and recalculate cbn to be the superblock relative to 9781464240eSMatthew Dillon * the beginning of the component. This is typically done by 9791464240eSMatthew Dillon * adding 'off' and ii->ii_startoff together. However, 'off' 9801464240eSMatthew Dillon * must typically be divided by the number of components in 9811464240eSMatthew Dillon * this interleave array to be properly convert it from a 9821464240eSMatthew Dillon * CCD-relative logical superblock number to a 9831464240eSMatthew Dillon * component-relative superblock number. 9841464240eSMatthew Dillon */ 985a56bb8a5SSatoshi Asami if (ii->ii_ndisk == 1) { 9861464240eSMatthew Dillon /* 9871464240eSMatthew Dillon * When we have just one disk, it can't be a mirror 9881464240eSMatthew Dillon * or a parity config. 9891464240eSMatthew Dillon */ 990a56bb8a5SSatoshi Asami ccdisk = ii->ii_index[0]; 991a56bb8a5SSatoshi Asami cbn = ii->ii_startoff + off; 992a56bb8a5SSatoshi Asami } else { 99309b59204SSatoshi Asami if (cs->sc_cflags & CCDF_MIRROR) { 9941464240eSMatthew Dillon /* 9951464240eSMatthew Dillon * We have forced a uniform mapping, resulting 9961464240eSMatthew Dillon * in a single interleave array. We double 9971464240eSMatthew Dillon * up on the first half of the available 9981464240eSMatthew Dillon * components and our mirror is in the second 9991464240eSMatthew Dillon * half. This only works with a single 10001464240eSMatthew Dillon * interleave array because doubling up 10011464240eSMatthew Dillon * doubles the number of sectors, so there 10021464240eSMatthew Dillon * cannot be another interleave array because 10031464240eSMatthew Dillon * the next interleave array's calculations 10041464240eSMatthew Dillon * would be off. 10051464240eSMatthew Dillon */ 10061464240eSMatthew Dillon int ndisk2 = ii->ii_ndisk / 2; 10071464240eSMatthew Dillon ccdisk = ii->ii_index[off % ndisk2]; 10081464240eSMatthew Dillon cbn = ii->ii_startoff + off / ndisk2; 10091464240eSMatthew Dillon ci2 = &cs->sc_cinfo[ccdisk + ndisk2]; 10101464240eSMatthew Dillon } else if (cs->sc_cflags & CCDF_PARITY) { 10111464240eSMatthew Dillon /* 10121464240eSMatthew Dillon * XXX not implemented yet 10131464240eSMatthew Dillon */ 10141464240eSMatthew Dillon int ndisk2 = ii->ii_ndisk - 1; 10151464240eSMatthew Dillon ccdisk = ii->ii_index[off % ndisk2]; 10161464240eSMatthew Dillon cbn = ii->ii_startoff + off / ndisk2; 10177ecb65faSSatoshi Asami if (cbn % ii->ii_ndisk <= ccdisk) 10187ecb65faSSatoshi Asami ccdisk++; 10191464240eSMatthew Dillon } else { 1020a56bb8a5SSatoshi Asami ccdisk = ii->ii_index[off % ii->ii_ndisk]; 1021a56bb8a5SSatoshi Asami cbn = ii->ii_startoff + off / ii->ii_ndisk; 1022a56bb8a5SSatoshi Asami } 10237ecb65faSSatoshi Asami } 10241464240eSMatthew Dillon 1025a56bb8a5SSatoshi Asami ci = &cs->sc_cinfo[ccdisk]; 10261464240eSMatthew Dillon 10271464240eSMatthew Dillon /* 10281464240eSMatthew Dillon * Convert cbn from a superblock to a normal block so it 10291464240eSMatthew Dillon * can be used to calculate (along with cboff) the normal 10301464240eSMatthew Dillon * block index into this particular disk. 10311464240eSMatthew Dillon */ 10321464240eSMatthew Dillon cbn *= cs->sc_ileave; 1033a56bb8a5SSatoshi Asami } 1034a56bb8a5SSatoshi Asami 1035a56bb8a5SSatoshi Asami /* 1036a56bb8a5SSatoshi Asami * Fill in the component buf structure. 1037a56bb8a5SSatoshi Asami */ 10381464240eSMatthew Dillon cbp = getccdbuf(NULL); 10399d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_cmd = bp->bio_cmd; 10409d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_done = ccdiodone; 10419d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_dev = ci->ci_dev; /* XXX */ 10429d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_blkno = cbn + cboff + CCD_OFFSET; 10439d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_offset = dbtob(cbn + cboff + CCD_OFFSET); 10449d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_data = addr; 1045a56bb8a5SSatoshi Asami if (cs->sc_ileave == 0) 104640969e38SDavid Greenman cbc = dbtob((off_t)(ci->ci_size - cbn)); 1047a56bb8a5SSatoshi Asami else 104840969e38SDavid Greenman cbc = dbtob((off_t)(cs->sc_ileave - cboff)); 10499d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_bcount = (cbc < bcount) ? cbc : bcount; 10509d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_caller1 = (void*)cbp->cb_buf.bio_bcount; 1051c0b89506SJohn Dyson 1052a56bb8a5SSatoshi Asami /* 1053a56bb8a5SSatoshi Asami * context for ccdiodone 1054a56bb8a5SSatoshi Asami */ 1055a56bb8a5SSatoshi Asami cbp->cb_obp = bp; 1056a56bb8a5SSatoshi Asami cbp->cb_unit = cs - ccd_softc; 1057a56bb8a5SSatoshi Asami cbp->cb_comp = ci - cs->sc_cinfo; 1058a56bb8a5SSatoshi Asami 1059a56bb8a5SSatoshi Asami #ifdef DEBUG 1060a56bb8a5SSatoshi Asami if (ccddebug & CCDB_IO) 1061a56bb8a5SSatoshi Asami printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 10629d7f7369SPoul-Henning Kamp ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.bio_blkno, 10639d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_data, cbp->cb_buf.bio_bcount); 1064a56bb8a5SSatoshi Asami #endif 10653bc746beSSatoshi Asami cb[0] = cbp; 10661464240eSMatthew Dillon 10671464240eSMatthew Dillon /* 10681464240eSMatthew Dillon * Note: both I/O's setup when reading from mirror, but only one 10691464240eSMatthew Dillon * will be executed. 10701464240eSMatthew Dillon */ 10711464240eSMatthew Dillon if (cs->sc_cflags & CCDF_MIRROR) { 10721464240eSMatthew Dillon /* mirror, setup second I/O */ 10731464240eSMatthew Dillon cbp = getccdbuf(cb[0]); 10749d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_dev = ci2->ci_dev; 10753bc746beSSatoshi Asami cbp->cb_comp = ci2 - cs->sc_cinfo; 10763bc746beSSatoshi Asami cb[1] = cbp; 1077e7322872SSatoshi Asami /* link together the ccdbuf's and clear "mirror done" flag */ 1078e7322872SSatoshi Asami cb[0]->cb_mirror = cb[1]; 1079e7322872SSatoshi Asami cb[1]->cb_mirror = cb[0]; 1080e7322872SSatoshi Asami cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; 1081e7322872SSatoshi Asami cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; 10823bc746beSSatoshi Asami } 1083a56bb8a5SSatoshi Asami } 1084a56bb8a5SSatoshi Asami 1085a56bb8a5SSatoshi Asami static void 1086a56bb8a5SSatoshi Asami ccdintr(cs, bp) 10871464240eSMatthew Dillon struct ccd_softc *cs; 10889d7f7369SPoul-Henning Kamp struct bio *bp; 1089a56bb8a5SSatoshi Asami { 1090a56bb8a5SSatoshi Asami #ifdef DEBUG 1091a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 1092a56bb8a5SSatoshi Asami printf("ccdintr(%x, %x)\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; 10999d7f7369SPoul-Henning Kamp devstat_end_transaction_bio(&cs->device_stats, bp); 11009d7f7369SPoul-Henning Kamp biodone(bp); 1101a56bb8a5SSatoshi Asami } 1102a56bb8a5SSatoshi Asami 1103a56bb8a5SSatoshi Asami /* 1104a56bb8a5SSatoshi Asami * Called at interrupt time. 1105a56bb8a5SSatoshi Asami * Mark the component as done and if all components are done, 1106a56bb8a5SSatoshi Asami * take a ccd interrupt. 1107a56bb8a5SSatoshi Asami */ 1108e2738b4fSPoul-Henning Kamp static void 110921144e3bSPoul-Henning Kamp ccdiodone(ibp) 11109d7f7369SPoul-Henning Kamp struct bio *ibp; 1111a56bb8a5SSatoshi Asami { 111221144e3bSPoul-Henning Kamp struct ccdbuf *cbp = (struct ccdbuf *)ibp; 11139d7f7369SPoul-Henning Kamp struct bio *bp = cbp->cb_obp; 11141464240eSMatthew Dillon int unit = cbp->cb_unit; 1115a56bb8a5SSatoshi Asami int count, s; 1116a56bb8a5SSatoshi Asami 1117a56bb8a5SSatoshi Asami s = splbio(); 1118a56bb8a5SSatoshi Asami #ifdef DEBUG 1119a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW) 1120a56bb8a5SSatoshi Asami printf("ccdiodone(%x)\n", cbp); 1121a56bb8a5SSatoshi Asami if (ccddebug & CCDB_IO) { 1122a56bb8a5SSatoshi Asami printf("ccdiodone: bp %x bcount %d resid %d\n", 11239d7f7369SPoul-Henning Kamp bp, bp->bio_bcount, bp->bio_resid); 1124a56bb8a5SSatoshi Asami printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 11259d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_dev, cbp->cb_comp, cbp, 11269d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_blkno, cbp->cb_buf.bio_data, 11279d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_bcount); 1128a56bb8a5SSatoshi Asami } 1129a56bb8a5SSatoshi Asami #endif 11301464240eSMatthew Dillon /* 11311464240eSMatthew Dillon * If an error occured, report it. If this is a mirrored 11321464240eSMatthew Dillon * configuration and the first of two possible reads, do not 11331464240eSMatthew Dillon * set the error in the bp yet because the second read may 11341464240eSMatthew Dillon * succeed. 11351464240eSMatthew Dillon */ 1136a56bb8a5SSatoshi Asami 11379d7f7369SPoul-Henning Kamp if (cbp->cb_buf.bio_flags & BIO_ERROR) { 11381464240eSMatthew Dillon const char *msg = ""; 11391464240eSMatthew Dillon 11401464240eSMatthew Dillon if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) && 11419d7f7369SPoul-Henning Kamp (cbp->cb_buf.bio_cmd == BIO_READ) && 11421464240eSMatthew Dillon (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 11431464240eSMatthew Dillon /* 11441464240eSMatthew Dillon * We will try our read on the other disk down 11451464240eSMatthew Dillon * below, also reverse the default pick so if we 11461464240eSMatthew Dillon * are doing a scan we do not keep hitting the 11471464240eSMatthew Dillon * bad disk first. 11481464240eSMatthew Dillon */ 11491464240eSMatthew Dillon struct ccd_softc *cs = &ccd_softc[unit]; 11501464240eSMatthew Dillon 11511464240eSMatthew Dillon msg = ", trying other disk"; 11521464240eSMatthew Dillon cs->sc_pick = 1 - cs->sc_pick; 11539d7f7369SPoul-Henning Kamp cs->sc_blk[cs->sc_pick] = bp->bio_blkno; 11541464240eSMatthew Dillon } else { 11559d7f7369SPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 11569d7f7369SPoul-Henning Kamp bp->bio_error = cbp->cb_buf.bio_error ? 11579d7f7369SPoul-Henning Kamp cbp->cb_buf.bio_error : EIO; 11581464240eSMatthew Dillon } 11591464240eSMatthew Dillon printf("ccd%d: error %d on component %d block %d (ccd block %d)%s\n", 11609d7f7369SPoul-Henning Kamp unit, bp->bio_error, cbp->cb_comp, 11619d7f7369SPoul-Henning Kamp (int)cbp->cb_buf.bio_blkno, bp->bio_blkno, msg); 1162a56bb8a5SSatoshi Asami } 1163e7322872SSatoshi Asami 11641464240eSMatthew Dillon /* 11651464240eSMatthew Dillon * Process mirror. If we are writing, I/O has been initiated on both 11661464240eSMatthew Dillon * buffers and we fall through only after both are finished. 11671464240eSMatthew Dillon * 11681464240eSMatthew Dillon * If we are reading only one I/O is initiated at a time. If an 11691464240eSMatthew Dillon * error occurs we initiate the second I/O and return, otherwise 11701464240eSMatthew Dillon * we free the second I/O without initiating it. 11711464240eSMatthew Dillon */ 11721464240eSMatthew Dillon 11731464240eSMatthew Dillon if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) { 11749d7f7369SPoul-Henning Kamp if (cbp->cb_buf.bio_cmd == BIO_WRITE) { 11751464240eSMatthew Dillon /* 11761464240eSMatthew Dillon * When writing, handshake with the second buffer 11771464240eSMatthew Dillon * to determine when both are done. If both are not 11781464240eSMatthew Dillon * done, return here. 11791464240eSMatthew Dillon */ 1180e7322872SSatoshi Asami if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 1181e7322872SSatoshi Asami cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; 1182e7322872SSatoshi Asami putccdbuf(cbp); 1183e7322872SSatoshi Asami splx(s); 1184e7322872SSatoshi Asami return; 1185e7322872SSatoshi Asami } 11861464240eSMatthew Dillon } else { 11871464240eSMatthew Dillon /* 11881464240eSMatthew Dillon * When reading, either dispose of the second buffer 11891464240eSMatthew Dillon * or initiate I/O on the second buffer if an error 11901464240eSMatthew Dillon * occured with this one. 11911464240eSMatthew Dillon */ 11921464240eSMatthew Dillon if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 11939d7f7369SPoul-Henning Kamp if (cbp->cb_buf.bio_flags & BIO_ERROR) { 11941464240eSMatthew Dillon cbp->cb_mirror->cb_pflags |= 11951464240eSMatthew Dillon CCDPF_MIRROR_DONE; 11969d7f7369SPoul-Henning Kamp BIO_STRATEGY(&cbp->cb_mirror->cb_buf, 0); 11971464240eSMatthew Dillon putccdbuf(cbp); 11981464240eSMatthew Dillon splx(s); 11991464240eSMatthew Dillon return; 12001464240eSMatthew Dillon } else { 12011464240eSMatthew Dillon putccdbuf(cbp->cb_mirror); 12021464240eSMatthew Dillon /* fall through */ 12031464240eSMatthew Dillon } 12041464240eSMatthew Dillon } 12051464240eSMatthew Dillon } 12061464240eSMatthew Dillon } 1207e7322872SSatoshi Asami 120825d1a00bSMatthew Dillon /* 12099d7f7369SPoul-Henning Kamp * use bio_caller1 to determine how big the original request was rather 12109d7f7369SPoul-Henning Kamp * then bio_bcount, because bio_bcount may have been truncated for EOF. 121125d1a00bSMatthew Dillon * 121225d1a00bSMatthew Dillon * XXX We check for an error, but we do not test the resid for an 121325d1a00bSMatthew Dillon * aligned EOF condition. This may result in character & block 121425d1a00bSMatthew Dillon * device access not recognizing EOF properly when read or written 121525d1a00bSMatthew Dillon * sequentially, but will not effect filesystems. 121625d1a00bSMatthew Dillon */ 12179d7f7369SPoul-Henning Kamp count = (long)cbp->cb_buf.bio_caller1; 1218a56bb8a5SSatoshi Asami putccdbuf(cbp); 1219a56bb8a5SSatoshi Asami 1220a56bb8a5SSatoshi Asami /* 1221a56bb8a5SSatoshi Asami * If all done, "interrupt". 1222a56bb8a5SSatoshi Asami */ 12239d7f7369SPoul-Henning Kamp bp->bio_resid -= count; 12249d7f7369SPoul-Henning Kamp if (bp->bio_resid < 0) 1225a56bb8a5SSatoshi Asami panic("ccdiodone: count"); 12269d7f7369SPoul-Henning Kamp if (bp->bio_resid == 0) 1227a56bb8a5SSatoshi Asami ccdintr(&ccd_softc[unit], bp); 1228a56bb8a5SSatoshi Asami splx(s); 1229a56bb8a5SSatoshi Asami } 1230a56bb8a5SSatoshi Asami 1231e2738b4fSPoul-Henning Kamp static int 1232a56bb8a5SSatoshi Asami ccdioctl(dev, cmd, data, flag, p) 1233a56bb8a5SSatoshi Asami dev_t dev; 1234ecbb00a2SDoug Rabson u_long cmd; 1235a56bb8a5SSatoshi Asami caddr_t data; 1236a56bb8a5SSatoshi Asami int flag; 1237a56bb8a5SSatoshi Asami struct proc *p; 1238a56bb8a5SSatoshi Asami { 1239a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 1240a56bb8a5SSatoshi Asami int i, j, lookedup = 0, error = 0; 1241a56bb8a5SSatoshi Asami int part, pmask, s; 1242a56bb8a5SSatoshi Asami struct ccd_softc *cs; 1243a56bb8a5SSatoshi Asami struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1244a56bb8a5SSatoshi Asami struct ccddevice ccd; 1245a56bb8a5SSatoshi Asami char **cpp; 1246a56bb8a5SSatoshi Asami struct vnode **vpp; 1247a56bb8a5SSatoshi Asami 1248a56bb8a5SSatoshi Asami if (unit >= numccd) 1249a56bb8a5SSatoshi Asami return (ENXIO); 1250a56bb8a5SSatoshi Asami cs = &ccd_softc[unit]; 1251a56bb8a5SSatoshi Asami 1252a56bb8a5SSatoshi Asami bzero(&ccd, sizeof(ccd)); 1253a56bb8a5SSatoshi Asami 1254a56bb8a5SSatoshi Asami switch (cmd) { 1255a56bb8a5SSatoshi Asami case CCDIOCSET: 1256a56bb8a5SSatoshi Asami if (cs->sc_flags & CCDF_INITED) 1257a56bb8a5SSatoshi Asami return (EBUSY); 1258a56bb8a5SSatoshi Asami 1259a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1260a56bb8a5SSatoshi Asami return (EBADF); 1261a56bb8a5SSatoshi Asami 1262b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 1263a56bb8a5SSatoshi Asami return (error); 1264a56bb8a5SSatoshi Asami 1265a56bb8a5SSatoshi Asami /* Fill in some important bits. */ 1266a56bb8a5SSatoshi Asami ccd.ccd_unit = unit; 1267a56bb8a5SSatoshi Asami ccd.ccd_interleave = ccio->ccio_ileave; 1268b8e29b55SSatoshi Asami if (ccd.ccd_interleave == 0 && 1269b8e29b55SSatoshi Asami ((ccio->ccio_flags & CCDF_MIRROR) || 1270b8e29b55SSatoshi Asami (ccio->ccio_flags & CCDF_PARITY))) { 1271b8e29b55SSatoshi Asami printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit); 1272b8e29b55SSatoshi Asami ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY); 1273b8e29b55SSatoshi Asami } 127409b59204SSatoshi Asami if ((ccio->ccio_flags & CCDF_MIRROR) && 127509b59204SSatoshi Asami (ccio->ccio_flags & CCDF_PARITY)) { 127609b59204SSatoshi Asami printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit); 127709b59204SSatoshi Asami ccio->ccio_flags &= ~CCDF_PARITY; 127809b59204SSatoshi Asami } 127909b59204SSatoshi Asami if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) && 12807ecb65faSSatoshi Asami !(ccio->ccio_flags & CCDF_UNIFORM)) { 128109b59204SSatoshi Asami printf("ccd%d: mirror/parity forces uniform flag\n", 128209b59204SSatoshi Asami unit); 12837ecb65faSSatoshi Asami ccio->ccio_flags |= CCDF_UNIFORM; 12847ecb65faSSatoshi Asami } 1285a56bb8a5SSatoshi Asami ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; 1286a56bb8a5SSatoshi Asami 1287a56bb8a5SSatoshi Asami /* 1288a56bb8a5SSatoshi Asami * Allocate space for and copy in the array of 1289a56bb8a5SSatoshi Asami * componet pathnames and device numbers. 1290a56bb8a5SSatoshi Asami */ 1291a56bb8a5SSatoshi Asami cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1292a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 1293a56bb8a5SSatoshi Asami vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1294a56bb8a5SSatoshi Asami M_DEVBUF, M_WAITOK); 1295a56bb8a5SSatoshi Asami 1296a56bb8a5SSatoshi Asami error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1297a56bb8a5SSatoshi Asami ccio->ccio_ndisks * sizeof(char **)); 1298a56bb8a5SSatoshi Asami if (error) { 1299a56bb8a5SSatoshi Asami free(vpp, M_DEVBUF); 1300a56bb8a5SSatoshi Asami free(cpp, M_DEVBUF); 1301a56bb8a5SSatoshi Asami ccdunlock(cs); 1302a56bb8a5SSatoshi Asami return (error); 1303a56bb8a5SSatoshi Asami } 1304a56bb8a5SSatoshi Asami 1305a56bb8a5SSatoshi Asami #ifdef DEBUG 1306a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 1307a56bb8a5SSatoshi Asami for (i = 0; i < ccio->ccio_ndisks; ++i) 1308a56bb8a5SSatoshi Asami printf("ccdioctl: component %d: 0x%x\n", 1309a56bb8a5SSatoshi Asami i, cpp[i]); 1310a56bb8a5SSatoshi Asami #endif 1311a56bb8a5SSatoshi Asami 1312a56bb8a5SSatoshi Asami for (i = 0; i < ccio->ccio_ndisks; ++i) { 1313a56bb8a5SSatoshi Asami #ifdef DEBUG 1314a56bb8a5SSatoshi Asami if (ccddebug & CCDB_INIT) 1315a56bb8a5SSatoshi Asami printf("ccdioctl: lookedup = %d\n", lookedup); 1316a56bb8a5SSatoshi Asami #endif 1317b4e36adfSMatthew Dillon if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) { 1318a56bb8a5SSatoshi Asami for (j = 0; j < lookedup; ++j) 1319a56bb8a5SSatoshi Asami (void)vn_close(vpp[j], FREAD|FWRITE, 1320a56bb8a5SSatoshi Asami p->p_ucred, p); 1321a56bb8a5SSatoshi Asami free(vpp, M_DEVBUF); 1322a56bb8a5SSatoshi Asami free(cpp, M_DEVBUF); 1323a56bb8a5SSatoshi Asami ccdunlock(cs); 1324a56bb8a5SSatoshi Asami return (error); 1325a56bb8a5SSatoshi Asami } 1326a56bb8a5SSatoshi Asami ++lookedup; 1327a56bb8a5SSatoshi Asami } 1328a56bb8a5SSatoshi Asami ccd.ccd_cpp = cpp; 1329a56bb8a5SSatoshi Asami ccd.ccd_vpp = vpp; 1330a56bb8a5SSatoshi Asami ccd.ccd_ndev = ccio->ccio_ndisks; 1331a56bb8a5SSatoshi Asami 1332a56bb8a5SSatoshi Asami /* 1333a56bb8a5SSatoshi Asami * Initialize the ccd. Fills in the softc for us. 1334a56bb8a5SSatoshi Asami */ 1335b4e36adfSMatthew Dillon if ((error = ccdinit(&ccd, cpp, p)) != 0) { 1336a56bb8a5SSatoshi Asami for (j = 0; j < lookedup; ++j) 1337a56bb8a5SSatoshi Asami (void)vn_close(vpp[j], FREAD|FWRITE, 1338a56bb8a5SSatoshi Asami p->p_ucred, p); 1339a56bb8a5SSatoshi Asami bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); 1340a56bb8a5SSatoshi Asami free(vpp, M_DEVBUF); 1341a56bb8a5SSatoshi Asami free(cpp, M_DEVBUF); 1342a56bb8a5SSatoshi Asami ccdunlock(cs); 1343a56bb8a5SSatoshi Asami return (error); 1344a56bb8a5SSatoshi Asami } 1345a56bb8a5SSatoshi Asami 1346a56bb8a5SSatoshi Asami /* 1347a56bb8a5SSatoshi Asami * The ccd has been successfully initialized, so 1348a56bb8a5SSatoshi Asami * we can place it into the array and read the disklabel. 1349a56bb8a5SSatoshi Asami */ 1350a56bb8a5SSatoshi Asami bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1351a56bb8a5SSatoshi Asami ccio->ccio_unit = unit; 1352a56bb8a5SSatoshi Asami ccio->ccio_size = cs->sc_size; 1353a56bb8a5SSatoshi Asami ccdgetdisklabel(dev); 1354a56bb8a5SSatoshi Asami 1355a56bb8a5SSatoshi Asami ccdunlock(cs); 1356a56bb8a5SSatoshi Asami 1357a56bb8a5SSatoshi Asami break; 1358a56bb8a5SSatoshi Asami 1359a56bb8a5SSatoshi Asami case CCDIOCCLR: 1360a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) 1361a56bb8a5SSatoshi Asami return (ENXIO); 1362a56bb8a5SSatoshi Asami 1363a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1364a56bb8a5SSatoshi Asami return (EBADF); 1365a56bb8a5SSatoshi Asami 1366b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 1367a56bb8a5SSatoshi Asami return (error); 1368a56bb8a5SSatoshi Asami 1369af8862e4SPoul-Henning Kamp /* Don't unconfigure if any other partitions are open */ 1370d8594dfbSSatoshi Asami part = ccdpart(dev); 1371a56bb8a5SSatoshi Asami pmask = (1 << part); 1372af8862e4SPoul-Henning Kamp if ((cs->sc_openmask & ~pmask)) { 1373a56bb8a5SSatoshi Asami ccdunlock(cs); 1374a56bb8a5SSatoshi Asami return (EBUSY); 1375a56bb8a5SSatoshi Asami } 1376a56bb8a5SSatoshi Asami 1377a56bb8a5SSatoshi Asami /* 1378a56bb8a5SSatoshi Asami * Free ccd_softc information and clear entry. 1379a56bb8a5SSatoshi Asami */ 1380a56bb8a5SSatoshi Asami 1381a56bb8a5SSatoshi Asami /* Close the components and free their pathnames. */ 1382a56bb8a5SSatoshi Asami for (i = 0; i < cs->sc_nccdisks; ++i) { 1383a56bb8a5SSatoshi Asami /* 1384a56bb8a5SSatoshi Asami * XXX: this close could potentially fail and 1385a56bb8a5SSatoshi Asami * cause Bad Things. Maybe we need to force 1386a56bb8a5SSatoshi Asami * the close to happen? 1387a56bb8a5SSatoshi Asami */ 1388a56bb8a5SSatoshi Asami #ifdef DEBUG 1389a56bb8a5SSatoshi Asami if (ccddebug & CCDB_VNODE) 1390a56bb8a5SSatoshi Asami vprint("CCDIOCCLR: vnode info", 1391a56bb8a5SSatoshi Asami cs->sc_cinfo[i].ci_vp); 1392a56bb8a5SSatoshi Asami #endif 1393a56bb8a5SSatoshi Asami (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1394a56bb8a5SSatoshi Asami p->p_ucred, p); 1395a56bb8a5SSatoshi Asami free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1396a56bb8a5SSatoshi Asami } 1397a56bb8a5SSatoshi Asami 1398a56bb8a5SSatoshi Asami /* Free interleave index. */ 1399a56bb8a5SSatoshi Asami for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1400a56bb8a5SSatoshi Asami free(cs->sc_itable[i].ii_index, M_DEVBUF); 1401a56bb8a5SSatoshi Asami 1402a56bb8a5SSatoshi Asami /* Free component info and interleave table. */ 1403a56bb8a5SSatoshi Asami free(cs->sc_cinfo, M_DEVBUF); 1404a56bb8a5SSatoshi Asami free(cs->sc_itable, M_DEVBUF); 1405a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_INITED; 1406a56bb8a5SSatoshi Asami 1407a56bb8a5SSatoshi Asami /* 1408a56bb8a5SSatoshi Asami * Free ccddevice information and clear entry. 1409a56bb8a5SSatoshi Asami */ 1410a56bb8a5SSatoshi Asami free(ccddevs[unit].ccd_cpp, M_DEVBUF); 1411a56bb8a5SSatoshi Asami free(ccddevs[unit].ccd_vpp, M_DEVBUF); 1412a56bb8a5SSatoshi Asami ccd.ccd_dk = -1; 1413a56bb8a5SSatoshi Asami bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1414a56bb8a5SSatoshi Asami 141521c3b31eSMatt Jacob /* 141621c3b31eSMatt Jacob * And remove the devstat entry. 141721c3b31eSMatt Jacob */ 141821c3b31eSMatt Jacob devstat_remove_entry(&cs->device_stats); 141921c3b31eSMatt Jacob 1420a56bb8a5SSatoshi Asami /* This must be atomic. */ 1421a56bb8a5SSatoshi Asami s = splhigh(); 1422a56bb8a5SSatoshi Asami ccdunlock(cs); 1423a56bb8a5SSatoshi Asami bzero(cs, sizeof(struct ccd_softc)); 1424a56bb8a5SSatoshi Asami splx(s); 1425a56bb8a5SSatoshi Asami 1426a56bb8a5SSatoshi Asami break; 1427a56bb8a5SSatoshi Asami 1428a56bb8a5SSatoshi Asami case DIOCGDINFO: 1429a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) 1430a56bb8a5SSatoshi Asami return (ENXIO); 1431a56bb8a5SSatoshi Asami 14326cc5a722SPoul-Henning Kamp *(struct disklabel *)data = cs->sc_label; 1433a56bb8a5SSatoshi Asami break; 1434a56bb8a5SSatoshi Asami 1435a56bb8a5SSatoshi Asami case DIOCGPART: 1436a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) 1437a56bb8a5SSatoshi Asami return (ENXIO); 1438a56bb8a5SSatoshi Asami 14396cc5a722SPoul-Henning Kamp ((struct partinfo *)data)->disklab = &cs->sc_label; 1440a56bb8a5SSatoshi Asami ((struct partinfo *)data)->part = 14416cc5a722SPoul-Henning Kamp &cs->sc_label.d_partitions[ccdpart(dev)]; 1442a56bb8a5SSatoshi Asami break; 1443a56bb8a5SSatoshi Asami 1444a56bb8a5SSatoshi Asami case DIOCWDINFO: 1445a56bb8a5SSatoshi Asami case DIOCSDINFO: 1446a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) 1447a56bb8a5SSatoshi Asami return (ENXIO); 1448a56bb8a5SSatoshi Asami 1449a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1450a56bb8a5SSatoshi Asami return (EBADF); 1451a56bb8a5SSatoshi Asami 1452b4e36adfSMatthew Dillon if ((error = ccdlock(cs)) != 0) 1453a56bb8a5SSatoshi Asami return (error); 1454a56bb8a5SSatoshi Asami 1455a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_LABELLING; 1456a56bb8a5SSatoshi Asami 14576cc5a722SPoul-Henning Kamp error = setdisklabel(&cs->sc_label, 1458d8594dfbSSatoshi Asami (struct disklabel *)data, 0); 1459a56bb8a5SSatoshi Asami if (error == 0) { 1460a56bb8a5SSatoshi Asami if (cmd == DIOCWDINFO) 1461e2a13e8cSSatoshi Asami error = writedisklabel(CCDLABELDEV(dev), 146249ff4debSPoul-Henning Kamp &cs->sc_label); 1463a56bb8a5SSatoshi Asami } 1464a56bb8a5SSatoshi Asami 1465a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_LABELLING; 1466a56bb8a5SSatoshi Asami 1467a56bb8a5SSatoshi Asami ccdunlock(cs); 1468a56bb8a5SSatoshi Asami 1469a56bb8a5SSatoshi Asami if (error) 1470a56bb8a5SSatoshi Asami return (error); 1471a56bb8a5SSatoshi Asami break; 1472a56bb8a5SSatoshi Asami 1473a56bb8a5SSatoshi Asami case DIOCWLABEL: 1474a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) 1475a56bb8a5SSatoshi Asami return (ENXIO); 1476a56bb8a5SSatoshi Asami 1477a56bb8a5SSatoshi Asami if ((flag & FWRITE) == 0) 1478a56bb8a5SSatoshi Asami return (EBADF); 1479a56bb8a5SSatoshi Asami if (*(int *)data != 0) 1480a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_WLABEL; 1481a56bb8a5SSatoshi Asami else 1482a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_WLABEL; 1483a56bb8a5SSatoshi Asami break; 1484a56bb8a5SSatoshi Asami 1485a56bb8a5SSatoshi Asami default: 1486a56bb8a5SSatoshi Asami return (ENOTTY); 1487a56bb8a5SSatoshi Asami } 1488a56bb8a5SSatoshi Asami 1489a56bb8a5SSatoshi Asami return (0); 1490a56bb8a5SSatoshi Asami } 1491a56bb8a5SSatoshi Asami 1492e2738b4fSPoul-Henning Kamp static int 1493a56bb8a5SSatoshi Asami ccdsize(dev) 1494a56bb8a5SSatoshi Asami dev_t dev; 1495a56bb8a5SSatoshi Asami { 1496a56bb8a5SSatoshi Asami struct ccd_softc *cs; 1497a56bb8a5SSatoshi Asami int part, size; 1498a56bb8a5SSatoshi Asami 1499af8862e4SPoul-Henning Kamp if (ccdopen(dev, 0, S_IFCHR, curproc)) 1500a56bb8a5SSatoshi Asami return (-1); 1501a56bb8a5SSatoshi Asami 1502a56bb8a5SSatoshi Asami cs = &ccd_softc[ccdunit(dev)]; 1503d8594dfbSSatoshi Asami part = ccdpart(dev); 1504a56bb8a5SSatoshi Asami 1505a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_INITED) == 0) 1506a56bb8a5SSatoshi Asami return (-1); 1507a56bb8a5SSatoshi Asami 15086cc5a722SPoul-Henning Kamp if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP) 1509a56bb8a5SSatoshi Asami size = -1; 1510a56bb8a5SSatoshi Asami else 15116cc5a722SPoul-Henning Kamp size = cs->sc_label.d_partitions[part].p_size; 1512a56bb8a5SSatoshi Asami 1513af8862e4SPoul-Henning Kamp if (ccdclose(dev, 0, S_IFCHR, curproc)) 1514a56bb8a5SSatoshi Asami return (-1); 1515a56bb8a5SSatoshi Asami 1516a56bb8a5SSatoshi Asami return (size); 1517a56bb8a5SSatoshi Asami } 1518a56bb8a5SSatoshi Asami 1519e2738b4fSPoul-Henning Kamp static int 1520e2a13e8cSSatoshi Asami ccddump(dev) 1521a56bb8a5SSatoshi Asami dev_t dev; 1522a56bb8a5SSatoshi Asami { 1523a56bb8a5SSatoshi Asami 1524a56bb8a5SSatoshi Asami /* Not implemented. */ 1525a56bb8a5SSatoshi Asami return ENXIO; 1526a56bb8a5SSatoshi Asami } 1527a56bb8a5SSatoshi Asami 1528a56bb8a5SSatoshi Asami /* 1529a56bb8a5SSatoshi Asami * Lookup the provided name in the filesystem. If the file exists, 1530a56bb8a5SSatoshi Asami * is a valid block device, and isn't being used by anyone else, 1531a56bb8a5SSatoshi Asami * set *vpp to the file's vnode. 1532a56bb8a5SSatoshi Asami */ 1533a56bb8a5SSatoshi Asami static int 1534a56bb8a5SSatoshi Asami ccdlookup(path, p, vpp) 1535a56bb8a5SSatoshi Asami char *path; 1536a56bb8a5SSatoshi Asami struct proc *p; 1537a56bb8a5SSatoshi Asami struct vnode **vpp; /* result */ 1538a56bb8a5SSatoshi Asami { 1539a56bb8a5SSatoshi Asami struct nameidata nd; 1540a56bb8a5SSatoshi Asami struct vnode *vp; 1541a56bb8a5SSatoshi Asami int error; 1542a56bb8a5SSatoshi Asami 1543a56bb8a5SSatoshi Asami NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1544b4e36adfSMatthew Dillon if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 1545a56bb8a5SSatoshi Asami #ifdef DEBUG 1546a56bb8a5SSatoshi Asami if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1547a56bb8a5SSatoshi Asami printf("ccdlookup: vn_open error = %d\n", error); 1548a56bb8a5SSatoshi Asami #endif 1549a56bb8a5SSatoshi Asami return (error); 1550a56bb8a5SSatoshi Asami } 1551a56bb8a5SSatoshi Asami vp = nd.ni_vp; 1552a56bb8a5SSatoshi Asami 1553a56bb8a5SSatoshi Asami if (vp->v_usecount > 1) { 1554762e6b85SEivind Eklund error = EBUSY; 1555762e6b85SEivind Eklund goto bad; 1556a56bb8a5SSatoshi Asami } 1557a56bb8a5SSatoshi Asami 1558ba4ad1fcSPoul-Henning Kamp if (!vn_isdisk(vp, &error)) 1559762e6b85SEivind Eklund goto bad; 1560a56bb8a5SSatoshi Asami 1561a56bb8a5SSatoshi Asami #ifdef DEBUG 1562a56bb8a5SSatoshi Asami if (ccddebug & CCDB_VNODE) 1563a56bb8a5SSatoshi Asami vprint("ccdlookup: vnode info", vp); 1564a56bb8a5SSatoshi Asami #endif 1565a56bb8a5SSatoshi Asami 156606bcc9e5SMike Pritchard VOP_UNLOCK(vp, 0, p); 1567762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 1568a56bb8a5SSatoshi Asami *vpp = vp; 1569a56bb8a5SSatoshi Asami return (0); 1570762e6b85SEivind Eklund bad: 1571762e6b85SEivind Eklund VOP_UNLOCK(vp, 0, p); 1572762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 1573762e6b85SEivind Eklund /* vn_close does vrele() for vp */ 1574762e6b85SEivind Eklund (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1575762e6b85SEivind Eklund return (error); 1576a56bb8a5SSatoshi Asami } 1577a56bb8a5SSatoshi Asami 1578a56bb8a5SSatoshi Asami /* 1579a56bb8a5SSatoshi Asami * Read the disklabel from the ccd. If one is not present, fake one 1580a56bb8a5SSatoshi Asami * up. 1581a56bb8a5SSatoshi Asami */ 1582a56bb8a5SSatoshi Asami static void 1583a56bb8a5SSatoshi Asami ccdgetdisklabel(dev) 1584a56bb8a5SSatoshi Asami dev_t dev; 1585a56bb8a5SSatoshi Asami { 1586a56bb8a5SSatoshi Asami int unit = ccdunit(dev); 1587a56bb8a5SSatoshi Asami struct ccd_softc *cs = &ccd_softc[unit]; 1588a56bb8a5SSatoshi Asami char *errstring; 15896cc5a722SPoul-Henning Kamp struct disklabel *lp = &cs->sc_label; 1590a56bb8a5SSatoshi Asami struct ccdgeom *ccg = &cs->sc_geom; 1591a56bb8a5SSatoshi Asami 1592a56bb8a5SSatoshi Asami bzero(lp, sizeof(*lp)); 1593a56bb8a5SSatoshi Asami 1594a56bb8a5SSatoshi Asami lp->d_secperunit = cs->sc_size; 1595a56bb8a5SSatoshi Asami lp->d_secsize = ccg->ccg_secsize; 1596a56bb8a5SSatoshi Asami lp->d_nsectors = ccg->ccg_nsectors; 1597a56bb8a5SSatoshi Asami lp->d_ntracks = ccg->ccg_ntracks; 1598a56bb8a5SSatoshi Asami lp->d_ncylinders = ccg->ccg_ncylinders; 1599a56bb8a5SSatoshi Asami lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1600a56bb8a5SSatoshi Asami 1601a56bb8a5SSatoshi Asami strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1602a56bb8a5SSatoshi Asami lp->d_type = DTYPE_CCD; 1603a56bb8a5SSatoshi Asami strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1604a56bb8a5SSatoshi Asami lp->d_rpm = 3600; 1605a56bb8a5SSatoshi Asami lp->d_interleave = 1; 1606a56bb8a5SSatoshi Asami lp->d_flags = 0; 1607a56bb8a5SSatoshi Asami 1608a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_offset = 0; 1609a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1610a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1611a56bb8a5SSatoshi Asami lp->d_npartitions = RAW_PART + 1; 1612a56bb8a5SSatoshi Asami 1613d8594dfbSSatoshi Asami lp->d_bbsize = BBSIZE; /* XXX */ 1614d8594dfbSSatoshi Asami lp->d_sbsize = SBSIZE; /* XXX */ 1615d8594dfbSSatoshi Asami 1616a56bb8a5SSatoshi Asami lp->d_magic = DISKMAGIC; 1617a56bb8a5SSatoshi Asami lp->d_magic2 = DISKMAGIC; 16186cc5a722SPoul-Henning Kamp lp->d_checksum = dkcksum(&cs->sc_label); 1619a56bb8a5SSatoshi Asami 1620a56bb8a5SSatoshi Asami /* 1621a56bb8a5SSatoshi Asami * Call the generic disklabel extraction routine. 1622a56bb8a5SSatoshi Asami */ 162349ff4debSPoul-Henning Kamp errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label); 162449ff4debSPoul-Henning Kamp if (errstring != NULL) 1625a56bb8a5SSatoshi Asami ccdmakedisklabel(cs); 1626a56bb8a5SSatoshi Asami 1627a56bb8a5SSatoshi Asami #ifdef DEBUG 1628a56bb8a5SSatoshi Asami /* It's actually extremely common to have unlabeled ccds. */ 1629a56bb8a5SSatoshi Asami if (ccddebug & CCDB_LABEL) 1630a56bb8a5SSatoshi Asami if (errstring != NULL) 1631a56bb8a5SSatoshi Asami printf("ccd%d: %s\n", unit, errstring); 1632a56bb8a5SSatoshi Asami #endif 1633a56bb8a5SSatoshi Asami } 1634a56bb8a5SSatoshi Asami 1635a56bb8a5SSatoshi Asami /* 1636a56bb8a5SSatoshi Asami * Take care of things one might want to take care of in the event 1637a56bb8a5SSatoshi Asami * that a disklabel isn't present. 1638a56bb8a5SSatoshi Asami */ 1639a56bb8a5SSatoshi Asami static void 1640a56bb8a5SSatoshi Asami ccdmakedisklabel(cs) 1641a56bb8a5SSatoshi Asami struct ccd_softc *cs; 1642a56bb8a5SSatoshi Asami { 16436cc5a722SPoul-Henning Kamp struct disklabel *lp = &cs->sc_label; 1644a56bb8a5SSatoshi Asami 1645a56bb8a5SSatoshi Asami /* 1646a56bb8a5SSatoshi Asami * For historical reasons, if there's no disklabel present 1647a56bb8a5SSatoshi Asami * the raw partition must be marked FS_BSDFFS. 1648a56bb8a5SSatoshi Asami */ 1649a56bb8a5SSatoshi Asami lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1650a56bb8a5SSatoshi Asami 1651a56bb8a5SSatoshi Asami strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1652a56bb8a5SSatoshi Asami } 1653a56bb8a5SSatoshi Asami 1654a56bb8a5SSatoshi Asami /* 1655a56bb8a5SSatoshi Asami * Wait interruptibly for an exclusive lock. 1656a56bb8a5SSatoshi Asami * 1657a56bb8a5SSatoshi Asami * XXX 1658a56bb8a5SSatoshi Asami * Several drivers do this; it should be abstracted and made MP-safe. 1659a56bb8a5SSatoshi Asami */ 1660a56bb8a5SSatoshi Asami static int 1661a56bb8a5SSatoshi Asami ccdlock(cs) 1662a56bb8a5SSatoshi Asami struct ccd_softc *cs; 1663a56bb8a5SSatoshi Asami { 1664a56bb8a5SSatoshi Asami int error; 1665a56bb8a5SSatoshi Asami 1666a56bb8a5SSatoshi Asami while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1667a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_WANTED; 1668a56bb8a5SSatoshi Asami if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1669a56bb8a5SSatoshi Asami return (error); 1670a56bb8a5SSatoshi Asami } 1671a56bb8a5SSatoshi Asami cs->sc_flags |= CCDF_LOCKED; 1672a56bb8a5SSatoshi Asami return (0); 1673a56bb8a5SSatoshi Asami } 1674a56bb8a5SSatoshi Asami 1675a56bb8a5SSatoshi Asami /* 1676a56bb8a5SSatoshi Asami * Unlock and wake up any waiters. 1677a56bb8a5SSatoshi Asami */ 1678a56bb8a5SSatoshi Asami static void 1679a56bb8a5SSatoshi Asami ccdunlock(cs) 1680a56bb8a5SSatoshi Asami struct ccd_softc *cs; 1681a56bb8a5SSatoshi Asami { 1682a56bb8a5SSatoshi Asami 1683a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_LOCKED; 1684a56bb8a5SSatoshi Asami if ((cs->sc_flags & CCDF_WANTED) != 0) { 1685a56bb8a5SSatoshi Asami cs->sc_flags &= ~CCDF_WANTED; 1686a56bb8a5SSatoshi Asami wakeup(cs); 1687a56bb8a5SSatoshi Asami } 1688a56bb8a5SSatoshi Asami } 1689a56bb8a5SSatoshi Asami 1690a56bb8a5SSatoshi Asami #ifdef DEBUG 1691a56bb8a5SSatoshi Asami static void 1692a56bb8a5SSatoshi Asami printiinfo(ii) 1693a56bb8a5SSatoshi Asami struct ccdiinfo *ii; 1694a56bb8a5SSatoshi Asami { 16951464240eSMatthew Dillon int ix, i; 1696a56bb8a5SSatoshi Asami 1697a56bb8a5SSatoshi Asami for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1698a56bb8a5SSatoshi Asami printf(" itab[%d]: #dk %d sblk %d soff %d", 1699a56bb8a5SSatoshi Asami ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1700a56bb8a5SSatoshi Asami for (i = 0; i < ii->ii_ndisk; i++) 1701a56bb8a5SSatoshi Asami printf(" %d", ii->ii_index[i]); 1702a56bb8a5SSatoshi Asami printf("\n"); 1703a56bb8a5SSatoshi Asami } 1704a56bb8a5SSatoshi Asami } 1705a56bb8a5SSatoshi Asami #endif 1706d8594dfbSSatoshi Asami 1707d8594dfbSSatoshi Asami 1708d8594dfbSSatoshi Asami /* Local Variables: */ 1709d8594dfbSSatoshi Asami /* c-argdecl-indent: 8 */ 171009b59204SSatoshi Asami /* c-continued-statement-offset: 8 */ 1711d8594dfbSSatoshi Asami /* c-indent-level: 8 */ 1712d8594dfbSSatoshi Asami /* End: */ 1713