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