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