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