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