1 /* $NetBSD: ccd.c,v 1.35 1996/10/13 01:37:06 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 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 REGENTS OR CONTRIBUTORS BE 30 * 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) 1988 University of Utah. 41 * Copyright (c) 1990, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from: Utah $Hdr: cd.c 1.6 90/11/28$ 77 * 78 * @(#)cd.c 8.2 (Berkeley) 11/16/93 79 */ 80 81 /* 82 * "Concatenated" disk driver. 83 * 84 * Dynamic configuration and disklabel support by: 85 * Jason R. Thorpe <thorpej@nas.nasa.gov> 86 * Numerical Aerodynamic Simulation Facility 87 * Mail Stop 258-6 88 * NASA Ames Research Center 89 * Moffett Field, CA 94035 90 * 91 * Mirroring support based on code written by Satoshi Asami 92 * and Nisha Talagala. 93 */ 94 95 #include <sys/param.h> 96 #include <sys/systm.h> 97 #include <sys/proc.h> 98 #include <sys/errno.h> 99 #include <sys/buf.h> 100 #include <sys/malloc.h> 101 #include <sys/namei.h> 102 #include <sys/stat.h> 103 #include <sys/ioctl.h> 104 #include <sys/disklabel.h> 105 #include <sys/device.h> 106 #include <sys/disk.h> 107 #include <sys/syslog.h> 108 #include <sys/fcntl.h> 109 #include <sys/vnode.h> 110 #include <sys/conf.h> 111 112 #include <dev/ccdvar.h> 113 114 #if defined(CCDDEBUG) && !defined(DEBUG) 115 #define DEBUG 116 #endif 117 118 #ifdef DEBUG 119 #define CCDB_FOLLOW 0x01 120 #define CCDB_INIT 0x02 121 #define CCDB_IO 0x04 122 #define CCDB_LABEL 0x08 123 #define CCDB_VNODE 0x10 124 int ccddebug = 0x00; 125 #endif 126 127 #define ccdunit(x) DISKUNIT(x) 128 129 struct ccdbuf { 130 struct buf cb_buf; /* new I/O buf */ 131 struct buf *cb_obp; /* ptr. to original I/O buf */ 132 int cb_unit; /* target unit */ 133 int cb_comp; /* target component */ 134 int cb_flags; /* misc. flags */ 135 136 #define CBF_MIRROR 0x01 /* we're for a mirror component */ 137 }; 138 139 #define getccdbuf() \ 140 ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) 141 #define putccdbuf(cbp) \ 142 free((caddr_t)(cbp), M_DEVBUF) 143 144 #define CCDLABELDEV(dev) \ 145 (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART)) 146 147 /* called by main() at boot time */ 148 void ccdattach __P((int)); 149 150 /* called by biodone() at interrupt time */ 151 void ccdiodone __P((struct buf *)); 152 int ccdsize __P((dev_t)); 153 154 static void ccdstart __P((struct ccd_softc *, struct buf *)); 155 static void ccdinterleave __P((struct ccd_softc *, int)); 156 static void ccdintr __P((struct ccd_softc *, struct buf *)); 157 static int ccdinit __P((struct ccddevice *, char **, struct proc *)); 158 static int ccdlookup __P((char *, struct proc *p, struct vnode **)); 159 static void ccdbuffer __P((struct ccd_softc *, struct buf *, 160 daddr_t, caddr_t, long, struct ccdbuf **)); 161 static void ccdgetdisklabel __P((dev_t)); 162 static void ccdmakedisklabel __P((struct ccd_softc *)); 163 static int ccdlock __P((struct ccd_softc *)); 164 static void ccdunlock __P((struct ccd_softc *)); 165 166 #ifdef DEBUG 167 static void printiinfo __P((struct ccdiinfo *)); 168 #endif 169 170 /* Non-private for the benefit of libkvm. */ 171 struct ccd_softc *ccd_softc; 172 struct ccddevice *ccddevs; 173 int numccd = 0; 174 175 /* 176 * Called by main() during pseudo-device attachment. All we need 177 * to do is allocate enough space for devices to be configured later. 178 */ 179 void 180 ccdattach(num) 181 int num; 182 { 183 if (num <= 0) { 184 #ifdef DIAGNOSTIC 185 panic("ccdattach: count <= 0"); 186 #endif 187 return; 188 } 189 190 ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), 191 M_DEVBUF, M_NOWAIT); 192 ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice), 193 M_DEVBUF, M_NOWAIT); 194 if ((ccd_softc == NULL) || (ccddevs == NULL)) { 195 printf("WARNING: no memory for concatenated disks\n"); 196 if (ccd_softc != NULL) 197 free(ccd_softc, M_DEVBUF); 198 if (ccddevs != NULL) 199 free(ccddevs, M_DEVBUF); 200 return; 201 } 202 numccd = num; 203 bzero(ccd_softc, num * sizeof(struct ccd_softc)); 204 bzero(ccddevs, num * sizeof(struct ccddevice)); 205 } 206 207 static int 208 ccdinit(ccd, cpaths, p) 209 struct ccddevice *ccd; 210 char **cpaths; 211 struct proc *p; 212 { 213 register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; 214 register struct ccdcinfo *ci = NULL; 215 register size_t size; 216 register int ix; 217 struct vnode *vp; 218 struct vattr va; 219 size_t minsize; 220 int maxsecsize; 221 struct partinfo dpart; 222 struct ccdgeom *ccg = &cs->sc_geom; 223 char tmppath[MAXPATHLEN]; 224 int error; 225 226 #ifdef DEBUG 227 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 228 printf("ccdinit: unit %d\n", ccd->ccd_unit); 229 #endif 230 231 cs->sc_size = 0; 232 cs->sc_ileave = ccd->ccd_interleave; 233 cs->sc_nccdisks = ccd->ccd_ndev; 234 sprintf(cs->sc_xname, "ccd%d", ccd->ccd_unit); /* XXX */ 235 236 /* Allocate space for the component info. */ 237 cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), 238 M_DEVBUF, M_WAITOK); 239 240 /* 241 * Verify that each component piece exists and record 242 * relevant information about it. 243 */ 244 maxsecsize = 0; 245 minsize = 0; 246 for (ix = 0; ix < cs->sc_nccdisks; ix++) { 247 vp = ccd->ccd_vpp[ix]; 248 ci = &cs->sc_cinfo[ix]; 249 ci->ci_vp = vp; 250 251 /* 252 * Copy in the pathname of the component. 253 */ 254 bzero(tmppath, sizeof(tmppath)); /* sanity */ 255 error = copyinstr(cpaths[ix], tmppath, 256 MAXPATHLEN, &ci->ci_pathlen); 257 if (error) { 258 #ifdef DEBUG 259 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 260 printf("%s: can't copy path, error = %d\n", 261 cs->sc_xname, error); 262 #endif 263 free(cs->sc_cinfo, M_DEVBUF); 264 return (error); 265 } 266 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); 267 bcopy(tmppath, ci->ci_path, ci->ci_pathlen); 268 269 /* 270 * XXX: Cache the component's dev_t. 271 */ 272 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) { 273 #ifdef DEBUG 274 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 275 printf("%s: %s: getattr failed %s = %d\n", 276 cs->sc_xname, ci->ci_path, 277 "error", error); 278 #endif 279 free(ci->ci_path, M_DEVBUF); 280 free(cs->sc_cinfo, M_DEVBUF); 281 return (error); 282 } 283 ci->ci_dev = va.va_rdev; 284 285 /* 286 * Get partition information for the component. 287 */ 288 error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, 289 FREAD, p->p_ucred, p); 290 if (error) { 291 #ifdef DEBUG 292 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 293 printf("%s: %s: ioctl failed, error = %d\n", 294 cs->sc_xname, ci->ci_path, error); 295 #endif 296 free(ci->ci_path, M_DEVBUF); 297 free(cs->sc_cinfo, M_DEVBUF); 298 return (error); 299 } 300 if (dpart.part->p_fstype == FS_BSDFFS) { 301 maxsecsize = 302 ((dpart.disklab->d_secsize > maxsecsize) ? 303 dpart.disklab->d_secsize : maxsecsize); 304 size = dpart.part->p_size; 305 } else { 306 #ifdef DEBUG 307 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 308 printf("%s: %s: incorrect partition type\n", 309 cs->sc_xname, ci->ci_path); 310 #endif 311 free(ci->ci_path, M_DEVBUF); 312 free(cs->sc_cinfo, M_DEVBUF); 313 return (EFTYPE); 314 } 315 316 /* 317 * Calculate the size, truncating to an interleave 318 * boundary if necessary. 319 */ 320 if (cs->sc_ileave > 1) 321 size -= size % cs->sc_ileave; 322 323 if (size == 0) { 324 #ifdef DEBUG 325 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 326 printf("%s: %s: size == 0\n", 327 cs->sc_xname, ci->ci_path); 328 #endif 329 free(ci->ci_path, M_DEVBUF); 330 free(cs->sc_cinfo, M_DEVBUF); 331 return (ENODEV); 332 } 333 334 if (minsize == 0 || size < minsize) 335 minsize = size; 336 ci->ci_size = size; 337 cs->sc_size += size; 338 } 339 340 /* 341 * Don't allow the interleave to be smaller than 342 * the biggest component sector. 343 */ 344 if ((cs->sc_ileave > 0) && 345 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 346 #ifdef DEBUG 347 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 348 printf("%s: interleave must be at least %d\n", 349 cs->sc_xname, (maxsecsize / DEV_BSIZE)); 350 #endif 351 free(ci->ci_path, M_DEVBUF); 352 free(cs->sc_cinfo, M_DEVBUF); 353 return (EINVAL); 354 } 355 356 /* 357 * Mirroring support requires uniform interleave and 358 * and even number of components. 359 */ 360 if (ccd->ccd_flags & CCDF_MIRROR) { 361 ccd->ccd_flags |= CCDF_UNIFORM; 362 if (cs->sc_ileave == 0) { 363 #ifdef DEBUG 364 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 365 printf("%s: mirroring requires interleave\n", 366 cs->sc_xname); 367 #endif 368 free(ci->ci_path, M_DEVBUF); 369 free(cs->sc_cinfo, M_DEVBUF); 370 return (EINVAL); 371 } 372 if (cs->sc_nccdisks % 2) { 373 #ifdef DEBUG 374 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 375 printf("%s: mirroring requires even # of components\n", 376 cs->sc_xname); 377 #endif 378 free(ci->ci_path, M_DEVBUF); 379 free(cs->sc_cinfo, M_DEVBUF); 380 return (EINVAL); 381 } 382 } 383 384 /* 385 * If uniform interleave is desired set all sizes to that of 386 * the smallest component. 387 */ 388 if (ccd->ccd_flags & CCDF_UNIFORM) { 389 for (ci = cs->sc_cinfo; 390 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 391 ci->ci_size = minsize; 392 393 if (ccd->ccd_flags & CCDF_MIRROR) 394 cs->sc_size = (cs->sc_nccdisks / 2) * minsize; 395 else 396 cs->sc_size = cs->sc_nccdisks * minsize; 397 } 398 399 /* 400 * Construct the interleave table. 401 */ 402 ccdinterleave(cs, ccd->ccd_unit); 403 404 /* 405 * Create pseudo-geometry based on 1MB cylinders. It's 406 * pretty close. 407 */ 408 ccg->ccg_secsize = DEV_BSIZE; 409 ccg->ccg_ntracks = 1; 410 ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); 411 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 412 413 cs->sc_flags |= CCDF_INITED; 414 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */ 415 cs->sc_unit = ccd->ccd_unit; 416 417 return (0); 418 } 419 420 static void 421 ccdinterleave(cs, unit) 422 register struct ccd_softc *cs; 423 int unit; 424 { 425 register struct ccdcinfo *ci, *smallci; 426 register struct ccdiinfo *ii; 427 register daddr_t bn, lbn; 428 register int ix; 429 u_long size; 430 431 #ifdef DEBUG 432 if (ccddebug & CCDB_INIT) 433 printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave); 434 #endif 435 /* 436 * Allocate an interleave table. 437 * Chances are this is too big, but we don't care. 438 */ 439 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 440 cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 441 bzero((caddr_t)cs->sc_itable, size); 442 443 /* 444 * Trivial case: no interleave (actually interleave of disk size). 445 * Each table entry represents a single component in its entirety. 446 */ 447 if (cs->sc_ileave == 0) { 448 bn = 0; 449 ii = cs->sc_itable; 450 451 for (ix = 0; ix < cs->sc_nccdisks; ix++) { 452 /* Allocate space for ii_index. */ 453 ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); 454 ii->ii_ndisk = 1; 455 ii->ii_startblk = bn; 456 ii->ii_startoff = 0; 457 ii->ii_index[0] = ix; 458 bn += cs->sc_cinfo[ix].ci_size; 459 ii++; 460 } 461 ii->ii_ndisk = 0; 462 #ifdef DEBUG 463 if (ccddebug & CCDB_INIT) 464 printiinfo(cs->sc_itable); 465 #endif 466 return; 467 } 468 469 /* 470 * The following isn't fast or pretty; it doesn't have to be. 471 */ 472 size = 0; 473 bn = lbn = 0; 474 for (ii = cs->sc_itable; ; ii++) { 475 /* Allocate space for ii_index. */ 476 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), 477 M_DEVBUF, M_WAITOK); 478 479 /* 480 * Locate the smallest of the remaining components 481 */ 482 smallci = NULL; 483 for (ci = cs->sc_cinfo; 484 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 485 if (ci->ci_size > size && 486 (smallci == NULL || 487 ci->ci_size < smallci->ci_size)) 488 smallci = ci; 489 490 /* 491 * Nobody left, all done 492 */ 493 if (smallci == NULL) { 494 ii->ii_ndisk = 0; 495 break; 496 } 497 498 /* 499 * Record starting logical block and component offset 500 */ 501 ii->ii_startblk = bn / cs->sc_ileave; 502 ii->ii_startoff = lbn; 503 504 /* 505 * Determine how many disks take part in this interleave 506 * and record their indices. 507 */ 508 ix = 0; 509 for (ci = cs->sc_cinfo; 510 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 511 if (ci->ci_size >= smallci->ci_size) 512 ii->ii_index[ix++] = ci - cs->sc_cinfo; 513 ii->ii_ndisk = ix; 514 bn += ix * (smallci->ci_size - size); 515 lbn = smallci->ci_size / cs->sc_ileave; 516 size = smallci->ci_size; 517 } 518 #ifdef DEBUG 519 if (ccddebug & CCDB_INIT) 520 printiinfo(cs->sc_itable); 521 #endif 522 } 523 524 /* ARGSUSED */ 525 int 526 ccdopen(dev, flags, fmt, p) 527 dev_t dev; 528 int flags, fmt; 529 struct proc *p; 530 { 531 int unit = ccdunit(dev); 532 struct ccd_softc *cs; 533 struct disklabel *lp; 534 int error = 0, part, pmask; 535 536 #ifdef DEBUG 537 if (ccddebug & CCDB_FOLLOW) 538 printf("ccdopen(%x, %x)\n", dev, flags); 539 #endif 540 if (unit >= numccd) 541 return (ENXIO); 542 cs = &ccd_softc[unit]; 543 544 if ((error = ccdlock(cs)) != 0) 545 return (error); 546 547 lp = cs->sc_dkdev.dk_label; 548 549 part = DISKPART(dev); 550 pmask = (1 << part); 551 552 /* 553 * If we're initialized, check to see if there are any other 554 * open partitions. If not, then it's safe to update 555 * the in-core disklabel. 556 */ 557 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0)) 558 ccdgetdisklabel(dev); 559 560 /* Check that the partition exists. */ 561 if (part != RAW_PART) { 562 if (((cs->sc_flags & CCDF_INITED) == 0) || 563 ((part > lp->d_npartitions) || 564 (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 565 error = ENXIO; 566 goto done; 567 } 568 } 569 570 /* Prevent our unit from being unconfigured while open. */ 571 switch (fmt) { 572 case S_IFCHR: 573 cs->sc_dkdev.dk_copenmask |= pmask; 574 break; 575 576 case S_IFBLK: 577 cs->sc_dkdev.dk_bopenmask |= pmask; 578 break; 579 } 580 cs->sc_dkdev.dk_openmask = 581 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 582 583 done: 584 ccdunlock(cs); 585 return (error); 586 } 587 588 /* ARGSUSED */ 589 int 590 ccdclose(dev, flags, fmt, p) 591 dev_t dev; 592 int flags, fmt; 593 struct proc *p; 594 { 595 int unit = ccdunit(dev); 596 struct ccd_softc *cs; 597 int error = 0, part; 598 599 #ifdef DEBUG 600 if (ccddebug & CCDB_FOLLOW) 601 printf("ccdclose(%x, %x)\n", dev, flags); 602 #endif 603 604 if (unit >= numccd) 605 return (ENXIO); 606 cs = &ccd_softc[unit]; 607 608 if ((error = ccdlock(cs)) != 0) 609 return (error); 610 611 part = DISKPART(dev); 612 613 /* ...that much closer to allowing unconfiguration... */ 614 switch (fmt) { 615 case S_IFCHR: 616 cs->sc_dkdev.dk_copenmask &= ~(1 << part); 617 break; 618 619 case S_IFBLK: 620 cs->sc_dkdev.dk_bopenmask &= ~(1 << part); 621 break; 622 } 623 cs->sc_dkdev.dk_openmask = 624 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 625 626 ccdunlock(cs); 627 return (0); 628 } 629 630 void 631 ccdstrategy(bp) 632 register struct buf *bp; 633 { 634 register int unit = ccdunit(bp->b_dev); 635 register struct ccd_softc *cs = &ccd_softc[unit]; 636 register int s; 637 int wlabel; 638 struct disklabel *lp; 639 640 #ifdef DEBUG 641 if (ccddebug & CCDB_FOLLOW) 642 printf("ccdstrategy(%p): unit %d\n", bp, unit); 643 #endif 644 if ((cs->sc_flags & CCDF_INITED) == 0) { 645 bp->b_error = ENXIO; 646 bp->b_flags |= B_ERROR; 647 goto done; 648 } 649 650 /* If it's a nil transfer, wake up the top half now. */ 651 if (bp->b_bcount == 0) 652 goto done; 653 654 lp = cs->sc_dkdev.dk_label; 655 656 /* 657 * Do bounds checking and adjust transfer. If there's an 658 * error, the bounds check will flag that for us. 659 */ 660 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 661 if (DISKPART(bp->b_dev) != RAW_PART) 662 if (bounds_check_with_label(bp, lp, wlabel) <= 0) 663 goto done; 664 665 bp->b_resid = bp->b_bcount; 666 667 /* 668 * "Start" the unit. 669 */ 670 s = splbio(); 671 ccdstart(cs, bp); 672 splx(s); 673 return; 674 done: 675 biodone(bp); 676 } 677 678 static void 679 ccdstart(cs, bp) 680 register struct ccd_softc *cs; 681 register struct buf *bp; 682 { 683 register long bcount, rcount; 684 struct ccdbuf *cbp[4]; 685 caddr_t addr; 686 daddr_t bn; 687 struct partition *pp; 688 689 #ifdef DEBUG 690 if (ccddebug & CCDB_FOLLOW) 691 printf("ccdstart(%p, %p)\n", cs, bp); 692 #endif 693 694 /* Instrumentation. */ 695 disk_busy(&cs->sc_dkdev); 696 697 /* 698 * Translate the partition-relative block number to an absolute. 699 */ 700 bn = bp->b_blkno; 701 if (DISKPART(bp->b_dev) != RAW_PART) { 702 pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)]; 703 bn += pp->p_offset; 704 } 705 706 /* 707 * Allocate component buffers and fire off the requests 708 */ 709 addr = bp->b_data; 710 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 711 ccdbuffer(cs, bp, bn, addr, bcount, cbp); 712 rcount = cbp[0]->cb_buf.b_bcount; 713 if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) 714 cbp[0]->cb_buf.b_vp->v_numoutput++; 715 VOP_STRATEGY(&cbp[0]->cb_buf); 716 717 /* 718 * Mirror requires additional write. 719 */ 720 if ((cs->sc_cflags & CCDF_MIRROR) && 721 ((cbp[0]->cb_buf.b_flags & B_READ) == 0)) { 722 cbp[1]->cb_buf.b_vp->v_numoutput++; 723 VOP_STRATEGY(&cbp[1]->cb_buf); 724 } 725 726 bn += btodb(rcount); 727 addr += rcount; 728 } 729 } 730 731 /* 732 * Build a component buffer header. 733 */ 734 static void 735 ccdbuffer(cs, bp, bn, addr, bcount, cbpp) 736 register struct ccd_softc *cs; 737 struct buf *bp; 738 daddr_t bn; 739 caddr_t addr; 740 long bcount; 741 struct ccdbuf **cbpp; 742 { 743 register struct ccdcinfo *ci, *ci2 = NULL; 744 register struct ccdbuf *cbp; 745 register daddr_t cbn, cboff; 746 747 #ifdef DEBUG 748 if (ccddebug & CCDB_IO) 749 printf("ccdbuffer(%p, %p, %d, %p, %ld)\n", 750 cs, bp, bn, addr, bcount); 751 #endif 752 /* 753 * Determine which component bn falls in. 754 */ 755 cbn = bn; 756 cboff = 0; 757 758 /* 759 * Serially concatenated 760 */ 761 if (cs->sc_ileave == 0) { 762 register daddr_t sblk; 763 764 sblk = 0; 765 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 766 sblk += ci->ci_size; 767 cbn -= sblk; 768 } 769 /* 770 * Interleaved 771 */ 772 else { 773 register struct ccdiinfo *ii; 774 int ccdisk, off; 775 776 cboff = cbn % cs->sc_ileave; 777 cbn /= cs->sc_ileave; 778 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 779 if (ii->ii_startblk > cbn) 780 break; 781 ii--; 782 off = cbn - ii->ii_startblk; 783 if (ii->ii_ndisk == 1) { 784 ccdisk = ii->ii_index[0]; 785 cbn = ii->ii_startoff + off; 786 } else { 787 if (cs->sc_cflags & CCDF_MIRROR) { 788 ccdisk = 789 ii->ii_index[off % (ii->ii_ndisk / 2)]; 790 cbn = ii->ii_startoff + 791 (off / (ii->ii_ndisk / 2)); 792 /* Mirrored data */ 793 ci2 = 794 &cs->sc_cinfo[ccdisk + (ii->ii_ndisk / 2)]; 795 } else { 796 /* Normal case. */ 797 ccdisk = ii->ii_index[off % ii->ii_ndisk]; 798 cbn = ii->ii_startoff + off / ii->ii_ndisk; 799 } 800 } 801 cbn *= cs->sc_ileave; 802 ci = &cs->sc_cinfo[ccdisk]; 803 } 804 805 /* 806 * Fill in the component buf structure. 807 */ 808 cbp = getccdbuf(); 809 cbp->cb_flags = 0; 810 cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 811 cbp->cb_buf.b_iodone = ccdiodone; 812 cbp->cb_buf.b_proc = bp->b_proc; 813 cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */ 814 cbp->cb_buf.b_blkno = cbn + cboff; 815 cbp->cb_buf.b_data = addr; 816 cbp->cb_buf.b_vp = ci->ci_vp; 817 if (cs->sc_ileave == 0) 818 cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn); 819 else 820 cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff); 821 if (cbp->cb_buf.b_bcount > bcount) 822 cbp->cb_buf.b_bcount = bcount; 823 824 /* 825 * context for ccdiodone 826 */ 827 cbp->cb_obp = bp; 828 cbp->cb_unit = cs - ccd_softc; 829 cbp->cb_comp = ci - cs->sc_cinfo; 830 831 /* First buffer is dealt with. */ 832 cbpp[0] = cbp; 833 834 #ifdef DEBUG 835 if (ccddebug & CCDB_IO) 836 printf(" dev %x(u%d): cbp %p bn %d addr %p bcnt %ld\n", 837 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 838 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 839 #endif 840 841 /* 842 * Mirrors have an additional write operation that is nearly 843 * identical to the first. 844 */ 845 if ((cs->sc_cflags & CCDF_MIRROR) && 846 ((cbp->cb_buf.b_flags & B_READ) == 0)) { 847 cbp = getccdbuf(); 848 *cbp = *cbpp[0]; 849 cbp->cb_flags = CBF_MIRROR; 850 cbp->cb_buf.b_dev = ci2->ci_dev; /* XXX */ 851 cbp->cb_buf.b_vp = ci2->ci_vp; 852 cbp->cb_comp = ci2 - cs->sc_cinfo; 853 cbpp[1] = cbp; 854 } 855 } 856 857 static void 858 ccdintr(cs, bp) 859 register struct ccd_softc *cs; 860 register struct buf *bp; 861 { 862 863 #ifdef DEBUG 864 if (ccddebug & CCDB_FOLLOW) 865 printf("ccdintr(%p, %p)\n", cs, bp); 866 #endif 867 /* 868 * Request is done for better or worse, wakeup the top half. 869 */ 870 if (bp->b_flags & B_ERROR) 871 bp->b_resid = bp->b_bcount; 872 disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid)); 873 biodone(bp); 874 } 875 876 /* 877 * Called at interrupt time. 878 * Mark the component as done and if all components are done, 879 * take a ccd interrupt. 880 */ 881 void 882 ccdiodone(vbp) 883 struct buf *vbp; 884 { 885 struct ccdbuf *cbp = (struct ccdbuf *) vbp; 886 register struct buf *bp = cbp->cb_obp; 887 register int unit = cbp->cb_unit; 888 struct ccd_softc *cs = &ccd_softc[unit]; 889 int count, cbflags, s; 890 char *comptype; 891 892 s = splbio(); 893 #ifdef DEBUG 894 if (ccddebug & CCDB_FOLLOW) 895 printf("ccdiodone(%p)\n", cbp); 896 if (ccddebug & CCDB_IO) { 897 if (cbp->cb_flags & CBF_MIRROR) 898 printf("ccdiodone: mirror component\n"); 899 else 900 printf("ccdiodone: bp %p bcount %ld resid %ld\n", 901 bp, bp->b_bcount, bp->b_resid); 902 printf(" dev %x(u%d), cbp %p bn %d addr %p bcnt %ld\n", 903 cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 904 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 905 cbp->cb_buf.b_bcount); 906 } 907 #endif 908 909 if (cbp->cb_buf.b_flags & B_ERROR) { 910 if (cbp->cb_flags & CBF_MIRROR) 911 comptype = " (mirror)"; 912 else { 913 bp->b_flags |= B_ERROR; 914 bp->b_error = cbp->cb_buf.b_error ? 915 cbp->cb_buf.b_error : EIO; 916 comptype = ""; 917 } 918 919 printf("%s: error %d on component %d%s\n", 920 cs->sc_xname, bp->b_error, cbp->cb_comp, comptype); 921 } 922 count = cbp->cb_buf.b_bcount; 923 cbflags = cbp->cb_flags; 924 putccdbuf(cbp); 925 926 /* 927 * If all done, "interrupt". 928 * 929 * Note that mirror component buffers aren't counted against 930 * the original I/O buffer. 931 */ 932 if ((cbflags & CBF_MIRROR) == 0) { 933 bp->b_resid -= count; 934 if (bp->b_resid < 0) 935 panic("ccdiodone: count"); 936 if (bp->b_resid == 0) 937 ccdintr(&ccd_softc[unit], bp); 938 } 939 splx(s); 940 } 941 942 /* ARGSUSED */ 943 int 944 ccdread(dev, uio, flags) 945 dev_t dev; 946 struct uio *uio; 947 int flags; 948 { 949 int unit = ccdunit(dev); 950 struct ccd_softc *cs; 951 952 #ifdef DEBUG 953 if (ccddebug & CCDB_FOLLOW) 954 printf("ccdread(%x, %p)\n", dev, uio); 955 #endif 956 if (unit >= numccd) 957 return (ENXIO); 958 cs = &ccd_softc[unit]; 959 960 if ((cs->sc_flags & CCDF_INITED) == 0) 961 return (ENXIO); 962 963 /* 964 * XXX: It's not clear that using minphys() is completely safe, 965 * in particular, for raw I/O. Underlying devices might have some 966 * non-obvious limits, because of the copy to user-space. 967 */ 968 return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio)); 969 } 970 971 /* ARGSUSED */ 972 int 973 ccdwrite(dev, uio, flags) 974 dev_t dev; 975 struct uio *uio; 976 int flags; 977 { 978 int unit = ccdunit(dev); 979 struct ccd_softc *cs; 980 981 #ifdef DEBUG 982 if (ccddebug & CCDB_FOLLOW) 983 printf("ccdwrite(%x, %p)\n", dev, uio); 984 #endif 985 if (unit >= numccd) 986 return (ENXIO); 987 cs = &ccd_softc[unit]; 988 989 if ((cs->sc_flags & CCDF_INITED) == 0) 990 return (ENXIO); 991 992 /* 993 * XXX: It's not clear that using minphys() is completely safe, 994 * in particular, for raw I/O. Underlying devices might have some 995 * non-obvious limits, because of the copy to user-space. 996 */ 997 return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio)); 998 } 999 1000 int 1001 ccdioctl(dev, cmd, data, flag, p) 1002 dev_t dev; 1003 u_long cmd; 1004 caddr_t data; 1005 int flag; 1006 struct proc *p; 1007 { 1008 int unit = ccdunit(dev); 1009 int i, j, lookedup = 0, error = 0; 1010 int part, pmask, s; 1011 struct ccd_softc *cs; 1012 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1013 struct ccddevice ccd; 1014 char **cpp; 1015 struct vnode **vpp; 1016 1017 if (unit >= numccd) 1018 return (ENXIO); 1019 cs = &ccd_softc[unit]; 1020 1021 bzero(&ccd, sizeof(ccd)); 1022 1023 switch (cmd) { 1024 case CCDIOCSET: 1025 if (cs->sc_flags & CCDF_INITED) 1026 return (EBUSY); 1027 1028 if ((flag & FWRITE) == 0) 1029 return (EBADF); 1030 1031 if ((error = ccdlock(cs)) != 0) 1032 return (error); 1033 1034 /* Fill in some important bits. */ 1035 ccd.ccd_unit = unit; 1036 ccd.ccd_interleave = ccio->ccio_ileave; 1037 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; 1038 1039 /* 1040 * Allocate space for and copy in the array of 1041 * componet pathnames and device numbers. 1042 */ 1043 cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1044 M_DEVBUF, M_WAITOK); 1045 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1046 M_DEVBUF, M_WAITOK); 1047 1048 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1049 ccio->ccio_ndisks * sizeof(char **)); 1050 if (error) { 1051 free(vpp, M_DEVBUF); 1052 free(cpp, M_DEVBUF); 1053 ccdunlock(cs); 1054 return (error); 1055 } 1056 1057 #ifdef DEBUG 1058 if (ccddebug & CCDB_INIT) 1059 for (i = 0; i < ccio->ccio_ndisks; ++i) 1060 printf("ccdioctl: component %d: 0x%p\n", 1061 i, cpp[i]); 1062 #endif 1063 1064 for (i = 0; i < ccio->ccio_ndisks; ++i) { 1065 #ifdef DEBUG 1066 if (ccddebug & CCDB_INIT) 1067 printf("ccdioctl: lookedup = %d\n", lookedup); 1068 #endif 1069 if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) { 1070 for (j = 0; j < lookedup; ++j) 1071 (void)vn_close(vpp[j], FREAD|FWRITE, 1072 p->p_ucred, p); 1073 free(vpp, M_DEVBUF); 1074 free(cpp, M_DEVBUF); 1075 ccdunlock(cs); 1076 return (error); 1077 } 1078 ++lookedup; 1079 } 1080 ccd.ccd_cpp = cpp; 1081 ccd.ccd_vpp = vpp; 1082 ccd.ccd_ndev = ccio->ccio_ndisks; 1083 1084 /* 1085 * Initialize the ccd. Fills in the softc for us. 1086 */ 1087 if ((error = ccdinit(&ccd, cpp, p)) != 0) { 1088 for (j = 0; j < lookedup; ++j) 1089 (void)vn_close(vpp[j], FREAD|FWRITE, 1090 p->p_ucred, p); 1091 bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); 1092 free(vpp, M_DEVBUF); 1093 free(cpp, M_DEVBUF); 1094 ccdunlock(cs); 1095 return (error); 1096 } 1097 1098 /* 1099 * The ccd has been successfully initialized, so 1100 * we can place it into the array. Don't try to 1101 * read the disklabel until the disk has been attached, 1102 * because space for the disklabel is allocated 1103 * in disk_attach(); 1104 */ 1105 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1106 ccio->ccio_unit = unit; 1107 ccio->ccio_size = cs->sc_size; 1108 1109 /* Attach the disk. */ 1110 cs->sc_dkdev.dk_name = cs->sc_xname; 1111 disk_attach(&cs->sc_dkdev); 1112 1113 /* Try and read the disklabel. */ 1114 ccdgetdisklabel(dev); 1115 1116 ccdunlock(cs); 1117 1118 break; 1119 1120 case CCDIOCCLR: 1121 if ((cs->sc_flags & CCDF_INITED) == 0) 1122 return (ENXIO); 1123 1124 if ((flag & FWRITE) == 0) 1125 return (EBADF); 1126 1127 if ((error = ccdlock(cs)) != 0) 1128 return (error); 1129 1130 /* 1131 * Don't unconfigure if any other partitions are open 1132 * or if both the character and block flavors of this 1133 * partition are open. 1134 */ 1135 part = DISKPART(dev); 1136 pmask = (1 << part); 1137 if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1138 ((cs->sc_dkdev.dk_bopenmask & pmask) && 1139 (cs->sc_dkdev.dk_copenmask & pmask))) { 1140 ccdunlock(cs); 1141 return (EBUSY); 1142 } 1143 1144 /* 1145 * Free ccd_softc information and clear entry. 1146 */ 1147 1148 /* Close the components and free their pathnames. */ 1149 for (i = 0; i < cs->sc_nccdisks; ++i) { 1150 /* 1151 * XXX: this close could potentially fail and 1152 * cause Bad Things. Maybe we need to force 1153 * the close to happen? 1154 */ 1155 #ifdef DEBUG 1156 if (ccddebug & CCDB_VNODE) 1157 vprint("CCDIOCCLR: vnode info", 1158 cs->sc_cinfo[i].ci_vp); 1159 #endif 1160 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1161 p->p_ucred, p); 1162 free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1163 } 1164 1165 /* Free interleave index. */ 1166 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1167 free(cs->sc_itable[i].ii_index, M_DEVBUF); 1168 1169 /* Free component info and interleave table. */ 1170 free(cs->sc_cinfo, M_DEVBUF); 1171 free(cs->sc_itable, M_DEVBUF); 1172 cs->sc_flags &= ~CCDF_INITED; 1173 1174 /* 1175 * Free ccddevice information and clear entry. 1176 */ 1177 free(ccddevs[unit].ccd_cpp, M_DEVBUF); 1178 free(ccddevs[unit].ccd_vpp, M_DEVBUF); 1179 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1180 1181 /* Detatch the disk. */ 1182 disk_detach(&cs->sc_dkdev); 1183 1184 /* This must be atomic. */ 1185 s = splhigh(); 1186 ccdunlock(cs); 1187 bzero(cs, sizeof(struct ccd_softc)); 1188 splx(s); 1189 1190 break; 1191 1192 case DIOCGDINFO: 1193 if ((cs->sc_flags & CCDF_INITED) == 0) 1194 return (ENXIO); 1195 1196 *(struct disklabel *)data = *(cs->sc_dkdev.dk_label); 1197 break; 1198 1199 case DIOCGPART: 1200 if ((cs->sc_flags & CCDF_INITED) == 0) 1201 return (ENXIO); 1202 1203 ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label; 1204 ((struct partinfo *)data)->part = 1205 &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)]; 1206 break; 1207 1208 case DIOCWDINFO: 1209 case DIOCSDINFO: 1210 if ((cs->sc_flags & CCDF_INITED) == 0) 1211 return (ENXIO); 1212 1213 if ((flag & FWRITE) == 0) 1214 return (EBADF); 1215 1216 if ((error = ccdlock(cs)) != 0) 1217 return (error); 1218 1219 cs->sc_flags |= CCDF_LABELLING; 1220 1221 error = setdisklabel(cs->sc_dkdev.dk_label, 1222 (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel); 1223 if (error == 0) { 1224 if (cmd == DIOCWDINFO) 1225 error = writedisklabel(CCDLABELDEV(dev), 1226 ccdstrategy, cs->sc_dkdev.dk_label, 1227 cs->sc_dkdev.dk_cpulabel); 1228 } 1229 1230 cs->sc_flags &= ~CCDF_LABELLING; 1231 1232 ccdunlock(cs); 1233 1234 if (error) 1235 return (error); 1236 break; 1237 1238 case DIOCWLABEL: 1239 if ((cs->sc_flags & CCDF_INITED) == 0) 1240 return (ENXIO); 1241 1242 if ((flag & FWRITE) == 0) 1243 return (EBADF); 1244 if (*(int *)data != 0) 1245 cs->sc_flags |= CCDF_WLABEL; 1246 else 1247 cs->sc_flags &= ~CCDF_WLABEL; 1248 break; 1249 1250 default: 1251 return (ENOTTY); 1252 } 1253 1254 return (0); 1255 } 1256 1257 int 1258 ccdsize(dev) 1259 dev_t dev; 1260 { 1261 struct ccd_softc *cs; 1262 int part, size; 1263 1264 if (ccdopen(dev, 0, S_IFBLK, curproc)) 1265 return (-1); 1266 1267 cs = &ccd_softc[ccdunit(dev)]; 1268 part = DISKPART(dev); 1269 1270 if ((cs->sc_flags & CCDF_INITED) == 0) 1271 return (-1); 1272 1273 if (cs->sc_dkdev.dk_label->d_partitions[part].p_fstype != FS_SWAP) 1274 size = -1; 1275 else 1276 size = cs->sc_dkdev.dk_label->d_partitions[part].p_size; 1277 1278 if (ccdclose(dev, 0, S_IFBLK, curproc)) 1279 return (-1); 1280 1281 return (size); 1282 } 1283 1284 int 1285 ccddump(dev, blkno, va, size) 1286 dev_t dev; 1287 daddr_t blkno; 1288 caddr_t va; 1289 size_t size; 1290 { 1291 1292 /* Not implemented. */ 1293 return ENXIO; 1294 } 1295 1296 /* 1297 * Lookup the provided name in the filesystem. If the file exists, 1298 * is a valid block device, and isn't being used by anyone else, 1299 * set *vpp to the file's vnode. 1300 */ 1301 static int 1302 ccdlookup(path, p, vpp) 1303 char *path; 1304 struct proc *p; 1305 struct vnode **vpp; /* result */ 1306 { 1307 struct nameidata nd; 1308 struct vnode *vp; 1309 struct vattr va; 1310 int error; 1311 1312 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1313 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 1314 #ifdef DEBUG 1315 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 1316 printf("ccdlookup: vn_open error = %d\n", error); 1317 #endif 1318 return (error); 1319 } 1320 vp = nd.ni_vp; 1321 1322 if (vp->v_usecount > 1) { 1323 VOP_UNLOCK(vp); 1324 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1325 return (EBUSY); 1326 } 1327 1328 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) { 1329 #ifdef DEBUG 1330 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 1331 printf("ccdlookup: getattr error = %d\n", error); 1332 #endif 1333 VOP_UNLOCK(vp); 1334 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1335 return (error); 1336 } 1337 1338 /* XXX: eventually we should handle VREG, too. */ 1339 if (va.va_type != VBLK) { 1340 VOP_UNLOCK(vp); 1341 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1342 return (ENOTBLK); 1343 } 1344 1345 #ifdef DEBUG 1346 if (ccddebug & CCDB_VNODE) 1347 vprint("ccdlookup: vnode info", vp); 1348 #endif 1349 1350 VOP_UNLOCK(vp); 1351 *vpp = vp; 1352 return (0); 1353 } 1354 1355 /* 1356 * Read the disklabel from the ccd. If one is not present, fake one 1357 * up. 1358 */ 1359 static void 1360 ccdgetdisklabel(dev) 1361 dev_t dev; 1362 { 1363 int unit = ccdunit(dev); 1364 struct ccd_softc *cs = &ccd_softc[unit]; 1365 char *errstring; 1366 struct disklabel *lp = cs->sc_dkdev.dk_label; 1367 struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel; 1368 struct ccdgeom *ccg = &cs->sc_geom; 1369 1370 bzero(lp, sizeof(*lp)); 1371 bzero(clp, sizeof(*clp)); 1372 1373 lp->d_secperunit = cs->sc_size; 1374 lp->d_secsize = ccg->ccg_secsize; 1375 lp->d_nsectors = ccg->ccg_nsectors; 1376 lp->d_ntracks = ccg->ccg_ntracks; 1377 lp->d_ncylinders = ccg->ccg_ncylinders; 1378 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1379 1380 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1381 lp->d_type = DTYPE_CCD; 1382 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1383 lp->d_rpm = 3600; 1384 lp->d_interleave = 1; 1385 lp->d_flags = 0; 1386 1387 lp->d_partitions[RAW_PART].p_offset = 0; 1388 lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1389 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1390 lp->d_npartitions = RAW_PART + 1; 1391 1392 lp->d_magic = DISKMAGIC; 1393 lp->d_magic2 = DISKMAGIC; 1394 lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label); 1395 1396 /* 1397 * Call the generic disklabel extraction routine. 1398 */ 1399 errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1400 cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel); 1401 if (errstring) 1402 ccdmakedisklabel(cs); 1403 1404 #ifdef DEBUG 1405 /* It's actually extremely common to have unlabeled ccds. */ 1406 if (ccddebug & CCDB_LABEL) 1407 if (errstring != NULL) 1408 printf("%s: %s\n", cs->sc_xname, errstring); 1409 #endif 1410 } 1411 1412 /* 1413 * Take care of things one might want to take care of in the event 1414 * that a disklabel isn't present. 1415 */ 1416 static void 1417 ccdmakedisklabel(cs) 1418 struct ccd_softc *cs; 1419 { 1420 struct disklabel *lp = cs->sc_dkdev.dk_label; 1421 1422 /* 1423 * For historical reasons, if there's no disklabel present 1424 * the raw partition must be marked FS_BSDFFS. 1425 */ 1426 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1427 1428 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1429 } 1430 1431 /* 1432 * Wait interruptibly for an exclusive lock. 1433 * 1434 * XXX 1435 * Several drivers do this; it should be abstracted and made MP-safe. 1436 */ 1437 static int 1438 ccdlock(cs) 1439 struct ccd_softc *cs; 1440 { 1441 int error; 1442 1443 while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1444 cs->sc_flags |= CCDF_WANTED; 1445 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1446 return (error); 1447 } 1448 cs->sc_flags |= CCDF_LOCKED; 1449 return (0); 1450 } 1451 1452 /* 1453 * Unlock and wake up any waiters. 1454 */ 1455 static void 1456 ccdunlock(cs) 1457 struct ccd_softc *cs; 1458 { 1459 1460 cs->sc_flags &= ~CCDF_LOCKED; 1461 if ((cs->sc_flags & CCDF_WANTED) != 0) { 1462 cs->sc_flags &= ~CCDF_WANTED; 1463 wakeup(cs); 1464 } 1465 } 1466 1467 #ifdef DEBUG 1468 static void 1469 printiinfo(ii) 1470 struct ccdiinfo *ii; 1471 { 1472 register int ix, i; 1473 1474 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1475 printf(" itab[%d]: #dk %d sblk %d soff %d", 1476 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1477 for (i = 0; i < ii->ii_ndisk; i++) 1478 printf(" %d", ii->ii_index[i]); 1479 printf("\n"); 1480 } 1481 } 1482 #endif 1483