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