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