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