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