1 /* $NetBSD: ccd.c,v 1.104 2005/05/22 15:54:46 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.104 2005/05/22 15:54:46 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 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 ccd_softc *cs; 988 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 989 struct ucred *uc; 990 char **cpp; 991 struct vnode **vpp; 992 #ifdef __HAVE_OLD_DISKLABEL 993 struct disklabel newlabel; 994 #endif 995 996 if (unit >= numccd) 997 return (ENXIO); 998 cs = &ccd_softc[unit]; 999 1000 /* Must be open for writes for these commands... */ 1001 switch (cmd) { 1002 case CCDIOCSET: 1003 case CCDIOCCLR: 1004 case DIOCSDINFO: 1005 case DIOCWDINFO: 1006 #ifdef __HAVE_OLD_DISKLABEL 1007 case ODIOCSDINFO: 1008 case ODIOCWDINFO: 1009 #endif 1010 case DIOCKLABEL: 1011 case DIOCWLABEL: 1012 if ((flag & FWRITE) == 0) 1013 return (EBADF); 1014 } 1015 1016 if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0) 1017 return (error); 1018 1019 /* Must be initialized for these... */ 1020 switch (cmd) { 1021 case CCDIOCCLR: 1022 case DIOCGDINFO: 1023 case DIOCCACHESYNC: 1024 case DIOCSDINFO: 1025 case DIOCWDINFO: 1026 case DIOCGPART: 1027 case DIOCWLABEL: 1028 case DIOCKLABEL: 1029 case DIOCGDEFLABEL: 1030 #ifdef __HAVE_OLD_DISKLABEL 1031 case ODIOCGDINFO: 1032 case ODIOCSDINFO: 1033 case ODIOCWDINFO: 1034 case ODIOCGDEFLABEL: 1035 #endif 1036 if ((cs->sc_flags & CCDF_INITED) == 0) { 1037 error = ENXIO; 1038 goto out; 1039 } 1040 } 1041 1042 switch (cmd) { 1043 case CCDIOCSET: 1044 if (cs->sc_flags & CCDF_INITED) { 1045 error = EBUSY; 1046 goto out; 1047 } 1048 1049 /* Validate the flags. */ 1050 if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) { 1051 error = EINVAL; 1052 goto out; 1053 } 1054 1055 if (ccio->ccio_ndisks > CCD_MAXNDISKS) { 1056 error = EINVAL; 1057 goto out; 1058 } 1059 1060 /* Fill in some important bits. */ 1061 cs->sc_ileave = ccio->ccio_ileave; 1062 cs->sc_nccdisks = ccio->ccio_ndisks; 1063 cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK; 1064 1065 /* 1066 * Allocate space for and copy in the array of 1067 * componet pathnames and device numbers. 1068 */ 1069 cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1070 M_DEVBUF, M_WAITOK); 1071 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1072 M_DEVBUF, M_WAITOK); 1073 1074 error = copyin(ccio->ccio_disks, cpp, 1075 ccio->ccio_ndisks * sizeof(char **)); 1076 if (error) { 1077 free(vpp, M_DEVBUF); 1078 free(cpp, M_DEVBUF); 1079 goto out; 1080 } 1081 1082 #ifdef DEBUG 1083 if (ccddebug & CCDB_INIT) 1084 for (i = 0; i < ccio->ccio_ndisks; ++i) 1085 printf("ccdioctl: component %d: %p\n", 1086 i, cpp[i]); 1087 #endif 1088 1089 for (i = 0; i < ccio->ccio_ndisks; ++i) { 1090 #ifdef DEBUG 1091 if (ccddebug & CCDB_INIT) 1092 printf("ccdioctl: lookedup = %d\n", lookedup); 1093 #endif 1094 if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) { 1095 for (j = 0; j < lookedup; ++j) 1096 (void)vn_close(vpp[j], FREAD|FWRITE, 1097 p->p_ucred, p); 1098 free(vpp, M_DEVBUF); 1099 free(cpp, M_DEVBUF); 1100 goto out; 1101 } 1102 ++lookedup; 1103 } 1104 1105 /* 1106 * Initialize the ccd. Fills in the softc for us. 1107 */ 1108 if ((error = ccdinit(cs, cpp, vpp, p)) != 0) { 1109 for (j = 0; j < lookedup; ++j) 1110 (void)vn_close(vpp[j], FREAD|FWRITE, 1111 p->p_ucred, p); 1112 free(vpp, M_DEVBUF); 1113 free(cpp, M_DEVBUF); 1114 goto out; 1115 } 1116 1117 /* We can free the temporary variables now. */ 1118 free(vpp, M_DEVBUF); 1119 free(cpp, M_DEVBUF); 1120 1121 /* 1122 * The ccd has been successfully initialized, so 1123 * we can place it into the array. Don't try to 1124 * read the disklabel until the disk has been attached, 1125 * because space for the disklabel is allocated 1126 * in disk_attach(); 1127 */ 1128 ccio->ccio_unit = unit; 1129 ccio->ccio_size = cs->sc_size; 1130 1131 bufq_alloc(&cs->sc_bufq, BUFQ_FCFS); 1132 1133 /* Attach the disk. */ 1134 disk_attach(&cs->sc_dkdev); 1135 1136 /* Try and read the disklabel. */ 1137 ccdgetdisklabel(dev); 1138 break; 1139 1140 case CCDIOCCLR: 1141 /* 1142 * Don't unconfigure if any other partitions are open 1143 * or if both the character and block flavors of this 1144 * partition are open. 1145 */ 1146 part = DISKPART(dev); 1147 pmask = (1 << part); 1148 if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1149 ((cs->sc_dkdev.dk_bopenmask & pmask) && 1150 (cs->sc_dkdev.dk_copenmask & pmask))) { 1151 error = EBUSY; 1152 goto out; 1153 } 1154 1155 /* Kill off any queued buffers. */ 1156 s = splbio(); 1157 bufq_drain(&cs->sc_bufq); 1158 splx(s); 1159 1160 bufq_free(&cs->sc_bufq); 1161 1162 /* 1163 * Free ccd_softc information and clear entry. 1164 */ 1165 1166 /* Close the components and free their pathnames. */ 1167 for (i = 0; i < cs->sc_nccdisks; ++i) { 1168 /* 1169 * XXX: this close could potentially fail and 1170 * cause Bad Things. Maybe we need to force 1171 * the close to happen? 1172 */ 1173 #ifdef DEBUG 1174 if (ccddebug & CCDB_VNODE) 1175 vprint("CCDIOCCLR: vnode info", 1176 cs->sc_cinfo[i].ci_vp); 1177 #endif 1178 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1179 p->p_ucred, p); 1180 free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1181 } 1182 1183 /* Free interleave index. */ 1184 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1185 free(cs->sc_itable[i].ii_index, M_DEVBUF); 1186 1187 /* Free component info and interleave table. */ 1188 free(cs->sc_cinfo, M_DEVBUF); 1189 free(cs->sc_itable, M_DEVBUF); 1190 cs->sc_flags &= ~(CCDF_INITED|CCDF_VLABEL); 1191 1192 /* Detatch the disk. */ 1193 disk_detach(&cs->sc_dkdev); 1194 break; 1195 1196 case DIOCGDINFO: 1197 *(struct disklabel *)data = *(cs->sc_dkdev.dk_label); 1198 break; 1199 #ifdef __HAVE_OLD_DISKLABEL 1200 case ODIOCGDINFO: 1201 newlabel = *(cs->sc_dkdev.dk_label); 1202 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1203 return ENOTTY; 1204 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1205 break; 1206 #endif 1207 1208 case DIOCGPART: 1209 ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label; 1210 ((struct partinfo *)data)->part = 1211 &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 1212 break; 1213 1214 case DIOCCACHESYNC: 1215 /* 1216 * XXX Do we really need to care about having a writable 1217 * file descriptor here? 1218 */ 1219 if ((flag & FWRITE) == 0) 1220 return (EBADF); 1221 1222 /* 1223 * We pass this call down to all components and report 1224 * the first error we encounter. 1225 */ 1226 uc = (p != NULL) ? p->p_ucred : NOCRED; 1227 for (error = 0, i = 0; i < cs->sc_nccdisks; i++) { 1228 j = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, data, 1229 flag, uc, p); 1230 if (j != 0 && error == 0) 1231 error = j; 1232 } 1233 break; 1234 1235 case DIOCWDINFO: 1236 case DIOCSDINFO: 1237 #ifdef __HAVE_OLD_DISKLABEL 1238 case ODIOCWDINFO: 1239 case ODIOCSDINFO: 1240 #endif 1241 { 1242 struct disklabel *lp; 1243 #ifdef __HAVE_OLD_DISKLABEL 1244 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 1245 memset(&newlabel, 0, sizeof newlabel); 1246 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 1247 lp = &newlabel; 1248 } else 1249 #endif 1250 lp = (struct disklabel *)data; 1251 1252 cs->sc_flags |= CCDF_LABELLING; 1253 1254 error = setdisklabel(cs->sc_dkdev.dk_label, 1255 lp, 0, cs->sc_dkdev.dk_cpulabel); 1256 if (error == 0) { 1257 if (cmd == DIOCWDINFO 1258 #ifdef __HAVE_OLD_DISKLABEL 1259 || cmd == ODIOCWDINFO 1260 #endif 1261 ) 1262 error = writedisklabel(CCDLABELDEV(dev), 1263 ccdstrategy, cs->sc_dkdev.dk_label, 1264 cs->sc_dkdev.dk_cpulabel); 1265 } 1266 1267 cs->sc_flags &= ~CCDF_LABELLING; 1268 break; 1269 } 1270 1271 case DIOCKLABEL: 1272 if (*(int *)data != 0) 1273 cs->sc_flags |= CCDF_KLABEL; 1274 else 1275 cs->sc_flags &= ~CCDF_KLABEL; 1276 break; 1277 1278 case DIOCWLABEL: 1279 if (*(int *)data != 0) 1280 cs->sc_flags |= CCDF_WLABEL; 1281 else 1282 cs->sc_flags &= ~CCDF_WLABEL; 1283 break; 1284 1285 case DIOCGDEFLABEL: 1286 ccdgetdefaultlabel(cs, (struct disklabel *)data); 1287 break; 1288 1289 #ifdef __HAVE_OLD_DISKLABEL 1290 case ODIOCGDEFLABEL: 1291 ccdgetdefaultlabel(cs, &newlabel); 1292 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 1293 return ENOTTY; 1294 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 1295 break; 1296 #endif 1297 1298 default: 1299 error = ENOTTY; 1300 } 1301 1302 out: 1303 (void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL); 1304 return (error); 1305 } 1306 1307 static int 1308 ccdsize(dev_t dev) 1309 { 1310 struct ccd_softc *cs; 1311 struct disklabel *lp; 1312 int part, unit, omask, size; 1313 1314 unit = ccdunit(dev); 1315 if (unit >= numccd) 1316 return (-1); 1317 cs = &ccd_softc[unit]; 1318 1319 if ((cs->sc_flags & CCDF_INITED) == 0) 1320 return (-1); 1321 1322 part = DISKPART(dev); 1323 omask = cs->sc_dkdev.dk_openmask & (1 << part); 1324 lp = cs->sc_dkdev.dk_label; 1325 1326 if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc)) 1327 return (-1); 1328 1329 if (lp->d_partitions[part].p_fstype != FS_SWAP) 1330 size = -1; 1331 else 1332 size = lp->d_partitions[part].p_size * 1333 (lp->d_secsize / DEV_BSIZE); 1334 1335 if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc)) 1336 return (-1); 1337 1338 return (size); 1339 } 1340 1341 static int 1342 ccddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 1343 { 1344 1345 /* Not implemented. */ 1346 return ENXIO; 1347 } 1348 1349 /* 1350 * Lookup the provided name in the filesystem. If the file exists, 1351 * is a valid block device, and isn't being used by anyone else, 1352 * set *vpp to the file's vnode. 1353 */ 1354 static int 1355 ccdlookup(char *path, struct proc *p, struct vnode **vpp /* result */) 1356 { 1357 struct nameidata nd; 1358 struct vnode *vp; 1359 struct vattr va; 1360 int error; 1361 1362 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1363 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 1364 #ifdef DEBUG 1365 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 1366 printf("ccdlookup: vn_open error = %d\n", error); 1367 #endif 1368 return (error); 1369 } 1370 vp = nd.ni_vp; 1371 1372 if (vp->v_usecount > 1) { 1373 VOP_UNLOCK(vp, 0); 1374 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1375 return (EBUSY); 1376 } 1377 1378 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) { 1379 #ifdef DEBUG 1380 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 1381 printf("ccdlookup: getattr error = %d\n", error); 1382 #endif 1383 VOP_UNLOCK(vp, 0); 1384 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1385 return (error); 1386 } 1387 1388 /* XXX: eventually we should handle VREG, too. */ 1389 if (va.va_type != VBLK) { 1390 VOP_UNLOCK(vp, 0); 1391 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1392 return (ENOTBLK); 1393 } 1394 1395 #ifdef DEBUG 1396 if (ccddebug & CCDB_VNODE) 1397 vprint("ccdlookup: vnode info", vp); 1398 #endif 1399 1400 VOP_UNLOCK(vp, 0); 1401 *vpp = vp; 1402 return (0); 1403 } 1404 1405 static void 1406 ccdgetdefaultlabel(struct ccd_softc *cs, struct disklabel *lp) 1407 { 1408 struct ccdgeom *ccg = &cs->sc_geom; 1409 1410 memset(lp, 0, sizeof(*lp)); 1411 1412 lp->d_secperunit = cs->sc_size; 1413 lp->d_secsize = ccg->ccg_secsize; 1414 lp->d_nsectors = ccg->ccg_nsectors; 1415 lp->d_ntracks = ccg->ccg_ntracks; 1416 lp->d_ncylinders = ccg->ccg_ncylinders; 1417 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1418 1419 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1420 lp->d_type = DTYPE_CCD; 1421 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1422 lp->d_rpm = 3600; 1423 lp->d_interleave = 1; 1424 lp->d_flags = 0; 1425 1426 lp->d_partitions[RAW_PART].p_offset = 0; 1427 lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1428 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1429 lp->d_npartitions = RAW_PART + 1; 1430 1431 lp->d_magic = DISKMAGIC; 1432 lp->d_magic2 = DISKMAGIC; 1433 lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label); 1434 } 1435 1436 /* 1437 * Read the disklabel from the ccd. If one is not present, fake one 1438 * up. 1439 */ 1440 static void 1441 ccdgetdisklabel(dev_t dev) 1442 { 1443 int unit = ccdunit(dev); 1444 struct ccd_softc *cs = &ccd_softc[unit]; 1445 const char *errstring; 1446 struct disklabel *lp = cs->sc_dkdev.dk_label; 1447 struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel; 1448 1449 memset(clp, 0, sizeof(*clp)); 1450 1451 ccdgetdefaultlabel(cs, lp); 1452 1453 /* 1454 * Call the generic disklabel extraction routine. 1455 */ 1456 if ((cs->sc_flags & CCDF_NOLABEL) != 0) 1457 errstring = "CCDF_NOLABEL set; ignoring on-disk label"; 1458 else 1459 errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1460 cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel); 1461 if (errstring) 1462 ccdmakedisklabel(cs); 1463 else { 1464 int i; 1465 struct partition *pp; 1466 1467 /* 1468 * Sanity check whether the found disklabel is valid. 1469 * 1470 * This is necessary since total size of ccd may vary 1471 * when an interleave is changed even though exactly 1472 * same componets are used, and old disklabel may used 1473 * if that is found. 1474 */ 1475 if (lp->d_secperunit != cs->sc_size) 1476 printf("WARNING: %s: " 1477 "total sector size in disklabel (%d) != " 1478 "the size of ccd (%lu)\n", cs->sc_xname, 1479 lp->d_secperunit, (u_long)cs->sc_size); 1480 for (i = 0; i < lp->d_npartitions; i++) { 1481 pp = &lp->d_partitions[i]; 1482 if (pp->p_offset + pp->p_size > cs->sc_size) 1483 printf("WARNING: %s: end of partition `%c' " 1484 "exceeds the size of ccd (%lu)\n", 1485 cs->sc_xname, 'a' + i, (u_long)cs->sc_size); 1486 } 1487 } 1488 1489 #ifdef DEBUG 1490 /* It's actually extremely common to have unlabeled ccds. */ 1491 if (ccddebug & CCDB_LABEL) 1492 if (errstring != NULL) 1493 printf("%s: %s\n", cs->sc_xname, errstring); 1494 #endif 1495 1496 /* In-core label now valid. */ 1497 cs->sc_flags |= CCDF_VLABEL; 1498 } 1499 1500 /* 1501 * Take care of things one might want to take care of in the event 1502 * that a disklabel isn't present. 1503 */ 1504 static void 1505 ccdmakedisklabel(struct ccd_softc *cs) 1506 { 1507 struct disklabel *lp = cs->sc_dkdev.dk_label; 1508 1509 /* 1510 * For historical reasons, if there's no disklabel present 1511 * the raw partition must be marked FS_BSDFFS. 1512 */ 1513 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1514 1515 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1516 1517 lp->d_checksum = dkcksum(lp); 1518 } 1519 1520 #ifdef DEBUG 1521 static void 1522 printiinfo(struct ccdiinfo *ii) 1523 { 1524 int ix, i; 1525 1526 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1527 printf(" itab[%d]: #dk %d sblk %" PRId64 " soff %" PRId64, 1528 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1529 for (i = 0; i < ii->ii_ndisk; i++) 1530 printf(" %d", ii->ii_index[i]); 1531 printf("\n"); 1532 } 1533 } 1534 #endif 1535