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