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