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