1 1.193 mlelstv /* $NetBSD: ccd.c,v 1.193 2025/08/17 22:04:34 mlelstv Exp $ */ 2 1.11 thorpej 3 1.28 thorpej /*- 4 1.133 ad * Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc. 5 1.11 thorpej * All rights reserved. 6 1.11 thorpej * 7 1.28 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.133 ad * by Jason R. Thorpe, and by Andrew Doran. 9 1.28 thorpej * 10 1.11 thorpej * Redistribution and use in source and binary forms, with or without 11 1.11 thorpej * modification, are permitted provided that the following conditions 12 1.11 thorpej * are met: 13 1.11 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.11 thorpej * notice, this list of conditions and the following disclaimer. 15 1.11 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.11 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.11 thorpej * documentation and/or other materials provided with the distribution. 18 1.11 thorpej * 19 1.28 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.28 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.28 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.45 jtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.45 jtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.28 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.28 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.28 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.28 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.28 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.28 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.11 thorpej */ 31 1.2 cgd 32 1.1 hpeyerl /* 33 1.138 rmind * Copyright (c) 1988 University of Utah. 34 1.3 hpeyerl * Copyright (c) 1990, 1993 35 1.3 hpeyerl * The Regents of the University of California. All rights reserved. 36 1.1 hpeyerl * 37 1.1 hpeyerl * This code is derived from software contributed to Berkeley by 38 1.1 hpeyerl * the Systems Programming Group of the University of Utah Computer 39 1.1 hpeyerl * Science Department. 40 1.1 hpeyerl * 41 1.1 hpeyerl * Redistribution and use in source and binary forms, with or without 42 1.1 hpeyerl * modification, are permitted provided that the following conditions 43 1.1 hpeyerl * are met: 44 1.1 hpeyerl * 1. Redistributions of source code must retain the above copyright 45 1.1 hpeyerl * notice, this list of conditions and the following disclaimer. 46 1.1 hpeyerl * 2. Redistributions in binary form must reproduce the above copyright 47 1.1 hpeyerl * notice, this list of conditions and the following disclaimer in the 48 1.1 hpeyerl * documentation and/or other materials provided with the distribution. 49 1.91 agc * 3. Neither the name of the University nor the names of its contributors 50 1.91 agc * may be used to endorse or promote products derived from this software 51 1.91 agc * without specific prior written permission. 52 1.91 agc * 53 1.91 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 1.91 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 1.91 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 1.91 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 1.91 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 1.91 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 1.91 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 1.91 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 1.91 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 1.91 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 1.91 agc * SUCH DAMAGE. 64 1.91 agc * 65 1.189 riastrad * from: Utah $Hdr: cd.c 1.6 90/11/28$ 66 1.91 agc * 67 1.91 agc * @(#)cd.c 8.2 (Berkeley) 11/16/93 68 1.91 agc */ 69 1.91 agc 70 1.91 agc /* 71 1.1 hpeyerl * "Concatenated" disk driver. 72 1.11 thorpej * 73 1.133 ad * Notes on concurrency: 74 1.133 ad * 75 1.133 ad * => sc_dvlock serializes access to the device nodes, excluding block I/O. 76 1.133 ad * 77 1.133 ad * => sc_iolock serializes access to (sc_flags & CCDF_INITED), disk stats, 78 1.133 ad * sc_stop, sc_bufq and b_resid from master buffers. 79 1.133 ad * 80 1.133 ad * => a combination of CCDF_INITED, sc_inflight, and sc_iolock is used to 81 1.133 ad * serialize I/O and configuration changes. 82 1.133 ad * 83 1.133 ad * => the in-core disk label does not change while the device is open. 84 1.133 ad * 85 1.133 ad * On memory consumption: ccd fans out I/O requests and so needs to 86 1.133 ad * allocate memory. If the system is desperately low on memory, we 87 1.133 ad * single thread I/O. 88 1.1 hpeyerl */ 89 1.74 lukem 90 1.74 lukem #include <sys/cdefs.h> 91 1.193 mlelstv __KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.193 2025/08/17 22:04:34 mlelstv Exp $"); 92 1.1 hpeyerl 93 1.1 hpeyerl #include <sys/param.h> 94 1.1 hpeyerl #include <sys/systm.h> 95 1.133 ad #include <sys/kernel.h> 96 1.3 hpeyerl #include <sys/proc.h> 97 1.1 hpeyerl #include <sys/errno.h> 98 1.1 hpeyerl #include <sys/buf.h> 99 1.133 ad #include <sys/kmem.h> 100 1.63 thorpej #include <sys/pool.h> 101 1.140 jruoho #include <sys/module.h> 102 1.11 thorpej #include <sys/namei.h> 103 1.3 hpeyerl #include <sys/stat.h> 104 1.3 hpeyerl #include <sys/ioctl.h> 105 1.3 hpeyerl #include <sys/disklabel.h> 106 1.11 thorpej #include <sys/device.h> 107 1.11 thorpej #include <sys/disk.h> 108 1.11 thorpej #include <sys/syslog.h> 109 1.3 hpeyerl #include <sys/fcntl.h> 110 1.11 thorpej #include <sys/vnode.h> 111 1.31 christos #include <sys/conf.h> 112 1.117 ad #include <sys/mutex.h> 113 1.56 thorpej #include <sys/queue.h> 114 1.110 elad #include <sys/kauth.h> 115 1.133 ad #include <sys/kthread.h> 116 1.133 ad #include <sys/bufq.h> 117 1.144 christos #include <sys/sysctl.h> 118 1.177 pgoyette #include <sys/compat_stub.h> 119 1.1 hpeyerl 120 1.135 uebayasi #include <uvm/uvm_extern.h> 121 1.135 uebayasi 122 1.1 hpeyerl #include <dev/ccdvar.h> 123 1.113 christos #include <dev/dkvar.h> 124 1.1 hpeyerl 125 1.149 hannken #include <miscfs/specfs/specdev.h> /* for v_rdev */ 126 1.149 hannken 127 1.165 christos #include "ioconf.h" 128 1.165 christos 129 1.11 thorpej #if defined(CCDDEBUG) && !defined(DEBUG) 130 1.11 thorpej #define DEBUG 131 1.11 thorpej #endif 132 1.11 thorpej 133 1.1 hpeyerl #ifdef DEBUG 134 1.3 hpeyerl #define CCDB_FOLLOW 0x01 135 1.3 hpeyerl #define CCDB_INIT 0x02 136 1.3 hpeyerl #define CCDB_IO 0x04 137 1.11 thorpej #define CCDB_LABEL 0x08 138 1.11 thorpej #define CCDB_VNODE 0x10 139 1.24 thorpej int ccddebug = 0x00; 140 1.1 hpeyerl #endif 141 1.1 hpeyerl 142 1.6 cgd #define ccdunit(x) DISKUNIT(x) 143 1.6 cgd 144 1.6 cgd struct ccdbuf { 145 1.6 cgd struct buf cb_buf; /* new I/O buf */ 146 1.6 cgd struct buf *cb_obp; /* ptr. to original I/O buf */ 147 1.59 thorpej struct ccd_softc *cb_sc; /* pointer to ccd softc */ 148 1.6 cgd int cb_comp; /* target component */ 149 1.56 thorpej SIMPLEQ_ENTRY(ccdbuf) cb_q; /* fifo of component buffers */ 150 1.38 thorpej }; 151 1.24 thorpej 152 1.63 thorpej /* component buffer pool */ 153 1.133 ad static pool_cache_t ccd_cache; 154 1.63 thorpej 155 1.190 hannken #define CCD_GETBUF(wait) pool_cache_get(ccd_cache, wait) 156 1.133 ad #define CCD_PUTBUF(cbp) pool_cache_put(ccd_cache, cbp) 157 1.1 hpeyerl 158 1.11 thorpej #define CCDLABELDEV(dev) \ 159 1.11 thorpej (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART)) 160 1.1 hpeyerl 161 1.11 thorpej /* called by main() at boot time */ 162 1.159 christos void ccddetach(void); 163 1.11 thorpej 164 1.11 thorpej /* called by biodone() at interrupt time */ 165 1.97 thorpej static void ccdiodone(struct buf *); 166 1.11 thorpej 167 1.97 thorpej static void ccdinterleave(struct ccd_softc *); 168 1.97 thorpej static int ccdinit(struct ccd_softc *, char **, struct vnode **, 169 1.107 christos struct lwp *); 170 1.97 thorpej static struct ccdbuf *ccdbuffer(struct ccd_softc *, struct buf *, 171 1.190 hannken daddr_t, void *, long, int); 172 1.97 thorpej static void ccdgetdefaultlabel(struct ccd_softc *, struct disklabel *); 173 1.97 thorpej static void ccdgetdisklabel(dev_t); 174 1.97 thorpej static void ccdmakedisklabel(struct ccd_softc *); 175 1.190 hannken static int ccdstart(struct ccd_softc *, struct buf *, int); 176 1.133 ad static void ccdthread(void *); 177 1.97 thorpej 178 1.97 thorpej static dev_type_open(ccdopen); 179 1.97 thorpej static dev_type_close(ccdclose); 180 1.97 thorpej static dev_type_read(ccdread); 181 1.97 thorpej static dev_type_write(ccdwrite); 182 1.97 thorpej static dev_type_ioctl(ccdioctl); 183 1.97 thorpej static dev_type_strategy(ccdstrategy); 184 1.97 thorpej static dev_type_size(ccdsize); 185 1.78 gehenna 186 1.78 gehenna const struct bdevsw ccd_bdevsw = { 187 1.133 ad .d_open = ccdopen, 188 1.133 ad .d_close = ccdclose, 189 1.133 ad .d_strategy = ccdstrategy, 190 1.133 ad .d_ioctl = ccdioctl, 191 1.133 ad .d_dump = nodump, 192 1.133 ad .d_psize = ccdsize, 193 1.150 dholland .d_discard = nodiscard, 194 1.133 ad .d_flag = D_DISK | D_MPSAFE 195 1.78 gehenna }; 196 1.78 gehenna 197 1.78 gehenna const struct cdevsw ccd_cdevsw = { 198 1.133 ad .d_open = ccdopen, 199 1.133 ad .d_close = ccdclose, 200 1.133 ad .d_read = ccdread, 201 1.133 ad .d_write = ccdwrite, 202 1.133 ad .d_ioctl = ccdioctl, 203 1.133 ad .d_stop = nostop, 204 1.133 ad .d_tty = notty, 205 1.133 ad .d_poll = nopoll, 206 1.133 ad .d_mmap = nommap, 207 1.133 ad .d_kqfilter = nokqfilter, 208 1.151 dholland .d_discard = nodiscard, 209 1.133 ad .d_flag = D_DISK | D_MPSAFE 210 1.78 gehenna }; 211 1.3 hpeyerl 212 1.185 mlelstv static const struct dkdriver ccddkdriver = { 213 1.185 mlelstv .d_strategy = ccdstrategy, 214 1.185 mlelstv .d_minphys = minphys 215 1.185 mlelstv }; 216 1.185 mlelstv 217 1.11 thorpej #ifdef DEBUG 218 1.97 thorpej static void printiinfo(struct ccdiinfo *); 219 1.11 thorpej #endif 220 1.11 thorpej 221 1.144 christos static LIST_HEAD(, ccd_softc) ccds = LIST_HEAD_INITIALIZER(ccds); 222 1.144 christos static kmutex_t ccd_lock; 223 1.144 christos 224 1.167 pgoyette SYSCTL_SETUP_PROTO(sysctl_kern_ccd_setup); 225 1.167 pgoyette 226 1.144 christos static struct ccd_softc * 227 1.144 christos ccdcreate(int unit) { 228 1.144 christos struct ccd_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); 229 1.172 chs 230 1.144 christos /* Initialize per-softc structures. */ 231 1.144 christos snprintf(sc->sc_xname, sizeof(sc->sc_xname), "ccd%d", unit); 232 1.163 christos sc->sc_unit = unit; 233 1.144 christos mutex_init(&sc->sc_dvlock, MUTEX_DEFAULT, IPL_NONE); 234 1.144 christos sc->sc_iolock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); 235 1.144 christos cv_init(&sc->sc_stop, "ccdstop"); 236 1.144 christos cv_init(&sc->sc_push, "ccdthr"); 237 1.185 mlelstv disk_init(&sc->sc_dkdev, sc->sc_xname, &ccddkdriver); 238 1.144 christos return sc; 239 1.144 christos } 240 1.144 christos 241 1.144 christos static void 242 1.144 christos ccddestroy(struct ccd_softc *sc) { 243 1.144 christos mutex_obj_free(sc->sc_iolock); 244 1.148 joerg mutex_exit(&sc->sc_dvlock); 245 1.144 christos mutex_destroy(&sc->sc_dvlock); 246 1.144 christos cv_destroy(&sc->sc_stop); 247 1.144 christos cv_destroy(&sc->sc_push); 248 1.144 christos disk_destroy(&sc->sc_dkdev); 249 1.144 christos kmem_free(sc, sizeof(*sc)); 250 1.144 christos } 251 1.144 christos 252 1.144 christos static struct ccd_softc * 253 1.158 christos ccdget(int unit, int make) { 254 1.144 christos struct ccd_softc *sc; 255 1.144 christos if (unit < 0) { 256 1.144 christos #ifdef DIAGNOSTIC 257 1.144 christos panic("%s: unit %d!", __func__, unit); 258 1.144 christos #endif 259 1.144 christos return NULL; 260 1.144 christos } 261 1.144 christos mutex_enter(&ccd_lock); 262 1.144 christos LIST_FOREACH(sc, &ccds, sc_link) { 263 1.144 christos if (sc->sc_unit == unit) { 264 1.144 christos mutex_exit(&ccd_lock); 265 1.144 christos return sc; 266 1.144 christos } 267 1.144 christos } 268 1.144 christos mutex_exit(&ccd_lock); 269 1.158 christos if (!make) 270 1.158 christos return NULL; 271 1.144 christos if ((sc = ccdcreate(unit)) == NULL) 272 1.144 christos return NULL; 273 1.144 christos mutex_enter(&ccd_lock); 274 1.144 christos LIST_INSERT_HEAD(&ccds, sc, sc_link); 275 1.144 christos mutex_exit(&ccd_lock); 276 1.144 christos return sc; 277 1.144 christos } 278 1.144 christos 279 1.164 skrll static void 280 1.144 christos ccdput(struct ccd_softc *sc) { 281 1.144 christos mutex_enter(&ccd_lock); 282 1.144 christos LIST_REMOVE(sc, sc_link); 283 1.144 christos mutex_exit(&ccd_lock); 284 1.144 christos ccddestroy(sc); 285 1.144 christos } 286 1.1 hpeyerl 287 1.3 hpeyerl /* 288 1.11 thorpej * Called by main() during pseudo-device attachment. All we need 289 1.11 thorpej * to do is allocate enough space for devices to be configured later. 290 1.1 hpeyerl */ 291 1.1 hpeyerl void 292 1.97 thorpej ccdattach(int num) 293 1.3 hpeyerl { 294 1.144 christos mutex_init(&ccd_lock, MUTEX_DEFAULT, IPL_NONE); 295 1.57 thorpej 296 1.63 thorpej /* Initialize the component buffer pool. */ 297 1.133 ad ccd_cache = pool_cache_init(sizeof(struct ccdbuf), 0, 298 1.133 ad 0, 0, "ccdbuf", NULL, IPL_BIO, NULL, NULL, NULL); 299 1.1 hpeyerl } 300 1.1 hpeyerl 301 1.159 christos void 302 1.159 christos ccddetach(void) 303 1.159 christos { 304 1.159 christos pool_cache_destroy(ccd_cache); 305 1.159 christos mutex_destroy(&ccd_lock); 306 1.159 christos } 307 1.159 christos 308 1.11 thorpej static int 309 1.97 thorpej ccdinit(struct ccd_softc *cs, char **cpaths, struct vnode **vpp, 310 1.107 christos struct lwp *l) 311 1.1 hpeyerl { 312 1.68 augustss struct ccdcinfo *ci = NULL; 313 1.68 augustss int ix; 314 1.11 thorpej struct ccdgeom *ccg = &cs->sc_geom; 315 1.111 christos char *tmppath; 316 1.67 enami int error, path_alloced; 317 1.143 christos uint64_t psize, minsize; 318 1.143 christos unsigned secsize, maxsecsize; 319 1.156 jnemeth struct disk_geom *dg; 320 1.1 hpeyerl 321 1.1 hpeyerl #ifdef DEBUG 322 1.3 hpeyerl if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 323 1.59 thorpej printf("%s: ccdinit\n", cs->sc_xname); 324 1.1 hpeyerl #endif 325 1.11 thorpej 326 1.11 thorpej /* Allocate space for the component info. */ 327 1.133 ad cs->sc_cinfo = kmem_alloc(cs->sc_nccdisks * sizeof(*cs->sc_cinfo), 328 1.133 ad KM_SLEEP); 329 1.133 ad tmppath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 330 1.111 christos 331 1.57 thorpej cs->sc_size = 0; 332 1.57 thorpej 333 1.1 hpeyerl /* 334 1.1 hpeyerl * Verify that each component piece exists and record 335 1.1 hpeyerl * relevant information about it. 336 1.1 hpeyerl */ 337 1.11 thorpej maxsecsize = 0; 338 1.1 hpeyerl minsize = 0; 339 1.67 enami for (ix = 0, path_alloced = 0; ix < cs->sc_nccdisks; ix++) { 340 1.1 hpeyerl ci = &cs->sc_cinfo[ix]; 341 1.57 thorpej ci->ci_vp = vpp[ix]; 342 1.11 thorpej 343 1.11 thorpej /* 344 1.11 thorpej * Copy in the pathname of the component. 345 1.11 thorpej */ 346 1.141 joerg memset(tmppath, 0, MAXPATHLEN); /* sanity */ 347 1.29 christos error = copyinstr(cpaths[ix], tmppath, 348 1.29 christos MAXPATHLEN, &ci->ci_pathlen); 349 1.133 ad if (ci->ci_pathlen == 0) 350 1.133 ad error = EINVAL; 351 1.29 christos if (error) { 352 1.11 thorpej #ifdef DEBUG 353 1.11 thorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 354 1.35 christos printf("%s: can't copy path, error = %d\n", 355 1.23 thorpej cs->sc_xname, error); 356 1.11 thorpej #endif 357 1.67 enami goto out; 358 1.11 thorpej } 359 1.133 ad ci->ci_path = kmem_alloc(ci->ci_pathlen, KM_SLEEP); 360 1.72 thorpej memcpy(ci->ci_path, tmppath, ci->ci_pathlen); 361 1.67 enami path_alloced++; 362 1.11 thorpej 363 1.11 thorpej /* 364 1.11 thorpej * XXX: Cache the component's dev_t. 365 1.11 thorpej */ 366 1.149 hannken ci->ci_dev = vpp[ix]->v_rdev; 367 1.11 thorpej 368 1.3 hpeyerl /* 369 1.11 thorpej * Get partition information for the component. 370 1.3 hpeyerl */ 371 1.143 christos error = getdisksize(vpp[ix], &psize, &secsize); 372 1.29 christos if (error) { 373 1.11 thorpej #ifdef DEBUG 374 1.11 thorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 375 1.143 christos printf("%s: %s: disksize failed, error = %d\n", 376 1.23 thorpej cs->sc_xname, ci->ci_path, error); 377 1.11 thorpej #endif 378 1.67 enami goto out; 379 1.11 thorpej } 380 1.69 enami 381 1.11 thorpej /* 382 1.11 thorpej * Calculate the size, truncating to an interleave 383 1.11 thorpej * boundary if necessary. 384 1.11 thorpej */ 385 1.143 christos maxsecsize = secsize > maxsecsize ? secsize : maxsecsize; 386 1.1 hpeyerl if (cs->sc_ileave > 1) 387 1.143 christos psize -= psize % cs->sc_ileave; 388 1.11 thorpej 389 1.143 christos if (psize == 0) { 390 1.11 thorpej #ifdef DEBUG 391 1.11 thorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 392 1.35 christos printf("%s: %s: size == 0\n", 393 1.23 thorpej cs->sc_xname, ci->ci_path); 394 1.11 thorpej #endif 395 1.67 enami error = ENODEV; 396 1.67 enami goto out; 397 1.3 hpeyerl } 398 1.11 thorpej 399 1.143 christos if (minsize == 0 || psize < minsize) 400 1.143 christos minsize = psize; 401 1.143 christos ci->ci_size = psize; 402 1.143 christos cs->sc_size += psize; 403 1.1 hpeyerl } 404 1.11 thorpej 405 1.11 thorpej /* 406 1.11 thorpej * Don't allow the interleave to be smaller than 407 1.11 thorpej * the biggest component sector. 408 1.11 thorpej */ 409 1.11 thorpej if ((cs->sc_ileave > 0) && 410 1.11 thorpej (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 411 1.11 thorpej #ifdef DEBUG 412 1.11 thorpej if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 413 1.35 christos printf("%s: interleave must be at least %d\n", 414 1.23 thorpej cs->sc_xname, (maxsecsize / DEV_BSIZE)); 415 1.11 thorpej #endif 416 1.67 enami error = EINVAL; 417 1.67 enami goto out; 418 1.11 thorpej } 419 1.11 thorpej 420 1.1 hpeyerl /* 421 1.1 hpeyerl * If uniform interleave is desired set all sizes to that of 422 1.1 hpeyerl * the smallest component. 423 1.1 hpeyerl */ 424 1.57 thorpej if (cs->sc_flags & CCDF_UNIFORM) { 425 1.1 hpeyerl for (ci = cs->sc_cinfo; 426 1.1 hpeyerl ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 427 1.1 hpeyerl ci->ci_size = minsize; 428 1.24 thorpej 429 1.53 thorpej cs->sc_size = cs->sc_nccdisks * minsize; 430 1.1 hpeyerl } 431 1.11 thorpej 432 1.11 thorpej /* 433 1.11 thorpej * Construct the interleave table. 434 1.11 thorpej */ 435 1.57 thorpej ccdinterleave(cs); 436 1.11 thorpej 437 1.1 hpeyerl /* 438 1.11 thorpej * Create pseudo-geometry based on 1MB cylinders. It's 439 1.11 thorpej * pretty close. 440 1.1 hpeyerl */ 441 1.11 thorpej ccg->ccg_secsize = DEV_BSIZE; 442 1.19 thorpej ccg->ccg_ntracks = 1; 443 1.11 thorpej ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); 444 1.11 thorpej ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 445 1.156 jnemeth 446 1.156 jnemeth dg = &cs->sc_dkdev.dk_geom; 447 1.156 jnemeth memset(dg, 0, sizeof(*dg)); 448 1.158 christos dg->dg_secperunit = cs->sc_size; 449 1.158 christos dg->dg_secsize = ccg->ccg_secsize; 450 1.158 christos dg->dg_nsectors = ccg->ccg_nsectors; 451 1.158 christos dg->dg_ntracks = ccg->ccg_ntracks; 452 1.158 christos dg->dg_ncylinders = ccg->ccg_ncylinders; 453 1.164 skrll 454 1.152 sborrill if (cs->sc_ileave > 0) 455 1.152 sborrill aprint_normal("%s: Interleaving %d component%s " 456 1.152 sborrill "(%d block interleave)\n", cs->sc_xname, 457 1.152 sborrill cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : ""), 458 1.152 sborrill cs->sc_ileave); 459 1.152 sborrill else 460 1.152 sborrill aprint_normal("%s: Concatenating %d component%s\n", 461 1.152 sborrill cs->sc_xname, 462 1.152 sborrill cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : "")); 463 1.152 sborrill for (ix = 0; ix < cs->sc_nccdisks; ix++) { 464 1.152 sborrill ci = &cs->sc_cinfo[ix]; 465 1.152 sborrill aprint_normal("%s: %s (%ju blocks)\n", cs->sc_xname, 466 1.152 sborrill ci->ci_path, (uintmax_t)ci->ci_size); 467 1.152 sborrill } 468 1.152 sborrill aprint_normal("%s: total %ju blocks\n", cs->sc_xname, cs->sc_size); 469 1.11 thorpej 470 1.133 ad /* 471 1.133 ad * Create thread to handle deferred I/O. 472 1.133 ad */ 473 1.133 ad cs->sc_zap = false; 474 1.133 ad error = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, ccdthread, 475 1.133 ad cs, &cs->sc_thread, "%s", cs->sc_xname); 476 1.133 ad if (error) { 477 1.133 ad printf("ccdinit: can't create thread: %d\n", error); 478 1.133 ad goto out; 479 1.133 ad } 480 1.133 ad 481 1.133 ad /* 482 1.133 ad * Only now that everything is set up can we enable the device. 483 1.133 ad */ 484 1.133 ad mutex_enter(cs->sc_iolock); 485 1.11 thorpej cs->sc_flags |= CCDF_INITED; 486 1.133 ad mutex_exit(cs->sc_iolock); 487 1.133 ad kmem_free(tmppath, MAXPATHLEN); 488 1.11 thorpej return (0); 489 1.67 enami 490 1.67 enami out: 491 1.133 ad for (ix = 0; ix < path_alloced; ix++) { 492 1.133 ad kmem_free(cs->sc_cinfo[ix].ci_path, 493 1.133 ad cs->sc_cinfo[ix].ci_pathlen); 494 1.133 ad } 495 1.133 ad kmem_free(cs->sc_cinfo, cs->sc_nccdisks * sizeof(struct ccdcinfo)); 496 1.133 ad kmem_free(tmppath, MAXPATHLEN); 497 1.67 enami return (error); 498 1.1 hpeyerl } 499 1.1 hpeyerl 500 1.11 thorpej static void 501 1.97 thorpej ccdinterleave(struct ccd_softc *cs) 502 1.1 hpeyerl { 503 1.68 augustss struct ccdcinfo *ci, *smallci; 504 1.68 augustss struct ccdiinfo *ii; 505 1.68 augustss daddr_t bn, lbn; 506 1.68 augustss int ix; 507 1.1 hpeyerl u_long size; 508 1.1 hpeyerl 509 1.1 hpeyerl #ifdef DEBUG 510 1.3 hpeyerl if (ccddebug & CCDB_INIT) 511 1.35 christos printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave); 512 1.1 hpeyerl #endif 513 1.1 hpeyerl /* 514 1.1 hpeyerl * Allocate an interleave table. 515 1.1 hpeyerl * Chances are this is too big, but we don't care. 516 1.1 hpeyerl */ 517 1.1 hpeyerl size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 518 1.133 ad cs->sc_itable = kmem_zalloc(size, KM_SLEEP); 519 1.11 thorpej 520 1.1 hpeyerl /* 521 1.1 hpeyerl * Trivial case: no interleave (actually interleave of disk size). 522 1.11 thorpej * Each table entry represents a single component in its entirety. 523 1.1 hpeyerl */ 524 1.1 hpeyerl if (cs->sc_ileave == 0) { 525 1.1 hpeyerl bn = 0; 526 1.1 hpeyerl ii = cs->sc_itable; 527 1.11 thorpej 528 1.1 hpeyerl for (ix = 0; ix < cs->sc_nccdisks; ix++) { 529 1.19 thorpej /* Allocate space for ii_index. */ 530 1.133 ad ii->ii_indexsz = sizeof(int); 531 1.133 ad ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP); 532 1.1 hpeyerl ii->ii_ndisk = 1; 533 1.1 hpeyerl ii->ii_startblk = bn; 534 1.1 hpeyerl ii->ii_startoff = 0; 535 1.1 hpeyerl ii->ii_index[0] = ix; 536 1.1 hpeyerl bn += cs->sc_cinfo[ix].ci_size; 537 1.1 hpeyerl ii++; 538 1.1 hpeyerl } 539 1.1 hpeyerl ii->ii_ndisk = 0; 540 1.1 hpeyerl #ifdef DEBUG 541 1.3 hpeyerl if (ccddebug & CCDB_INIT) 542 1.1 hpeyerl printiinfo(cs->sc_itable); 543 1.1 hpeyerl #endif 544 1.11 thorpej return; 545 1.1 hpeyerl } 546 1.11 thorpej 547 1.1 hpeyerl /* 548 1.1 hpeyerl * The following isn't fast or pretty; it doesn't have to be. 549 1.1 hpeyerl */ 550 1.1 hpeyerl size = 0; 551 1.1 hpeyerl bn = lbn = 0; 552 1.1 hpeyerl for (ii = cs->sc_itable; ; ii++) { 553 1.11 thorpej /* Allocate space for ii_index. */ 554 1.133 ad ii->ii_indexsz = sizeof(int) * cs->sc_nccdisks; 555 1.133 ad ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP); 556 1.11 thorpej 557 1.1 hpeyerl /* 558 1.1 hpeyerl * Locate the smallest of the remaining components 559 1.1 hpeyerl */ 560 1.1 hpeyerl smallci = NULL; 561 1.1 hpeyerl for (ci = cs->sc_cinfo; 562 1.1 hpeyerl ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 563 1.1 hpeyerl if (ci->ci_size > size && 564 1.1 hpeyerl (smallci == NULL || 565 1.1 hpeyerl ci->ci_size < smallci->ci_size)) 566 1.1 hpeyerl smallci = ci; 567 1.11 thorpej 568 1.1 hpeyerl /* 569 1.1 hpeyerl * Nobody left, all done 570 1.1 hpeyerl */ 571 1.1 hpeyerl if (smallci == NULL) { 572 1.1 hpeyerl ii->ii_ndisk = 0; 573 1.1 hpeyerl break; 574 1.1 hpeyerl } 575 1.11 thorpej 576 1.1 hpeyerl /* 577 1.1 hpeyerl * Record starting logical block and component offset 578 1.1 hpeyerl */ 579 1.1 hpeyerl ii->ii_startblk = bn / cs->sc_ileave; 580 1.1 hpeyerl ii->ii_startoff = lbn; 581 1.11 thorpej 582 1.1 hpeyerl /* 583 1.1 hpeyerl * Determine how many disks take part in this interleave 584 1.1 hpeyerl * and record their indices. 585 1.1 hpeyerl */ 586 1.1 hpeyerl ix = 0; 587 1.1 hpeyerl for (ci = cs->sc_cinfo; 588 1.1 hpeyerl ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 589 1.1 hpeyerl if (ci->ci_size >= smallci->ci_size) 590 1.1 hpeyerl ii->ii_index[ix++] = ci - cs->sc_cinfo; 591 1.1 hpeyerl ii->ii_ndisk = ix; 592 1.1 hpeyerl bn += ix * (smallci->ci_size - size); 593 1.1 hpeyerl lbn = smallci->ci_size / cs->sc_ileave; 594 1.1 hpeyerl size = smallci->ci_size; 595 1.1 hpeyerl } 596 1.1 hpeyerl #ifdef DEBUG 597 1.3 hpeyerl if (ccddebug & CCDB_INIT) 598 1.1 hpeyerl printiinfo(cs->sc_itable); 599 1.1 hpeyerl #endif 600 1.1 hpeyerl } 601 1.1 hpeyerl 602 1.11 thorpej /* ARGSUSED */ 603 1.97 thorpej static int 604 1.116 christos ccdopen(dev_t dev, int flags, int fmt, struct lwp *l) 605 1.1 hpeyerl { 606 1.1 hpeyerl int unit = ccdunit(dev); 607 1.11 thorpej struct ccd_softc *cs; 608 1.11 thorpej struct disklabel *lp; 609 1.15 thorpej int error = 0, part, pmask; 610 1.1 hpeyerl 611 1.1 hpeyerl #ifdef DEBUG 612 1.3 hpeyerl if (ccddebug & CCDB_FOLLOW) 613 1.131 cegger printf("ccdopen(0x%"PRIx64", 0x%x)\n", dev, flags); 614 1.1 hpeyerl #endif 615 1.158 christos if ((cs = ccdget(unit, 1)) == NULL) 616 1.144 christos return ENXIO; 617 1.15 thorpej 618 1.133 ad mutex_enter(&cs->sc_dvlock); 619 1.15 thorpej 620 1.23 thorpej lp = cs->sc_dkdev.dk_label; 621 1.11 thorpej 622 1.11 thorpej part = DISKPART(dev); 623 1.11 thorpej pmask = (1 << part); 624 1.11 thorpej 625 1.15 thorpej /* 626 1.15 thorpej * If we're initialized, check to see if there are any other 627 1.15 thorpej * open partitions. If not, then it's safe to update 628 1.87 thorpej * the in-core disklabel. Only read the disklabel if it is 629 1.87 thorpej * not already valid. 630 1.15 thorpej */ 631 1.87 thorpej if ((cs->sc_flags & (CCDF_INITED|CCDF_VLABEL)) == CCDF_INITED && 632 1.87 thorpej cs->sc_dkdev.dk_openmask == 0) 633 1.15 thorpej ccdgetdisklabel(dev); 634 1.15 thorpej 635 1.11 thorpej /* Check that the partition exists. */ 636 1.27 thorpej if (part != RAW_PART) { 637 1.27 thorpej if (((cs->sc_flags & CCDF_INITED) == 0) || 638 1.37 thorpej ((part >= lp->d_npartitions) || 639 1.27 thorpej (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 640 1.27 thorpej error = ENXIO; 641 1.27 thorpej goto done; 642 1.27 thorpej } 643 1.15 thorpej } 644 1.11 thorpej 645 1.11 thorpej /* Prevent our unit from being unconfigured while open. */ 646 1.11 thorpej switch (fmt) { 647 1.11 thorpej case S_IFCHR: 648 1.11 thorpej cs->sc_dkdev.dk_copenmask |= pmask; 649 1.11 thorpej break; 650 1.11 thorpej 651 1.11 thorpej case S_IFBLK: 652 1.11 thorpej cs->sc_dkdev.dk_bopenmask |= pmask; 653 1.11 thorpej break; 654 1.11 thorpej } 655 1.11 thorpej cs->sc_dkdev.dk_openmask = 656 1.11 thorpej cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 657 1.11 thorpej 658 1.15 thorpej done: 659 1.133 ad mutex_exit(&cs->sc_dvlock); 660 1.33 thorpej return (error); 661 1.7 cgd } 662 1.7 cgd 663 1.11 thorpej /* ARGSUSED */ 664 1.97 thorpej static int 665 1.116 christos ccdclose(dev_t dev, int flags, int fmt, struct lwp *l) 666 1.7 cgd { 667 1.11 thorpej int unit = ccdunit(dev); 668 1.11 thorpej struct ccd_softc *cs; 669 1.117 ad int part; 670 1.11 thorpej 671 1.7 cgd #ifdef DEBUG 672 1.7 cgd if (ccddebug & CCDB_FOLLOW) 673 1.131 cegger printf("ccdclose(0x%"PRIx64", 0x%x)\n", dev, flags); 674 1.7 cgd #endif 675 1.11 thorpej 676 1.158 christos if ((cs = ccdget(unit, 0)) == NULL) 677 1.144 christos return ENXIO; 678 1.15 thorpej 679 1.133 ad mutex_enter(&cs->sc_dvlock); 680 1.15 thorpej 681 1.11 thorpej part = DISKPART(dev); 682 1.11 thorpej 683 1.11 thorpej /* ...that much closer to allowing unconfiguration... */ 684 1.11 thorpej switch (fmt) { 685 1.11 thorpej case S_IFCHR: 686 1.11 thorpej cs->sc_dkdev.dk_copenmask &= ~(1 << part); 687 1.11 thorpej break; 688 1.11 thorpej 689 1.11 thorpej case S_IFBLK: 690 1.11 thorpej cs->sc_dkdev.dk_bopenmask &= ~(1 << part); 691 1.11 thorpej break; 692 1.11 thorpej } 693 1.11 thorpej cs->sc_dkdev.dk_openmask = 694 1.11 thorpej cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 695 1.11 thorpej 696 1.87 thorpej if (cs->sc_dkdev.dk_openmask == 0) { 697 1.87 thorpej if ((cs->sc_flags & CCDF_KLABEL) == 0) 698 1.87 thorpej cs->sc_flags &= ~CCDF_VLABEL; 699 1.87 thorpej } 700 1.87 thorpej 701 1.133 ad mutex_exit(&cs->sc_dvlock); 702 1.7 cgd return (0); 703 1.1 hpeyerl } 704 1.1 hpeyerl 705 1.133 ad static void 706 1.133 ad ccdthread(void *cookie) 707 1.133 ad { 708 1.190 hannken int error; 709 1.133 ad struct ccd_softc *cs; 710 1.190 hannken struct buf *bp; 711 1.133 ad 712 1.133 ad cs = cookie; 713 1.133 ad 714 1.133 ad #ifdef DEBUG 715 1.133 ad if (ccddebug & CCDB_FOLLOW) 716 1.133 ad printf("ccdthread: hello\n"); 717 1.133 ad #endif 718 1.133 ad 719 1.133 ad mutex_enter(cs->sc_iolock); 720 1.133 ad while (__predict_true(!cs->sc_zap)) { 721 1.190 hannken bp = bufq_get(cs->sc_bufq); 722 1.190 hannken if (bp == NULL) { 723 1.133 ad /* Nothing to do. */ 724 1.133 ad cv_wait(&cs->sc_push, cs->sc_iolock); 725 1.133 ad continue; 726 1.133 ad } 727 1.133 ad #ifdef DEBUG 728 1.133 ad if (ccddebug & CCDB_FOLLOW) 729 1.133 ad printf("ccdthread: dispatching I/O\n"); 730 1.133 ad #endif 731 1.190 hannken error = ccdstart(cs, bp, PR_WAITOK); 732 1.190 hannken KASSERT(error == 0); 733 1.133 ad mutex_enter(cs->sc_iolock); 734 1.133 ad } 735 1.133 ad cs->sc_thread = NULL; 736 1.133 ad mutex_exit(cs->sc_iolock); 737 1.133 ad #ifdef DEBUG 738 1.133 ad if (ccddebug & CCDB_FOLLOW) 739 1.133 ad printf("ccdthread: goodbye\n"); 740 1.133 ad #endif 741 1.133 ad kthread_exit(0); 742 1.133 ad } 743 1.133 ad 744 1.97 thorpej static void 745 1.97 thorpej ccdstrategy(struct buf *bp) 746 1.1 hpeyerl { 747 1.68 augustss int unit = ccdunit(bp->b_dev); 748 1.144 christos struct ccd_softc *cs; 749 1.158 christos if ((cs = ccdget(unit, 0)) == NULL) 750 1.144 christos return; 751 1.133 ad 752 1.133 ad /* Must be open or reading label. */ 753 1.133 ad KASSERT(cs->sc_dkdev.dk_openmask != 0 || 754 1.133 ad (cs->sc_flags & CCDF_RLABEL) != 0); 755 1.133 ad 756 1.133 ad mutex_enter(cs->sc_iolock); 757 1.133 ad /* Synchronize with device init/uninit. */ 758 1.133 ad if (__predict_false((cs->sc_flags & CCDF_INITED) == 0)) { 759 1.133 ad mutex_exit(cs->sc_iolock); 760 1.133 ad #ifdef DEBUG 761 1.133 ad if (ccddebug & CCDB_FOLLOW) 762 1.133 ad printf("ccdstrategy: unit %d: not inited\n", unit); 763 1.133 ad #endif 764 1.133 ad bp->b_error = ENXIO; 765 1.133 ad bp->b_resid = bp->b_bcount; 766 1.133 ad biodone(bp); 767 1.133 ad return; 768 1.133 ad } 769 1.133 ad 770 1.190 hannken if (ccdstart(cs, bp, PR_NOWAIT) != 0) { 771 1.190 hannken /* Defer to thread if system is low on memory. */ 772 1.190 hannken bufq_put(cs->sc_bufq, bp); 773 1.190 hannken cv_broadcast(&cs->sc_push); 774 1.133 ad mutex_exit(cs->sc_iolock); 775 1.133 ad } 776 1.133 ad } 777 1.133 ad 778 1.190 hannken static int 779 1.190 hannken ccdstart(struct ccd_softc *cs, struct buf *bp, int wait) 780 1.133 ad { 781 1.88 thorpej daddr_t blkno; 782 1.11 thorpej int wlabel; 783 1.15 thorpej struct disklabel *lp; 784 1.133 ad long bcount, rcount; 785 1.133 ad struct ccdbuf *cbp; 786 1.133 ad char *addr; 787 1.133 ad daddr_t bn; 788 1.133 ad vnode_t *vp; 789 1.190 hannken SIMPLEQ_HEAD(, ccdbuf) cbufq; 790 1.133 ad 791 1.133 ad KASSERT(mutex_owned(cs->sc_iolock)); 792 1.133 ad KASSERT(bp != NULL); 793 1.1 hpeyerl 794 1.169 mlelstv disk_busy(&cs->sc_dkdev); 795 1.169 mlelstv 796 1.1 hpeyerl #ifdef DEBUG 797 1.3 hpeyerl if (ccddebug & CCDB_FOLLOW) 798 1.133 ad printf("ccdstart(%s, %p)\n", cs->sc_xname, bp); 799 1.59 thorpej #endif 800 1.11 thorpej 801 1.11 thorpej /* If it's a nil transfer, wake up the top half now. */ 802 1.11 thorpej if (bp->b_bcount == 0) 803 1.11 thorpej goto done; 804 1.11 thorpej 805 1.23 thorpej lp = cs->sc_dkdev.dk_label; 806 1.15 thorpej 807 1.11 thorpej /* 808 1.17 thorpej * Do bounds checking and adjust transfer. If there's an 809 1.88 thorpej * error, the bounds check will flag that for us. Convert 810 1.88 thorpej * the partition relative block number to an absolute. 811 1.11 thorpej */ 812 1.88 thorpej blkno = bp->b_blkno; 813 1.11 thorpej wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 814 1.88 thorpej if (DISKPART(bp->b_dev) != RAW_PART) { 815 1.86 thorpej if (bounds_check_with_label(&cs->sc_dkdev, bp, wlabel) <= 0) 816 1.1 hpeyerl goto done; 817 1.88 thorpej blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 818 1.88 thorpej } 819 1.133 ad mutex_exit(cs->sc_iolock); 820 1.88 thorpej bp->b_rawblkno = blkno; 821 1.11 thorpej 822 1.190 hannken /* Allocate the component buffers. */ 823 1.190 hannken SIMPLEQ_INIT(&cbufq); 824 1.133 ad bp->b_resid = bp->b_bcount; 825 1.133 ad bn = bp->b_rawblkno; 826 1.133 ad addr = bp->b_data; 827 1.133 ad for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 828 1.190 hannken cbp = ccdbuffer(cs, bp, bn, addr, bcount, wait); 829 1.190 hannken KASSERT(cbp != NULL || wait == PR_NOWAIT); 830 1.190 hannken if (cbp == NULL) { 831 1.190 hannken while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) { 832 1.190 hannken SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q); 833 1.190 hannken CCD_PUTBUF(cbp); 834 1.190 hannken } 835 1.190 hannken mutex_enter(cs->sc_iolock); 836 1.190 hannken disk_unbusy(&cs->sc_dkdev, 0, 0); 837 1.190 hannken return ENOMEM; 838 1.190 hannken } 839 1.190 hannken SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q); 840 1.133 ad rcount = cbp->cb_buf.b_bcount; 841 1.133 ad bn += btodb(rcount); 842 1.133 ad addr += rcount; 843 1.190 hannken } 844 1.190 hannken 845 1.190 hannken /* All buffers set up, now fire off the requests. */ 846 1.190 hannken while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) { 847 1.190 hannken SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q); 848 1.133 ad vp = cbp->cb_buf.b_vp; 849 1.133 ad if ((cbp->cb_buf.b_flags & B_READ) == 0) { 850 1.139 rmind mutex_enter(vp->v_interlock); 851 1.133 ad vp->v_numoutput++; 852 1.139 rmind mutex_exit(vp->v_interlock); 853 1.133 ad } 854 1.133 ad (void)VOP_STRATEGY(vp, &cbp->cb_buf); 855 1.133 ad } 856 1.190 hannken return 0; 857 1.88 thorpej 858 1.88 thorpej done: 859 1.133 ad disk_unbusy(&cs->sc_dkdev, 0, 0); 860 1.133 ad cv_broadcast(&cs->sc_stop); 861 1.133 ad cv_broadcast(&cs->sc_push); 862 1.133 ad mutex_exit(cs->sc_iolock); 863 1.88 thorpej bp->b_resid = bp->b_bcount; 864 1.1 hpeyerl biodone(bp); 865 1.190 hannken return 0; 866 1.1 hpeyerl } 867 1.1 hpeyerl 868 1.1 hpeyerl /* 869 1.1 hpeyerl * Build a component buffer header. 870 1.1 hpeyerl */ 871 1.55 thorpej static struct ccdbuf * 872 1.118 christos ccdbuffer(struct ccd_softc *cs, struct buf *bp, daddr_t bn, void *addr, 873 1.190 hannken long bcount, int wait) 874 1.1 hpeyerl { 875 1.68 augustss struct ccdcinfo *ci; 876 1.68 augustss struct ccdbuf *cbp; 877 1.68 augustss daddr_t cbn, cboff; 878 1.68 augustss u_int64_t cbc; 879 1.36 thorpej int ccdisk; 880 1.1 hpeyerl 881 1.1 hpeyerl #ifdef DEBUG 882 1.3 hpeyerl if (ccddebug & CCDB_IO) 883 1.81 kleink printf("ccdbuffer(%p, %p, %" PRId64 ", %p, %ld)\n", 884 1.1 hpeyerl cs, bp, bn, addr, bcount); 885 1.1 hpeyerl #endif 886 1.1 hpeyerl /* 887 1.1 hpeyerl * Determine which component bn falls in. 888 1.1 hpeyerl */ 889 1.1 hpeyerl cbn = bn; 890 1.1 hpeyerl cboff = 0; 891 1.11 thorpej 892 1.1 hpeyerl /* 893 1.1 hpeyerl * Serially concatenated 894 1.1 hpeyerl */ 895 1.1 hpeyerl if (cs->sc_ileave == 0) { 896 1.68 augustss daddr_t sblk; 897 1.1 hpeyerl 898 1.1 hpeyerl sblk = 0; 899 1.36 thorpej for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk]; 900 1.36 thorpej cbn >= sblk + ci->ci_size; 901 1.36 thorpej ccdisk++, ci = &cs->sc_cinfo[ccdisk]) 902 1.1 hpeyerl sblk += ci->ci_size; 903 1.1 hpeyerl cbn -= sblk; 904 1.1 hpeyerl } 905 1.1 hpeyerl /* 906 1.1 hpeyerl * Interleaved 907 1.1 hpeyerl */ 908 1.1 hpeyerl else { 909 1.68 augustss struct ccdiinfo *ii; 910 1.36 thorpej int off; 911 1.1 hpeyerl 912 1.1 hpeyerl cboff = cbn % cs->sc_ileave; 913 1.1 hpeyerl cbn /= cs->sc_ileave; 914 1.1 hpeyerl for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 915 1.1 hpeyerl if (ii->ii_startblk > cbn) 916 1.1 hpeyerl break; 917 1.1 hpeyerl ii--; 918 1.1 hpeyerl off = cbn - ii->ii_startblk; 919 1.1 hpeyerl if (ii->ii_ndisk == 1) { 920 1.1 hpeyerl ccdisk = ii->ii_index[0]; 921 1.1 hpeyerl cbn = ii->ii_startoff + off; 922 1.1 hpeyerl } else { 923 1.53 thorpej ccdisk = ii->ii_index[off % ii->ii_ndisk]; 924 1.53 thorpej cbn = ii->ii_startoff + off / ii->ii_ndisk; 925 1.1 hpeyerl } 926 1.1 hpeyerl cbn *= cs->sc_ileave; 927 1.1 hpeyerl ci = &cs->sc_cinfo[ccdisk]; 928 1.1 hpeyerl } 929 1.11 thorpej 930 1.1 hpeyerl /* 931 1.1 hpeyerl * Fill in the component buf structure. 932 1.1 hpeyerl */ 933 1.190 hannken cbp = CCD_GETBUF(wait); 934 1.190 hannken if (cbp == NULL) 935 1.190 hannken return NULL; 936 1.126 ad buf_init(&cbp->cb_buf); 937 1.126 ad cbp->cb_buf.b_flags = bp->b_flags; 938 1.126 ad cbp->cb_buf.b_oflags = bp->b_oflags; 939 1.126 ad cbp->cb_buf.b_cflags = bp->b_cflags; 940 1.29 christos cbp->cb_buf.b_iodone = ccdiodone; 941 1.6 cgd cbp->cb_buf.b_proc = bp->b_proc; 942 1.95 hannken cbp->cb_buf.b_dev = ci->ci_dev; 943 1.6 cgd cbp->cb_buf.b_blkno = cbn + cboff; 944 1.6 cgd cbp->cb_buf.b_data = addr; 945 1.11 thorpej cbp->cb_buf.b_vp = ci->ci_vp; 946 1.139 rmind cbp->cb_buf.b_objlock = ci->ci_vp->v_interlock; 947 1.1 hpeyerl if (cs->sc_ileave == 0) 948 1.50 thorpej cbc = dbtob((u_int64_t)(ci->ci_size - cbn)); 949 1.1 hpeyerl else 950 1.50 thorpej cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff)); 951 1.50 thorpej cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount; 952 1.6 cgd 953 1.1 hpeyerl /* 954 1.6 cgd * context for ccdiodone 955 1.1 hpeyerl */ 956 1.6 cgd cbp->cb_obp = bp; 957 1.59 thorpej cbp->cb_sc = cs; 958 1.36 thorpej cbp->cb_comp = ccdisk; 959 1.6 cgd 960 1.94 yamt BIO_COPYPRIO(&cbp->cb_buf, bp); 961 1.94 yamt 962 1.1 hpeyerl #ifdef DEBUG 963 1.3 hpeyerl if (ccddebug & CCDB_IO) 964 1.131 cegger printf(" dev 0x%"PRIx64"(u%lu): cbp %p bn %" PRId64 " addr %p" 965 1.99 yamt " bcnt %d\n", 966 1.62 mjacob ci->ci_dev, (unsigned long) (ci-cs->sc_cinfo), cbp, 967 1.62 mjacob cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 968 1.62 mjacob cbp->cb_buf.b_bcount); 969 1.1 hpeyerl #endif 970 1.55 thorpej 971 1.55 thorpej return (cbp); 972 1.1 hpeyerl } 973 1.1 hpeyerl 974 1.1 hpeyerl /* 975 1.11 thorpej * Called at interrupt time. 976 1.1 hpeyerl * Mark the component as done and if all components are done, 977 1.1 hpeyerl * take a ccd interrupt. 978 1.1 hpeyerl */ 979 1.97 thorpej static void 980 1.97 thorpej ccdiodone(struct buf *vbp) 981 1.1 hpeyerl { 982 1.29 christos struct ccdbuf *cbp = (struct ccdbuf *) vbp; 983 1.59 thorpej struct buf *bp = cbp->cb_obp; 984 1.59 thorpej struct ccd_softc *cs = cbp->cb_sc; 985 1.133 ad int count; 986 1.1 hpeyerl 987 1.1 hpeyerl #ifdef DEBUG 988 1.3 hpeyerl if (ccddebug & CCDB_FOLLOW) 989 1.35 christos printf("ccdiodone(%p)\n", cbp); 990 1.3 hpeyerl if (ccddebug & CCDB_IO) { 991 1.99 yamt printf("ccdiodone: bp %p bcount %d resid %d\n", 992 1.53 thorpej bp, bp->b_bcount, bp->b_resid); 993 1.131 cegger printf(" dev 0x%"PRIx64"(u%d), cbp %p bn %" PRId64 " addr %p" 994 1.99 yamt " bcnt %d\n", 995 1.6 cgd cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 996 1.6 cgd cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 997 1.6 cgd cbp->cb_buf.b_bcount); 998 1.1 hpeyerl } 999 1.1 hpeyerl #endif 1000 1.1 hpeyerl 1001 1.122 ad if (cbp->cb_buf.b_error != 0) { 1002 1.122 ad bp->b_error = cbp->cb_buf.b_error; 1003 1.53 thorpej printf("%s: error %d on component %d\n", 1004 1.53 thorpej cs->sc_xname, bp->b_error, cbp->cb_comp); 1005 1.1 hpeyerl } 1006 1.6 cgd count = cbp->cb_buf.b_bcount; 1007 1.126 ad buf_destroy(&cbp->cb_buf); 1008 1.63 thorpej CCD_PUTBUF(cbp); 1009 1.1 hpeyerl 1010 1.1 hpeyerl /* 1011 1.1 hpeyerl * If all done, "interrupt". 1012 1.53 thorpej */ 1013 1.133 ad mutex_enter(cs->sc_iolock); 1014 1.53 thorpej bp->b_resid -= count; 1015 1.53 thorpej if (bp->b_resid < 0) 1016 1.53 thorpej panic("ccdiodone: count"); 1017 1.133 ad if (bp->b_resid == 0) { 1018 1.133 ad /* 1019 1.133 ad * Request is done for better or worse, wakeup the top half. 1020 1.133 ad */ 1021 1.133 ad if (bp->b_error != 0) 1022 1.133 ad bp->b_resid = bp->b_bcount; 1023 1.133 ad disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid), 1024 1.133 ad (bp->b_flags & B_READ)); 1025 1.133 ad if (!disk_isbusy(&cs->sc_dkdev)) { 1026 1.133 ad if (bufq_peek(cs->sc_bufq) != NULL) { 1027 1.133 ad cv_broadcast(&cs->sc_push); 1028 1.133 ad } 1029 1.133 ad cv_broadcast(&cs->sc_stop); 1030 1.133 ad } 1031 1.133 ad mutex_exit(cs->sc_iolock); 1032 1.133 ad biodone(bp); 1033 1.133 ad } else 1034 1.133 ad mutex_exit(cs->sc_iolock); 1035 1.1 hpeyerl } 1036 1.1 hpeyerl 1037 1.11 thorpej /* ARGSUSED */ 1038 1.97 thorpej static int 1039 1.116 christos ccdread(dev_t dev, struct uio *uio, int flags) 1040 1.3 hpeyerl { 1041 1.11 thorpej int unit = ccdunit(dev); 1042 1.11 thorpej struct ccd_softc *cs; 1043 1.3 hpeyerl 1044 1.3 hpeyerl #ifdef DEBUG 1045 1.3 hpeyerl if (ccddebug & CCDB_FOLLOW) 1046 1.131 cegger printf("ccdread(0x%"PRIx64", %p)\n", dev, uio); 1047 1.3 hpeyerl #endif 1048 1.158 christos if ((cs = ccdget(unit, 0)) == NULL) 1049 1.144 christos return 0; 1050 1.11 thorpej 1051 1.133 ad /* Unlocked advisory check, ccdstrategy check is synchronous. */ 1052 1.11 thorpej if ((cs->sc_flags & CCDF_INITED) == 0) 1053 1.11 thorpej return (ENXIO); 1054 1.11 thorpej 1055 1.10 mycroft return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio)); 1056 1.3 hpeyerl } 1057 1.3 hpeyerl 1058 1.11 thorpej /* ARGSUSED */ 1059 1.97 thorpej static int 1060 1.116 christos ccdwrite(dev_t dev, struct uio *uio, int flags) 1061 1.3 hpeyerl { 1062 1.11 thorpej int unit = ccdunit(dev); 1063 1.11 thorpej struct ccd_softc *cs; 1064 1.3 hpeyerl 1065 1.3 hpeyerl #ifdef DEBUG 1066 1.3 hpeyerl if (ccddebug & CCDB_FOLLOW) 1067 1.131 cegger printf("ccdwrite(0x%"PRIx64", %p)\n", dev, uio); 1068 1.3 hpeyerl #endif 1069 1.158 christos if ((cs = ccdget(unit, 0)) == NULL) 1070 1.144 christos return ENOENT; 1071 1.11 thorpej 1072 1.133 ad /* Unlocked advisory check, ccdstrategy check is synchronous. */ 1073 1.11 thorpej if ((cs->sc_flags & CCDF_INITED) == 0) 1074 1.11 thorpej return (ENXIO); 1075 1.11 thorpej 1076 1.10 mycroft return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio)); 1077 1.3 hpeyerl } 1078 1.3 hpeyerl 1079 1.176 christos int (*compat_ccd_ioctl_60)(dev_t, u_long, void *, int, struct lwp *, 1080 1.176 christos int (*)(dev_t, u_long, void *, int, struct lwp *)) = (void *)enosys; 1081 1.176 christos 1082 1.97 thorpej static int 1083 1.118 christos ccdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1084 1.1 hpeyerl { 1085 1.11 thorpej int unit = ccdunit(dev); 1086 1.133 ad int i, j, lookedup = 0, error = 0; 1087 1.177 pgoyette int part, pmask, make, hook; 1088 1.11 thorpej struct ccd_softc *cs; 1089 1.11 thorpej struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1090 1.110 elad kauth_cred_t uc; 1091 1.11 thorpej char **cpp; 1092 1.136 dholland struct pathbuf *pb; 1093 1.11 thorpej struct vnode **vpp; 1094 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1095 1.70 fvdl struct disklabel newlabel; 1096 1.70 fvdl #endif 1097 1.11 thorpej 1098 1.158 christos switch (cmd) { 1099 1.158 christos case CCDIOCSET: 1100 1.158 christos make = 1; 1101 1.158 christos break; 1102 1.158 christos default: 1103 1.178 pgoyette MODULE_HOOK_CALL(ccd_ioctl_60_hook, 1104 1.177 pgoyette (0, cmd, NULL, 0, NULL, NULL), 1105 1.177 pgoyette enosys(), hook); 1106 1.177 pgoyette if (hook == 0) 1107 1.176 christos make = 1; 1108 1.176 christos else 1109 1.176 christos make = 0; 1110 1.158 christos break; 1111 1.158 christos } 1112 1.158 christos 1113 1.158 christos if ((cs = ccdget(unit, make)) == NULL) 1114 1.144 christos return ENOENT; 1115 1.133 ad uc = kauth_cred_get(); 1116 1.109 jld 1117 1.178 pgoyette MODULE_HOOK_CALL(ccd_ioctl_60_hook, 1118 1.177 pgoyette (dev, cmd, data, flag, l, ccdioctl), 1119 1.177 pgoyette enosys(), error); 1120 1.176 christos if (error != ENOSYS) 1121 1.152 sborrill return error; 1122 1.152 sborrill 1123 1.41 thorpej /* Must be open for writes for these commands... */ 1124 1.41 thorpej switch (cmd) { 1125 1.41 thorpej case CCDIOCSET: 1126 1.41 thorpej case CCDIOCCLR: 1127 1.41 thorpej case DIOCSDINFO: 1128 1.41 thorpej case DIOCWDINFO: 1129 1.157 mlelstv case DIOCCACHESYNC: 1130 1.157 mlelstv case DIOCAWEDGE: 1131 1.157 mlelstv case DIOCDWEDGE: 1132 1.179 martin case DIOCRMWEDGES: 1133 1.157 mlelstv case DIOCMWEDGES: 1134 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1135 1.70 fvdl case ODIOCSDINFO: 1136 1.70 fvdl case ODIOCWDINFO: 1137 1.70 fvdl #endif 1138 1.87 thorpej case DIOCKLABEL: 1139 1.41 thorpej case DIOCWLABEL: 1140 1.41 thorpej if ((flag & FWRITE) == 0) 1141 1.41 thorpej return (EBADF); 1142 1.41 thorpej } 1143 1.41 thorpej 1144 1.41 thorpej /* Must be initialized for these... */ 1145 1.41 thorpej switch (cmd) { 1146 1.41 thorpej case CCDIOCCLR: 1147 1.42 kleink case DIOCGDINFO: 1148 1.170 jdolecek case DIOCGSTRATEGY: 1149 1.170 jdolecek case DIOCGCACHE: 1150 1.100 thorpej case DIOCCACHESYNC: 1151 1.157 mlelstv case DIOCAWEDGE: 1152 1.157 mlelstv case DIOCDWEDGE: 1153 1.157 mlelstv case DIOCLWEDGES: 1154 1.157 mlelstv case DIOCMWEDGES: 1155 1.42 kleink case DIOCSDINFO: 1156 1.42 kleink case DIOCWDINFO: 1157 1.166 christos case DIOCGPARTINFO: 1158 1.41 thorpej case DIOCWLABEL: 1159 1.87 thorpej case DIOCKLABEL: 1160 1.44 thorpej case DIOCGDEFLABEL: 1161 1.70 fvdl #ifdef __HAVE_OLD_DISKLABEL 1162 1.70 fvdl case ODIOCGDINFO: 1163 1.70 fvdl case ODIOCSDINFO: 1164 1.70 fvdl case ODIOCWDINFO: 1165 1.70 fvdl case ODIOCGDEFLABEL: 1166 1.70 fvdl #endif 1167 1.185 mlelstv if ((cs->sc_flags & CCDF_INITED) == 0) 1168 1.185 mlelstv return ENXIO; 1169 1.41 thorpej } 1170 1.41 thorpej 1171 1.164 skrll error = disk_ioctl(&cs->sc_dkdev, dev, cmd, data, flag, l); 1172 1.155 christos if (error != EPASSTHROUGH) 1173 1.185 mlelstv return error; 1174 1.185 mlelstv 1175 1.193 mlelstv error = 0; 1176 1.185 mlelstv switch (cmd) { 1177 1.185 mlelstv case DIOCGSTRATEGY: 1178 1.185 mlelstv { 1179 1.185 mlelstv struct disk_strategy *dks = (void *)data; 1180 1.185 mlelstv 1181 1.185 mlelstv mutex_enter(cs->sc_iolock); 1182 1.185 mlelstv if (cs->sc_bufq != NULL) 1183 1.185 mlelstv strlcpy(dks->dks_name, 1184 1.185 mlelstv bufq_getstrategyname(cs->sc_bufq), 1185 1.185 mlelstv sizeof(dks->dks_name)); 1186 1.185 mlelstv else 1187 1.185 mlelstv error = EINVAL; 1188 1.185 mlelstv mutex_exit(cs->sc_iolock); 1189 1.185 mlelstv dks->dks_paramlen = 0; 1190 1.185 mlelstv break; 1191 1.185 mlelstv } 1192 1.185 mlelstv 1193 1.185 mlelstv case DIOCWDINFO: 1194 1.185 mlelstv case DIOCSDINFO: 1195 1.185 mlelstv #ifdef __HAVE_OLD_DISKLABEL 1196 1.185 mlelstv case ODIOCWDINFO: 1197 1.185 mlelstv case ODIOCSDINFO: 1198 1.185 mlelstv #endif 1199 1.185 mlelstv { 1200 1.185 mlelstv struct disklabel *lp; 1201 1.185 mlelstv #ifdef __HAVE_OLD_DISKLABEL 1202 1.185 mlelstv if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1203 1.185 mlelstv memset(&newlabel, 0, sizeof newlabel); 1204 1.185 mlelstv memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1205 1.185 mlelstv lp = &newlabel; 1206 1.185 mlelstv } else 1207 1.185 mlelstv #endif 1208 1.185 mlelstv lp = (struct disklabel *)data; 1209 1.185 mlelstv 1210 1.185 mlelstv cs->sc_flags |= CCDF_LABELLING; 1211 1.185 mlelstv 1212 1.185 mlelstv error = setdisklabel(cs->sc_dkdev.dk_label, 1213 1.185 mlelstv lp, 0, cs->sc_dkdev.dk_cpulabel); 1214 1.185 mlelstv if (error == 0) { 1215 1.185 mlelstv if (cmd == DIOCWDINFO 1216 1.185 mlelstv #ifdef __HAVE_OLD_DISKLABEL 1217 1.185 mlelstv || cmd == ODIOCWDINFO 1218 1.185 mlelstv #endif 1219 1.185 mlelstv ) 1220 1.185 mlelstv error = writedisklabel(CCDLABELDEV(dev), 1221 1.185 mlelstv ccdstrategy, cs->sc_dkdev.dk_label, 1222 1.185 mlelstv cs->sc_dkdev.dk_cpulabel); 1223 1.185 mlelstv } 1224 1.185 mlelstv 1225 1.185 mlelstv cs->sc_flags &= ~CCDF_LABELLING; 1226 1.185 mlelstv break; 1227 1.185 mlelstv } 1228 1.185 mlelstv 1229 1.185 mlelstv case DIOCKLABEL: 1230 1.185 mlelstv if (*(int *)data != 0) 1231 1.185 mlelstv cs->sc_flags |= CCDF_KLABEL; 1232 1.185 mlelstv else 1233 1.185 mlelstv cs->sc_flags &= ~CCDF_KLABEL; 1234 1.185 mlelstv break; 1235 1.185 mlelstv 1236 1.185 mlelstv case DIOCWLABEL: 1237 1.185 mlelstv if (*(int *)data != 0) 1238 1.185 mlelstv cs->sc_flags |= CCDF_WLABEL; 1239 1.185 mlelstv else 1240 1.185 mlelstv cs->sc_flags &= ~CCDF_WLABEL; 1241 1.185 mlelstv break; 1242 1.185 mlelstv 1243 1.185 mlelstv case DIOCGDEFLABEL: 1244 1.185 mlelstv ccdgetdefaultlabel(cs, (struct disklabel *)data); 1245 1.185 mlelstv break; 1246 1.185 mlelstv 1247 1.185 mlelstv #ifdef __HAVE_OLD_DISKLABEL 1248 1.185 mlelstv case ODIOCGDEFLABEL: 1249 1.185 mlelstv ccdgetdefaultlabel(cs, &newlabel); 1250 1.185 mlelstv if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1251 1.185 mlelstv return ENOTTY; 1252 1.185 mlelstv memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1253 1.185 mlelstv break; 1254 1.185 mlelstv #endif 1255 1.185 mlelstv default: 1256 1.185 mlelstv error = ENOTTY; 1257 1.185 mlelstv break; 1258 1.185 mlelstv } 1259 1.185 mlelstv 1260 1.185 mlelstv if (error != ENOTTY) 1261 1.185 mlelstv return error; 1262 1.185 mlelstv 1263 1.185 mlelstv mutex_enter(&cs->sc_dvlock); 1264 1.155 christos 1265 1.157 mlelstv error = 0; 1266 1.11 thorpej switch (cmd) { 1267 1.11 thorpej case CCDIOCSET: 1268 1.57 thorpej if (cs->sc_flags & CCDF_INITED) { 1269 1.57 thorpej error = EBUSY; 1270 1.57 thorpej goto out; 1271 1.57 thorpej } 1272 1.54 thorpej 1273 1.54 thorpej /* Validate the flags. */ 1274 1.57 thorpej if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) { 1275 1.57 thorpej error = EINVAL; 1276 1.57 thorpej goto out; 1277 1.57 thorpej } 1278 1.15 thorpej 1279 1.133 ad if (ccio->ccio_ndisks > CCD_MAXNDISKS || 1280 1.133 ad ccio->ccio_ndisks == 0) { 1281 1.73 jdolecek error = EINVAL; 1282 1.73 jdolecek goto out; 1283 1.73 jdolecek } 1284 1.102 perry 1285 1.11 thorpej /* Fill in some important bits. */ 1286 1.57 thorpej cs->sc_ileave = ccio->ccio_ileave; 1287 1.57 thorpej cs->sc_nccdisks = ccio->ccio_ndisks; 1288 1.57 thorpej cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK; 1289 1.11 thorpej 1290 1.11 thorpej /* 1291 1.11 thorpej * Allocate space for and copy in the array of 1292 1.152 sborrill * component pathnames and device numbers. 1293 1.11 thorpej */ 1294 1.133 ad cpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*cpp), KM_SLEEP); 1295 1.133 ad vpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*vpp), KM_SLEEP); 1296 1.84 dsl error = copyin(ccio->ccio_disks, cpp, 1297 1.133 ad ccio->ccio_ndisks * sizeof(*cpp)); 1298 1.11 thorpej if (error) { 1299 1.133 ad kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp)); 1300 1.133 ad kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp)); 1301 1.57 thorpej goto out; 1302 1.11 thorpej } 1303 1.11 thorpej 1304 1.11 thorpej #ifdef DEBUG 1305 1.11 thorpej if (ccddebug & CCDB_INIT) 1306 1.11 thorpej for (i = 0; i < ccio->ccio_ndisks; ++i) 1307 1.104 christos printf("ccdioctl: component %d: %p\n", 1308 1.11 thorpej i, cpp[i]); 1309 1.11 thorpej #endif 1310 1.11 thorpej 1311 1.11 thorpej for (i = 0; i < ccio->ccio_ndisks; ++i) { 1312 1.11 thorpej #ifdef DEBUG 1313 1.11 thorpej if (ccddebug & CCDB_INIT) 1314 1.35 christos printf("ccdioctl: lookedup = %d\n", lookedup); 1315 1.11 thorpej #endif 1316 1.136 dholland error = pathbuf_copyin(cpp[i], &pb); 1317 1.137 dholland if (error == 0) { 1318 1.181 mlelstv error = vn_bdev_openpath(pb, &vpp[i], l); 1319 1.187 riastrad pathbuf_destroy(pb); 1320 1.136 dholland } 1321 1.136 dholland if (error != 0) { 1322 1.11 thorpej for (j = 0; j < lookedup; ++j) 1323 1.12 thorpej (void)vn_close(vpp[j], FREAD|FWRITE, 1324 1.128 ad uc); 1325 1.133 ad kmem_free(vpp, ccio->ccio_ndisks * 1326 1.133 ad sizeof(*vpp)); 1327 1.133 ad kmem_free(cpp, ccio->ccio_ndisks * 1328 1.133 ad sizeof(*cpp)); 1329 1.185 mlelstv 1330 1.185 mlelstv /* 1331 1.185 mlelstv * No component data is allocated, 1332 1.185 mlelstv * nothing is to be freed. 1333 1.185 mlelstv */ 1334 1.185 mlelstv cs->sc_nccdisks = 0; 1335 1.57 thorpej goto out; 1336 1.11 thorpej } 1337 1.11 thorpej ++lookedup; 1338 1.11 thorpej } 1339 1.11 thorpej 1340 1.133 ad /* Attach the disk. */ 1341 1.133 ad disk_attach(&cs->sc_dkdev); 1342 1.133 ad bufq_alloc(&cs->sc_bufq, "fcfs", 0); 1343 1.133 ad 1344 1.11 thorpej /* 1345 1.11 thorpej * Initialize the ccd. Fills in the softc for us. 1346 1.11 thorpej */ 1347 1.107 christos if ((error = ccdinit(cs, cpp, vpp, l)) != 0) { 1348 1.11 thorpej for (j = 0; j < lookedup; ++j) 1349 1.18 thorpej (void)vn_close(vpp[j], FREAD|FWRITE, 1350 1.128 ad uc); 1351 1.133 ad kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp)); 1352 1.133 ad kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp)); 1353 1.133 ad disk_detach(&cs->sc_dkdev); 1354 1.168 pgoyette mutex_exit(&cs->sc_dvlock); 1355 1.133 ad bufq_free(cs->sc_bufq); 1356 1.168 pgoyette return error; 1357 1.11 thorpej } 1358 1.11 thorpej 1359 1.57 thorpej /* We can free the temporary variables now. */ 1360 1.133 ad kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp)); 1361 1.133 ad kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp)); 1362 1.57 thorpej 1363 1.11 thorpej /* 1364 1.11 thorpej * The ccd has been successfully initialized, so 1365 1.23 thorpej * we can place it into the array. Don't try to 1366 1.23 thorpej * read the disklabel until the disk has been attached, 1367 1.23 thorpej * because space for the disklabel is allocated 1368 1.23 thorpej * in disk_attach(); 1369 1.11 thorpej */ 1370 1.11 thorpej ccio->ccio_unit = unit; 1371 1.11 thorpej ccio->ccio_size = cs->sc_size; 1372 1.23 thorpej 1373 1.23 thorpej /* Try and read the disklabel. */ 1374 1.11 thorpej ccdgetdisklabel(dev); 1375 1.157 mlelstv disk_set_info(NULL, &cs->sc_dkdev, NULL); 1376 1.157 mlelstv 1377 1.157 mlelstv /* discover wedges */ 1378 1.157 mlelstv mutex_exit(&cs->sc_dvlock); 1379 1.157 mlelstv dkwedge_discover(&cs->sc_dkdev); 1380 1.157 mlelstv return 0; 1381 1.11 thorpej 1382 1.11 thorpej case CCDIOCCLR: 1383 1.11 thorpej /* 1384 1.11 thorpej * Don't unconfigure if any other partitions are open 1385 1.11 thorpej * or if both the character and block flavors of this 1386 1.11 thorpej * partition are open. 1387 1.11 thorpej */ 1388 1.11 thorpej part = DISKPART(dev); 1389 1.11 thorpej pmask = (1 << part); 1390 1.11 thorpej if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1391 1.11 thorpej ((cs->sc_dkdev.dk_bopenmask & pmask) && 1392 1.15 thorpej (cs->sc_dkdev.dk_copenmask & pmask))) { 1393 1.57 thorpej error = EBUSY; 1394 1.57 thorpej goto out; 1395 1.15 thorpej } 1396 1.88 thorpej 1397 1.157 mlelstv /* Delete all of our wedges. */ 1398 1.157 mlelstv dkwedge_delall(&cs->sc_dkdev); 1399 1.157 mlelstv 1400 1.133 ad /* Stop new I/O, wait for in-flight I/O to complete. */ 1401 1.133 ad mutex_enter(cs->sc_iolock); 1402 1.133 ad cs->sc_flags &= ~(CCDF_INITED|CCDF_VLABEL); 1403 1.133 ad cs->sc_zap = true; 1404 1.133 ad while (disk_isbusy(&cs->sc_dkdev) || 1405 1.133 ad bufq_peek(cs->sc_bufq) != NULL || 1406 1.133 ad cs->sc_thread != NULL) { 1407 1.133 ad cv_broadcast(&cs->sc_push); 1408 1.133 ad (void)cv_timedwait(&cs->sc_stop, cs->sc_iolock, hz); 1409 1.133 ad } 1410 1.133 ad mutex_exit(cs->sc_iolock); 1411 1.11 thorpej 1412 1.11 thorpej /* 1413 1.11 thorpej * Free ccd_softc information and clear entry. 1414 1.11 thorpej */ 1415 1.22 thorpej 1416 1.22 thorpej /* Close the components and free their pathnames. */ 1417 1.11 thorpej for (i = 0; i < cs->sc_nccdisks; ++i) { 1418 1.11 thorpej /* 1419 1.11 thorpej * XXX: this close could potentially fail and 1420 1.11 thorpej * cause Bad Things. Maybe we need to force 1421 1.11 thorpej * the close to happen? 1422 1.11 thorpej */ 1423 1.11 thorpej #ifdef DEBUG 1424 1.11 thorpej if (ccddebug & CCDB_VNODE) 1425 1.11 thorpej vprint("CCDIOCCLR: vnode info", 1426 1.11 thorpej cs->sc_cinfo[i].ci_vp); 1427 1.11 thorpej #endif 1428 1.11 thorpej (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1429 1.128 ad uc); 1430 1.133 ad kmem_free(cs->sc_cinfo[i].ci_path, 1431 1.133 ad cs->sc_cinfo[i].ci_pathlen); 1432 1.38 thorpej } 1433 1.38 thorpej 1434 1.185 mlelstv if (cs->sc_nccdisks != 0) { 1435 1.185 mlelstv /* Free interleave index. */ 1436 1.185 mlelstv for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) { 1437 1.185 mlelstv kmem_free(cs->sc_itable[i].ii_index, 1438 1.185 mlelstv cs->sc_itable[i].ii_indexsz); 1439 1.185 mlelstv } 1440 1.185 mlelstv /* Free component info and interleave table. */ 1441 1.185 mlelstv kmem_free(cs->sc_cinfo, cs->sc_nccdisks * 1442 1.185 mlelstv sizeof(struct ccdcinfo)); 1443 1.185 mlelstv kmem_free(cs->sc_itable, (cs->sc_nccdisks + 1) * 1444 1.185 mlelstv sizeof(struct ccdiinfo)); 1445 1.133 ad } 1446 1.22 thorpej 1447 1.152 sborrill aprint_normal("%s: detached\n", cs->sc_xname); 1448 1.152 sborrill 1449 1.152 sborrill /* Detach the disk. */ 1450 1.123 ad disk_detach(&cs->sc_dkdev); 1451 1.133 ad bufq_free(cs->sc_bufq); 1452 1.185 mlelstv 1453 1.186 riastrad /* also releases sc_dvlock */ 1454 1.144 christos ccdput(cs); 1455 1.185 mlelstv 1456 1.148 joerg /* Don't break, otherwise cs is read again. */ 1457 1.148 joerg return 0; 1458 1.11 thorpej 1459 1.170 jdolecek case DIOCGCACHE: 1460 1.170 jdolecek { 1461 1.170 jdolecek int dkcache = 0; 1462 1.170 jdolecek 1463 1.170 jdolecek /* 1464 1.170 jdolecek * We pass this call down to all components and report 1465 1.170 jdolecek * intersection of the flags returned by the components. 1466 1.170 jdolecek * If any errors out, we return error. CCD components 1467 1.170 jdolecek * can not change unless the device is unconfigured, so 1468 1.170 jdolecek * device feature flags will remain static. RCE/WCE can change 1469 1.170 jdolecek * of course, if set directly on underlying device. 1470 1.170 jdolecek */ 1471 1.170 jdolecek for (error = 0, i = 0; i < cs->sc_nccdisks; i++) { 1472 1.170 jdolecek error = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, &j, 1473 1.170 jdolecek flag, uc); 1474 1.170 jdolecek if (error) 1475 1.170 jdolecek break; 1476 1.170 jdolecek 1477 1.170 jdolecek if (i == 0) 1478 1.170 jdolecek dkcache = j; 1479 1.170 jdolecek else 1480 1.171 jdolecek dkcache = DKCACHE_COMBINE(dkcache, j); 1481 1.170 jdolecek } 1482 1.170 jdolecek 1483 1.170 jdolecek *((int *)data) = dkcache; 1484 1.170 jdolecek break; 1485 1.170 jdolecek } 1486 1.170 jdolecek 1487 1.100 thorpej case DIOCCACHESYNC: 1488 1.100 thorpej /* 1489 1.100 thorpej * We pass this call down to all components and report 1490 1.100 thorpej * the first error we encounter. 1491 1.100 thorpej */ 1492 1.100 thorpej for (error = 0, i = 0; i < cs->sc_nccdisks; i++) { 1493 1.100 thorpej j = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, data, 1494 1.124 pooka flag, uc); 1495 1.100 thorpej if (j != 0 && error == 0) 1496 1.100 thorpej error = j; 1497 1.100 thorpej } 1498 1.100 thorpej break; 1499 1.100 thorpej 1500 1.185 mlelstv default: 1501 1.185 mlelstv error = ENOTTY; 1502 1.11 thorpej break; 1503 1.70 fvdl } 1504 1.11 thorpej 1505 1.57 thorpej out: 1506 1.133 ad mutex_exit(&cs->sc_dvlock); 1507 1.57 thorpej return (error); 1508 1.1 hpeyerl } 1509 1.1 hpeyerl 1510 1.97 thorpej static int 1511 1.97 thorpej ccdsize(dev_t dev) 1512 1.1 hpeyerl { 1513 1.11 thorpej struct ccd_softc *cs; 1514 1.40 thorpej struct disklabel *lp; 1515 1.40 thorpej int part, unit, omask, size; 1516 1.40 thorpej 1517 1.40 thorpej unit = ccdunit(dev); 1518 1.158 christos if ((cs = ccdget(unit, 0)) == NULL) 1519 1.144 christos return -1; 1520 1.11 thorpej 1521 1.40 thorpej if ((cs->sc_flags & CCDF_INITED) == 0) 1522 1.11 thorpej return (-1); 1523 1.11 thorpej 1524 1.11 thorpej part = DISKPART(dev); 1525 1.40 thorpej omask = cs->sc_dkdev.dk_openmask & (1 << part); 1526 1.40 thorpej lp = cs->sc_dkdev.dk_label; 1527 1.11 thorpej 1528 1.107 christos if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curlwp)) 1529 1.11 thorpej return (-1); 1530 1.11 thorpej 1531 1.40 thorpej if (lp->d_partitions[part].p_fstype != FS_SWAP) 1532 1.11 thorpej size = -1; 1533 1.11 thorpej else 1534 1.40 thorpej size = lp->d_partitions[part].p_size * 1535 1.40 thorpej (lp->d_secsize / DEV_BSIZE); 1536 1.11 thorpej 1537 1.107 christos if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curlwp)) 1538 1.11 thorpej return (-1); 1539 1.1 hpeyerl 1540 1.11 thorpej return (size); 1541 1.1 hpeyerl } 1542 1.1 hpeyerl 1543 1.11 thorpej static void 1544 1.97 thorpej ccdgetdefaultlabel(struct ccd_softc *cs, struct disklabel *lp) 1545 1.11 thorpej { 1546 1.11 thorpej struct ccdgeom *ccg = &cs->sc_geom; 1547 1.11 thorpej 1548 1.72 thorpej memset(lp, 0, sizeof(*lp)); 1549 1.11 thorpej 1550 1.153 mlelstv if (cs->sc_size > UINT32_MAX) 1551 1.153 mlelstv lp->d_secperunit = UINT32_MAX; 1552 1.153 mlelstv else 1553 1.153 mlelstv lp->d_secperunit = cs->sc_size; 1554 1.11 thorpej lp->d_secsize = ccg->ccg_secsize; 1555 1.11 thorpej lp->d_nsectors = ccg->ccg_nsectors; 1556 1.11 thorpej lp->d_ntracks = ccg->ccg_ntracks; 1557 1.11 thorpej lp->d_ncylinders = ccg->ccg_ncylinders; 1558 1.19 thorpej lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1559 1.11 thorpej 1560 1.11 thorpej strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1561 1.162 christos lp->d_type = DKTYPE_CCD; 1562 1.11 thorpej strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1563 1.11 thorpej lp->d_rpm = 3600; 1564 1.11 thorpej lp->d_interleave = 1; 1565 1.11 thorpej lp->d_flags = 0; 1566 1.11 thorpej 1567 1.11 thorpej lp->d_partitions[RAW_PART].p_offset = 0; 1568 1.153 mlelstv lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; 1569 1.11 thorpej lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1570 1.11 thorpej lp->d_npartitions = RAW_PART + 1; 1571 1.11 thorpej 1572 1.11 thorpej lp->d_magic = DISKMAGIC; 1573 1.11 thorpej lp->d_magic2 = DISKMAGIC; 1574 1.23 thorpej lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label); 1575 1.44 thorpej } 1576 1.44 thorpej 1577 1.44 thorpej /* 1578 1.44 thorpej * Read the disklabel from the ccd. If one is not present, fake one 1579 1.44 thorpej * up. 1580 1.44 thorpej */ 1581 1.44 thorpej static void 1582 1.97 thorpej ccdgetdisklabel(dev_t dev) 1583 1.44 thorpej { 1584 1.44 thorpej int unit = ccdunit(dev); 1585 1.144 christos struct ccd_softc *cs; 1586 1.85 dsl const char *errstring; 1587 1.144 christos struct disklabel *lp; 1588 1.144 christos struct cpu_disklabel *clp; 1589 1.44 thorpej 1590 1.158 christos if ((cs = ccdget(unit, 0)) == NULL) 1591 1.144 christos return; 1592 1.144 christos lp = cs->sc_dkdev.dk_label; 1593 1.144 christos clp = cs->sc_dkdev.dk_cpulabel; 1594 1.133 ad KASSERT(mutex_owned(&cs->sc_dvlock)); 1595 1.133 ad 1596 1.72 thorpej memset(clp, 0, sizeof(*clp)); 1597 1.44 thorpej 1598 1.44 thorpej ccdgetdefaultlabel(cs, lp); 1599 1.11 thorpej 1600 1.11 thorpej /* 1601 1.11 thorpej * Call the generic disklabel extraction routine. 1602 1.11 thorpej */ 1603 1.133 ad cs->sc_flags |= CCDF_RLABEL; 1604 1.92 lukem if ((cs->sc_flags & CCDF_NOLABEL) != 0) 1605 1.92 lukem errstring = "CCDF_NOLABEL set; ignoring on-disk label"; 1606 1.92 lukem else 1607 1.92 lukem errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1608 1.92 lukem cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel); 1609 1.29 christos if (errstring) 1610 1.11 thorpej ccdmakedisklabel(cs); 1611 1.47 enami else { 1612 1.47 enami int i; 1613 1.47 enami struct partition *pp; 1614 1.47 enami 1615 1.47 enami /* 1616 1.47 enami * Sanity check whether the found disklabel is valid. 1617 1.47 enami * 1618 1.47 enami * This is necessary since total size of ccd may vary 1619 1.47 enami * when an interleave is changed even though exactly 1620 1.192 andvar * same components are used, and old disklabel may used 1621 1.47 enami * if that is found. 1622 1.47 enami */ 1623 1.154 mlelstv if (lp->d_secperunit < UINT32_MAX ? 1624 1.154 mlelstv lp->d_secperunit != cs->sc_size : 1625 1.154 mlelstv lp->d_secperunit > cs->sc_size) 1626 1.47 enami printf("WARNING: %s: " 1627 1.152 sborrill "total sector size in disklabel (%ju) != " 1628 1.152 sborrill "the size of ccd (%ju)\n", cs->sc_xname, 1629 1.152 sborrill (uintmax_t)lp->d_secperunit, 1630 1.152 sborrill (uintmax_t)cs->sc_size); 1631 1.47 enami for (i = 0; i < lp->d_npartitions; i++) { 1632 1.47 enami pp = &lp->d_partitions[i]; 1633 1.47 enami if (pp->p_offset + pp->p_size > cs->sc_size) 1634 1.48 enami printf("WARNING: %s: end of partition `%c' " 1635 1.152 sborrill "exceeds the size of ccd (%ju)\n", 1636 1.152 sborrill cs->sc_xname, 'a' + i, (uintmax_t)cs->sc_size); 1637 1.47 enami } 1638 1.47 enami } 1639 1.11 thorpej 1640 1.11 thorpej #ifdef DEBUG 1641 1.11 thorpej /* It's actually extremely common to have unlabeled ccds. */ 1642 1.11 thorpej if (ccddebug & CCDB_LABEL) 1643 1.11 thorpej if (errstring != NULL) 1644 1.35 christos printf("%s: %s\n", cs->sc_xname, errstring); 1645 1.11 thorpej #endif 1646 1.87 thorpej 1647 1.87 thorpej /* In-core label now valid. */ 1648 1.133 ad cs->sc_flags = (cs->sc_flags | CCDF_VLABEL) & ~CCDF_RLABEL; 1649 1.11 thorpej } 1650 1.11 thorpej 1651 1.11 thorpej /* 1652 1.11 thorpej * Take care of things one might want to take care of in the event 1653 1.11 thorpej * that a disklabel isn't present. 1654 1.11 thorpej */ 1655 1.11 thorpej static void 1656 1.97 thorpej ccdmakedisklabel(struct ccd_softc *cs) 1657 1.11 thorpej { 1658 1.23 thorpej struct disklabel *lp = cs->sc_dkdev.dk_label; 1659 1.11 thorpej 1660 1.11 thorpej /* 1661 1.11 thorpej * For historical reasons, if there's no disklabel present 1662 1.11 thorpej * the raw partition must be marked FS_BSDFFS. 1663 1.11 thorpej */ 1664 1.11 thorpej lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1665 1.11 thorpej 1666 1.11 thorpej strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1667 1.44 thorpej 1668 1.44 thorpej lp->d_checksum = dkcksum(lp); 1669 1.11 thorpej } 1670 1.11 thorpej 1671 1.11 thorpej #ifdef DEBUG 1672 1.11 thorpej static void 1673 1.97 thorpej printiinfo(struct ccdiinfo *ii) 1674 1.11 thorpej { 1675 1.68 augustss int ix, i; 1676 1.11 thorpej 1677 1.11 thorpej for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1678 1.81 kleink printf(" itab[%d]: #dk %d sblk %" PRId64 " soff %" PRId64, 1679 1.34 christos ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1680 1.11 thorpej for (i = 0; i < ii->ii_ndisk; i++) 1681 1.35 christos printf(" %d", ii->ii_index[i]); 1682 1.35 christos printf("\n"); 1683 1.11 thorpej } 1684 1.1 hpeyerl } 1685 1.1 hpeyerl #endif 1686 1.134 haad 1687 1.175 pgoyette MODULE(MODULE_CLASS_DRIVER, ccd, "dk_subr,bufq_fcfs"); 1688 1.134 haad 1689 1.134 haad static int 1690 1.134 haad ccd_modcmd(modcmd_t cmd, void *arg) 1691 1.134 haad { 1692 1.145 martin int error = 0; 1693 1.145 martin #ifdef _MODULE 1694 1.145 martin int bmajor = -1, cmajor = -1; 1695 1.145 martin #endif 1696 1.140 jruoho 1697 1.140 jruoho 1698 1.134 haad switch (cmd) { 1699 1.134 haad case MODULE_CMD_INIT: 1700 1.140 jruoho #ifdef _MODULE 1701 1.158 christos ccdattach(0); 1702 1.140 jruoho 1703 1.158 christos error = devsw_attach("ccd", &ccd_bdevsw, &bmajor, 1704 1.134 haad &ccd_cdevsw, &cmajor); 1705 1.140 jruoho #endif 1706 1.134 haad break; 1707 1.134 haad 1708 1.134 haad case MODULE_CMD_FINI: 1709 1.140 jruoho #ifdef _MODULE 1710 1.158 christos mutex_enter(&ccd_lock); 1711 1.174 pgoyette if (!LIST_EMPTY(&ccds)) { 1712 1.159 christos mutex_exit(&ccd_lock); 1713 1.158 christos error = EBUSY; 1714 1.159 christos } else { 1715 1.159 christos mutex_exit(&ccd_lock); 1716 1.188 riastrad devsw_detach(&ccd_bdevsw, &ccd_cdevsw); 1717 1.159 christos ccddetach(); 1718 1.159 christos } 1719 1.140 jruoho #endif 1720 1.134 haad break; 1721 1.134 haad 1722 1.134 haad case MODULE_CMD_STAT: 1723 1.134 haad return ENOTTY; 1724 1.134 haad 1725 1.134 haad default: 1726 1.134 haad return ENOTTY; 1727 1.134 haad } 1728 1.134 haad 1729 1.134 haad return error; 1730 1.134 haad } 1731 1.144 christos 1732 1.144 christos static int 1733 1.144 christos ccd_units_sysctl(SYSCTLFN_ARGS) 1734 1.144 christos { 1735 1.144 christos struct sysctlnode node; 1736 1.144 christos struct ccd_softc *sc; 1737 1.144 christos int error, i, nccd, *units; 1738 1.144 christos size_t size; 1739 1.144 christos 1740 1.144 christos nccd = 0; 1741 1.144 christos mutex_enter(&ccd_lock); 1742 1.144 christos LIST_FOREACH(sc, &ccds, sc_link) 1743 1.144 christos nccd++; 1744 1.144 christos mutex_exit(&ccd_lock); 1745 1.144 christos 1746 1.144 christos if (nccd != 0) { 1747 1.144 christos size = nccd * sizeof(*units); 1748 1.144 christos units = kmem_zalloc(size, KM_SLEEP); 1749 1.144 christos i = 0; 1750 1.144 christos mutex_enter(&ccd_lock); 1751 1.144 christos LIST_FOREACH(sc, &ccds, sc_link) { 1752 1.144 christos if (i >= nccd) 1753 1.144 christos break; 1754 1.144 christos units[i] = sc->sc_unit; 1755 1.144 christos } 1756 1.144 christos mutex_exit(&ccd_lock); 1757 1.144 christos } else { 1758 1.144 christos units = NULL; 1759 1.144 christos size = 0; 1760 1.144 christos } 1761 1.144 christos 1762 1.144 christos node = *rnode; 1763 1.144 christos node.sysctl_data = units; 1764 1.144 christos node.sysctl_size = size; 1765 1.144 christos 1766 1.144 christos error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1767 1.144 christos if (units) 1768 1.144 christos kmem_free(units, size); 1769 1.144 christos return error; 1770 1.144 christos } 1771 1.144 christos 1772 1.144 christos static int 1773 1.144 christos ccd_info_sysctl(SYSCTLFN_ARGS) 1774 1.144 christos { 1775 1.144 christos struct sysctlnode node; 1776 1.144 christos struct ccddiskinfo ccd; 1777 1.144 christos struct ccd_softc *sc; 1778 1.191 pgoyette int unit, error; 1779 1.144 christos 1780 1.144 christos if (newp == NULL || newlen != sizeof(int)) 1781 1.144 christos return EINVAL; 1782 1.144 christos 1783 1.191 pgoyette error = sysctl_copyin(l, newp, &unit, sizeof unit); 1784 1.191 pgoyette if (error) 1785 1.191 pgoyette return error; 1786 1.144 christos newlen = 0; 1787 1.144 christos ccd.ccd_ndisks = ~0; 1788 1.144 christos mutex_enter(&ccd_lock); 1789 1.144 christos LIST_FOREACH(sc, &ccds, sc_link) { 1790 1.144 christos if (sc->sc_unit == unit) { 1791 1.144 christos ccd.ccd_ileave = sc->sc_ileave; 1792 1.144 christos ccd.ccd_size = sc->sc_size; 1793 1.144 christos ccd.ccd_ndisks = sc->sc_nccdisks; 1794 1.144 christos ccd.ccd_flags = sc->sc_flags; 1795 1.144 christos break; 1796 1.144 christos } 1797 1.144 christos } 1798 1.144 christos mutex_exit(&ccd_lock); 1799 1.144 christos 1800 1.144 christos if (ccd.ccd_ndisks == ~0) 1801 1.144 christos return ENOENT; 1802 1.144 christos 1803 1.144 christos node = *rnode; 1804 1.144 christos node.sysctl_data = &ccd; 1805 1.144 christos node.sysctl_size = sizeof(ccd); 1806 1.144 christos 1807 1.144 christos return sysctl_lookup(SYSCTLFN_CALL(&node)); 1808 1.144 christos } 1809 1.144 christos 1810 1.144 christos static int 1811 1.144 christos ccd_components_sysctl(SYSCTLFN_ARGS) 1812 1.144 christos { 1813 1.144 christos struct sysctlnode node; 1814 1.144 christos int error, unit; 1815 1.144 christos size_t size; 1816 1.144 christos char *names, *p, *ep; 1817 1.144 christos struct ccd_softc *sc; 1818 1.144 christos 1819 1.144 christos if (newp == NULL || newlen != sizeof(int)) 1820 1.144 christos return EINVAL; 1821 1.144 christos 1822 1.144 christos size = 0; 1823 1.191 pgoyette error = sysctl_copyin(l, newp, &unit, sizeof unit); 1824 1.191 pgoyette if (error) 1825 1.191 pgoyette return error; 1826 1.144 christos newlen = 0; 1827 1.144 christos mutex_enter(&ccd_lock); 1828 1.144 christos LIST_FOREACH(sc, &ccds, sc_link) 1829 1.144 christos if (sc->sc_unit == unit) { 1830 1.144 christos for (size_t i = 0; i < sc->sc_nccdisks; i++) 1831 1.144 christos size += strlen(sc->sc_cinfo[i].ci_path) + 1; 1832 1.144 christos break; 1833 1.144 christos } 1834 1.144 christos mutex_exit(&ccd_lock); 1835 1.144 christos 1836 1.144 christos if (size == 0) 1837 1.144 christos return ENOENT; 1838 1.164 skrll names = kmem_zalloc(size, KM_SLEEP); 1839 1.144 christos p = names; 1840 1.144 christos ep = names + size; 1841 1.144 christos mutex_enter(&ccd_lock); 1842 1.144 christos LIST_FOREACH(sc, &ccds, sc_link) 1843 1.144 christos if (sc->sc_unit == unit) { 1844 1.144 christos for (size_t i = 0; i < sc->sc_nccdisks; i++) { 1845 1.144 christos char *d = sc->sc_cinfo[i].ci_path; 1846 1.164 skrll while (p < ep && (*p++ = *d++) != '\0') 1847 1.144 christos continue; 1848 1.144 christos } 1849 1.144 christos break; 1850 1.144 christos } 1851 1.144 christos mutex_exit(&ccd_lock); 1852 1.144 christos 1853 1.144 christos node = *rnode; 1854 1.144 christos node.sysctl_data = names; 1855 1.144 christos node.sysctl_size = ep - names; 1856 1.144 christos 1857 1.144 christos error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1858 1.144 christos kmem_free(names, size); 1859 1.144 christos return error; 1860 1.144 christos } 1861 1.144 christos 1862 1.144 christos SYSCTL_SETUP(sysctl_kern_ccd_setup, "sysctl kern.ccd subtree setup") 1863 1.144 christos { 1864 1.144 christos const struct sysctlnode *node = NULL; 1865 1.144 christos 1866 1.144 christos sysctl_createv(clog, 0, NULL, &node, 1867 1.144 christos CTLFLAG_PERMANENT, 1868 1.144 christos CTLTYPE_NODE, "ccd", 1869 1.144 christos SYSCTL_DESCR("ConCatenated Disk state"), 1870 1.144 christos NULL, 0, NULL, 0, 1871 1.144 christos CTL_KERN, CTL_CREATE, CTL_EOL); 1872 1.144 christos 1873 1.144 christos if (node == NULL) 1874 1.144 christos return; 1875 1.144 christos 1876 1.144 christos sysctl_createv(clog, 0, &node, NULL, 1877 1.144 christos CTLFLAG_PERMANENT | CTLFLAG_READONLY, 1878 1.144 christos CTLTYPE_STRUCT, "units", 1879 1.144 christos SYSCTL_DESCR("List of ccd unit numbers"), 1880 1.144 christos ccd_units_sysctl, 0, NULL, 0, 1881 1.144 christos CTL_CREATE, CTL_EOL); 1882 1.144 christos sysctl_createv(clog, 0, &node, NULL, 1883 1.144 christos CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1884 1.144 christos CTLTYPE_STRUCT, "info", 1885 1.144 christos SYSCTL_DESCR("Information about a CCD unit"), 1886 1.144 christos ccd_info_sysctl, 0, NULL, 0, 1887 1.144 christos CTL_CREATE, CTL_EOL); 1888 1.144 christos sysctl_createv(clog, 0, &node, NULL, 1889 1.144 christos CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1890 1.144 christos CTLTYPE_STRUCT, "components", 1891 1.144 christos SYSCTL_DESCR("Information about CCD components"), 1892 1.144 christos ccd_components_sysctl, 0, NULL, 0, 1893 1.144 christos CTL_CREATE, CTL_EOL); 1894 1.144 christos } 1895