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