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