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