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