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