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 dev->si_bsize_phys = DEV_BSIZE; 637 dev->si_bsize_best = BLKDEV_IOSIZE; 638 dev->si_bsize_max = MAXBSIZE; 639 640 /* 641 * If we're initialized, check to see if there are any other 642 * open partitions. If not, then it's safe to update 643 * the in-core disklabel. 644 */ 645 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0)) 646 ccdgetdisklabel(dev); 647 648 /* Check that the partition exists. */ 649 if (part != RAW_PART && ((part >= lp->d_npartitions) || 650 (lp->d_partitions[part].p_fstype == FS_UNUSED))) { 651 error = ENXIO; 652 goto done; 653 } 654 655 /* Prevent our unit from being unconfigured while open. */ 656 switch (fmt) { 657 case S_IFCHR: 658 cs->sc_copenmask |= pmask; 659 break; 660 661 case S_IFBLK: 662 cs->sc_bopenmask |= pmask; 663 break; 664 } 665 cs->sc_openmask = 666 cs->sc_copenmask | cs->sc_bopenmask; 667 668 done: 669 ccdunlock(cs); 670 return (0); 671 } 672 673 /* ARGSUSED */ 674 static int 675 ccdclose(dev, flags, fmt, p) 676 dev_t dev; 677 int flags, fmt; 678 struct proc *p; 679 { 680 int unit = ccdunit(dev); 681 struct ccd_softc *cs; 682 int error = 0, part; 683 684 #ifdef DEBUG 685 if (ccddebug & CCDB_FOLLOW) 686 printf("ccdclose(%x, %x)\n", dev, flags); 687 #endif 688 689 if (unit >= numccd) 690 return (ENXIO); 691 cs = &ccd_softc[unit]; 692 693 if ((error = ccdlock(cs)) != 0) 694 return (error); 695 696 part = ccdpart(dev); 697 698 /* ...that much closer to allowing unconfiguration... */ 699 switch (fmt) { 700 case S_IFCHR: 701 cs->sc_copenmask &= ~(1 << part); 702 break; 703 704 case S_IFBLK: 705 cs->sc_bopenmask &= ~(1 << part); 706 break; 707 } 708 cs->sc_openmask = 709 cs->sc_copenmask | cs->sc_bopenmask; 710 711 ccdunlock(cs); 712 return (0); 713 } 714 715 static void 716 ccdstrategy(bp) 717 register struct buf *bp; 718 { 719 register int unit = ccdunit(bp->b_dev); 720 register struct ccd_softc *cs = &ccd_softc[unit]; 721 register int s; 722 int wlabel; 723 struct disklabel *lp; 724 725 #ifdef DEBUG 726 if (ccddebug & CCDB_FOLLOW) 727 printf("ccdstrategy(%x): unit %d\n", bp, unit); 728 #endif 729 if ((cs->sc_flags & CCDF_INITED) == 0) { 730 bp->b_error = ENXIO; 731 bp->b_flags |= B_ERROR; 732 goto done; 733 } 734 735 /* If it's a nil transfer, wake up the top half now. */ 736 if (bp->b_bcount == 0) 737 goto done; 738 739 lp = &cs->sc_label; 740 741 /* 742 * Do bounds checking and adjust transfer. If there's an 743 * error, the bounds check will flag that for us. 744 */ 745 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); 746 if (ccdpart(bp->b_dev) != RAW_PART) 747 if (bounds_check_with_label(bp, lp, wlabel) <= 0) 748 goto done; 749 750 bp->b_resid = bp->b_bcount; 751 752 /* 753 * "Start" the unit. 754 */ 755 s = splbio(); 756 ccdstart(cs, bp); 757 splx(s); 758 return; 759 done: 760 biodone(bp); 761 } 762 763 static void 764 ccdstart(cs, bp) 765 register struct ccd_softc *cs; 766 register struct buf *bp; 767 { 768 register long bcount, rcount; 769 struct ccdbuf *cbp[4]; 770 /* XXX! : 2 reads and 2 writes for RAID 4/5 */ 771 caddr_t addr; 772 daddr_t bn; 773 struct partition *pp; 774 775 #ifdef DEBUG 776 if (ccddebug & CCDB_FOLLOW) 777 printf("ccdstart(%x, %x)\n", cs, bp); 778 #endif 779 780 /* Record the transaction start */ 781 devstat_start_transaction(&cs->device_stats); 782 783 /* 784 * Translate the partition-relative block number to an absolute. 785 */ 786 bn = bp->b_blkno; 787 if (ccdpart(bp->b_dev) != RAW_PART) { 788 pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)]; 789 bn += pp->p_offset; 790 } 791 792 /* 793 * Allocate component buffers and fire off the requests 794 */ 795 addr = bp->b_data; 796 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 797 ccdbuffer(cbp, cs, bp, bn, addr, bcount); 798 rcount = cbp[0]->cb_buf.b_bcount; 799 if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) 800 cbp[0]->cb_buf.b_vp->v_numoutput++; 801 VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf); 802 if (cs->sc_cflags & CCDF_MIRROR && 803 (cbp[0]->cb_buf.b_flags & B_READ) == 0) { 804 /* mirror, start another write */ 805 cbp[1]->cb_buf.b_vp->v_numoutput++; 806 VOP_STRATEGY(cbp[1]->cb_buf.b_vp, &cbp[1]->cb_buf); 807 } 808 bn += btodb(rcount); 809 addr += rcount; 810 } 811 } 812 813 /* 814 * Build a component buffer header. 815 */ 816 static void 817 ccdbuffer(cb, cs, bp, bn, addr, bcount) 818 register struct ccdbuf **cb; 819 register struct ccd_softc *cs; 820 struct buf *bp; 821 daddr_t bn; 822 caddr_t addr; 823 long bcount; 824 { 825 register struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ 826 register struct ccdbuf *cbp; 827 register daddr_t cbn, cboff; 828 register off_t cbc; 829 830 #ifdef DEBUG 831 if (ccddebug & CCDB_IO) 832 printf("ccdbuffer(%x, %x, %d, %x, %d)\n", 833 cs, bp, bn, addr, bcount); 834 #endif 835 /* 836 * Determine which component bn falls in. 837 */ 838 cbn = bn; 839 cboff = 0; 840 841 /* 842 * Serially concatenated 843 */ 844 if (cs->sc_ileave == 0) { 845 register daddr_t sblk; 846 847 sblk = 0; 848 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 849 sblk += ci->ci_size; 850 cbn -= sblk; 851 } 852 /* 853 * Interleaved 854 */ 855 else { 856 register struct ccdiinfo *ii; 857 int ccdisk, off; 858 859 cboff = cbn % cs->sc_ileave; 860 cbn /= cs->sc_ileave; 861 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 862 if (ii->ii_startblk > cbn) 863 break; 864 ii--; 865 off = cbn - ii->ii_startblk; 866 if (ii->ii_ndisk == 1) { 867 ccdisk = ii->ii_index[0]; 868 cbn = ii->ii_startoff + off; 869 } else { 870 if (cs->sc_cflags & CCDF_MIRROR) { 871 ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)]; 872 cbn = ii->ii_startoff + off / (ii->ii_ndisk/2); 873 /* mirrored data */ 874 ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2]; 875 } 876 else if (cs->sc_cflags & CCDF_PARITY) { 877 ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)]; 878 cbn = ii->ii_startoff + off / (ii->ii_ndisk-1); 879 if (cbn % ii->ii_ndisk <= ccdisk) 880 ccdisk++; 881 } 882 else { 883 ccdisk = ii->ii_index[off % ii->ii_ndisk]; 884 cbn = ii->ii_startoff + off / ii->ii_ndisk; 885 } 886 } 887 cbn *= cs->sc_ileave; 888 ci = &cs->sc_cinfo[ccdisk]; 889 } 890 891 /* 892 * Fill in the component buf structure. 893 */ 894 cbp = getccdbuf(); 895 bzero(cbp, sizeof (struct ccdbuf)); 896 cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 897 cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone; 898 cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */ 899 cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET; 900 cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET); 901 cbp->cb_buf.b_data = addr; 902 cbp->cb_buf.b_vp = ci->ci_vp; 903 LIST_INIT(&cbp->cb_buf.b_dep); 904 BUF_LOCKINIT(&cbp->cb_buf); 905 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE); 906 cbp->cb_buf.b_resid = 0; 907 if (cs->sc_ileave == 0) 908 cbc = dbtob((off_t)(ci->ci_size - cbn)); 909 else 910 cbc = dbtob((off_t)(cs->sc_ileave - cboff)); 911 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount; 912 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount; 913 914 /* 915 * context for ccdiodone 916 */ 917 cbp->cb_obp = bp; 918 cbp->cb_unit = cs - ccd_softc; 919 cbp->cb_comp = ci - cs->sc_cinfo; 920 921 #ifdef DEBUG 922 if (ccddebug & CCDB_IO) 923 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 924 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 925 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 926 #endif 927 cb[0] = cbp; 928 if (cs->sc_cflags & CCDF_MIRROR && 929 (cbp->cb_buf.b_flags & B_READ) == 0) { 930 /* mirror, start one more write */ 931 cbp = getccdbuf(); 932 bzero(cbp, sizeof (struct ccdbuf)); 933 *cbp = *cb[0]; 934 cbp->cb_buf.b_dev = ci2->ci_dev; 935 cbp->cb_buf.b_vp = ci2->ci_vp; 936 LIST_INIT(&cbp->cb_buf.b_dep); 937 BUF_LOCKINIT(&cbp->cb_buf); 938 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE); 939 cbp->cb_comp = ci2 - cs->sc_cinfo; 940 cb[1] = cbp; 941 /* link together the ccdbuf's and clear "mirror done" flag */ 942 cb[0]->cb_mirror = cb[1]; 943 cb[1]->cb_mirror = cb[0]; 944 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; 945 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; 946 } 947 } 948 949 static void 950 ccdintr(cs, bp) 951 register struct ccd_softc *cs; 952 register struct buf *bp; 953 { 954 #ifdef DEBUG 955 if (ccddebug & CCDB_FOLLOW) 956 printf("ccdintr(%x, %x)\n", cs, bp); 957 #endif 958 /* 959 * Request is done for better or worse, wakeup the top half. 960 */ 961 /* Record device statistics */ 962 devstat_end_transaction(&cs->device_stats, 963 bp->b_bcount - bp->b_resid, 964 (bp->b_flags & B_ORDERED) ? 965 DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE, 966 (bp->b_flags & B_READ) ? DEVSTAT_READ : 967 DEVSTAT_WRITE); 968 969 if (bp->b_flags & B_ERROR) 970 bp->b_resid = bp->b_bcount; 971 biodone(bp); 972 } 973 974 /* 975 * Called at interrupt time. 976 * Mark the component as done and if all components are done, 977 * take a ccd interrupt. 978 */ 979 static void 980 ccdiodone(cbp) 981 struct ccdbuf *cbp; 982 { 983 register struct buf *bp = cbp->cb_obp; 984 register int unit = cbp->cb_unit; 985 int count, s; 986 987 s = splbio(); 988 #ifdef DEBUG 989 if (ccddebug & CCDB_FOLLOW) 990 printf("ccdiodone(%x)\n", cbp); 991 if (ccddebug & CCDB_IO) { 992 printf("ccdiodone: bp %x bcount %d resid %d\n", 993 bp, bp->b_bcount, bp->b_resid); 994 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 995 cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 996 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 997 cbp->cb_buf.b_bcount); 998 } 999 #endif 1000 1001 if (cbp->cb_buf.b_flags & B_ERROR) { 1002 bp->b_flags |= B_ERROR; 1003 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO; 1004 #ifdef DEBUG 1005 printf("ccd%d: error %d on component %d\n", 1006 unit, bp->b_error, cbp->cb_comp); 1007 #endif 1008 } 1009 1010 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR && 1011 (cbp->cb_buf.b_flags & B_READ) == 0) 1012 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 1013 /* I'm done before my counterpart, so just set 1014 partner's flag and return */ 1015 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; 1016 putccdbuf(cbp); 1017 splx(s); 1018 return; 1019 } 1020 1021 count = cbp->cb_buf.b_bcount; 1022 putccdbuf(cbp); 1023 1024 /* 1025 * If all done, "interrupt". 1026 */ 1027 bp->b_resid -= count; 1028 if (bp->b_resid < 0) 1029 panic("ccdiodone: count"); 1030 if (bp->b_resid == 0) 1031 ccdintr(&ccd_softc[unit], bp); 1032 splx(s); 1033 } 1034 1035 static int 1036 ccdioctl(dev, cmd, data, flag, p) 1037 dev_t dev; 1038 u_long cmd; 1039 caddr_t data; 1040 int flag; 1041 struct proc *p; 1042 { 1043 int unit = ccdunit(dev); 1044 int i, j, lookedup = 0, error = 0; 1045 int part, pmask, s; 1046 struct ccd_softc *cs; 1047 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1048 struct ccddevice ccd; 1049 char **cpp; 1050 struct vnode **vpp; 1051 1052 if (unit >= numccd) 1053 return (ENXIO); 1054 cs = &ccd_softc[unit]; 1055 1056 bzero(&ccd, sizeof(ccd)); 1057 1058 switch (cmd) { 1059 case CCDIOCSET: 1060 if (cs->sc_flags & CCDF_INITED) 1061 return (EBUSY); 1062 1063 if ((flag & FWRITE) == 0) 1064 return (EBADF); 1065 1066 if ((error = ccdlock(cs)) != 0) 1067 return (error); 1068 1069 /* Fill in some important bits. */ 1070 ccd.ccd_unit = unit; 1071 ccd.ccd_interleave = ccio->ccio_ileave; 1072 if (ccd.ccd_interleave == 0 && 1073 ((ccio->ccio_flags & CCDF_MIRROR) || 1074 (ccio->ccio_flags & CCDF_PARITY))) { 1075 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit); 1076 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY); 1077 } 1078 if ((ccio->ccio_flags & CCDF_MIRROR) && 1079 (ccio->ccio_flags & CCDF_PARITY)) { 1080 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit); 1081 ccio->ccio_flags &= ~CCDF_PARITY; 1082 } 1083 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) && 1084 !(ccio->ccio_flags & CCDF_UNIFORM)) { 1085 printf("ccd%d: mirror/parity forces uniform flag\n", 1086 unit); 1087 ccio->ccio_flags |= CCDF_UNIFORM; 1088 } 1089 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; 1090 1091 /* 1092 * Allocate space for and copy in the array of 1093 * componet pathnames and device numbers. 1094 */ 1095 cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1096 M_DEVBUF, M_WAITOK); 1097 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1098 M_DEVBUF, M_WAITOK); 1099 1100 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1101 ccio->ccio_ndisks * sizeof(char **)); 1102 if (error) { 1103 free(vpp, M_DEVBUF); 1104 free(cpp, M_DEVBUF); 1105 ccdunlock(cs); 1106 return (error); 1107 } 1108 1109 #ifdef DEBUG 1110 if (ccddebug & CCDB_INIT) 1111 for (i = 0; i < ccio->ccio_ndisks; ++i) 1112 printf("ccdioctl: component %d: 0x%x\n", 1113 i, cpp[i]); 1114 #endif 1115 1116 for (i = 0; i < ccio->ccio_ndisks; ++i) { 1117 #ifdef DEBUG 1118 if (ccddebug & CCDB_INIT) 1119 printf("ccdioctl: lookedup = %d\n", lookedup); 1120 #endif 1121 if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) { 1122 for (j = 0; j < lookedup; ++j) 1123 (void)vn_close(vpp[j], FREAD|FWRITE, 1124 p->p_ucred, p); 1125 free(vpp, M_DEVBUF); 1126 free(cpp, M_DEVBUF); 1127 ccdunlock(cs); 1128 return (error); 1129 } 1130 ++lookedup; 1131 } 1132 ccd.ccd_cpp = cpp; 1133 ccd.ccd_vpp = vpp; 1134 ccd.ccd_ndev = ccio->ccio_ndisks; 1135 1136 /* 1137 * Initialize the ccd. Fills in the softc for us. 1138 */ 1139 if ((error = ccdinit(&ccd, cpp, p)) != 0) { 1140 for (j = 0; j < lookedup; ++j) 1141 (void)vn_close(vpp[j], FREAD|FWRITE, 1142 p->p_ucred, p); 1143 bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); 1144 free(vpp, M_DEVBUF); 1145 free(cpp, M_DEVBUF); 1146 ccdunlock(cs); 1147 return (error); 1148 } 1149 1150 /* 1151 * The ccd has been successfully initialized, so 1152 * we can place it into the array and read the disklabel. 1153 */ 1154 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1155 ccio->ccio_unit = unit; 1156 ccio->ccio_size = cs->sc_size; 1157 ccdgetdisklabel(dev); 1158 1159 ccdunlock(cs); 1160 1161 break; 1162 1163 case CCDIOCCLR: 1164 if ((cs->sc_flags & CCDF_INITED) == 0) 1165 return (ENXIO); 1166 1167 if ((flag & FWRITE) == 0) 1168 return (EBADF); 1169 1170 if ((error = ccdlock(cs)) != 0) 1171 return (error); 1172 1173 /* 1174 * Don't unconfigure if any other partitions are open 1175 * or if both the character and block flavors of this 1176 * partition are open. 1177 */ 1178 part = ccdpart(dev); 1179 pmask = (1 << part); 1180 if ((cs->sc_openmask & ~pmask) || 1181 ((cs->sc_bopenmask & pmask) && 1182 (cs->sc_copenmask & pmask))) { 1183 ccdunlock(cs); 1184 return (EBUSY); 1185 } 1186 1187 /* 1188 * Free ccd_softc information and clear entry. 1189 */ 1190 1191 /* Close the components and free their pathnames. */ 1192 for (i = 0; i < cs->sc_nccdisks; ++i) { 1193 /* 1194 * XXX: this close could potentially fail and 1195 * cause Bad Things. Maybe we need to force 1196 * the close to happen? 1197 */ 1198 #ifdef DEBUG 1199 if (ccddebug & CCDB_VNODE) 1200 vprint("CCDIOCCLR: vnode info", 1201 cs->sc_cinfo[i].ci_vp); 1202 #endif 1203 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1204 p->p_ucred, p); 1205 free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1206 } 1207 1208 /* Free interleave index. */ 1209 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1210 free(cs->sc_itable[i].ii_index, M_DEVBUF); 1211 1212 /* Free component info and interleave table. */ 1213 free(cs->sc_cinfo, M_DEVBUF); 1214 free(cs->sc_itable, M_DEVBUF); 1215 cs->sc_flags &= ~CCDF_INITED; 1216 1217 /* 1218 * Free ccddevice information and clear entry. 1219 */ 1220 free(ccddevs[unit].ccd_cpp, M_DEVBUF); 1221 free(ccddevs[unit].ccd_vpp, M_DEVBUF); 1222 ccd.ccd_dk = -1; 1223 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1224 1225 /* 1226 * And remove the devstat entry. 1227 */ 1228 devstat_remove_entry(&cs->device_stats); 1229 1230 /* This must be atomic. */ 1231 s = splhigh(); 1232 ccdunlock(cs); 1233 bzero(cs, sizeof(struct ccd_softc)); 1234 splx(s); 1235 1236 break; 1237 1238 case DIOCGDINFO: 1239 if ((cs->sc_flags & CCDF_INITED) == 0) 1240 return (ENXIO); 1241 1242 *(struct disklabel *)data = cs->sc_label; 1243 break; 1244 1245 case DIOCGPART: 1246 if ((cs->sc_flags & CCDF_INITED) == 0) 1247 return (ENXIO); 1248 1249 ((struct partinfo *)data)->disklab = &cs->sc_label; 1250 ((struct partinfo *)data)->part = 1251 &cs->sc_label.d_partitions[ccdpart(dev)]; 1252 break; 1253 1254 case DIOCWDINFO: 1255 case DIOCSDINFO: 1256 if ((cs->sc_flags & CCDF_INITED) == 0) 1257 return (ENXIO); 1258 1259 if ((flag & FWRITE) == 0) 1260 return (EBADF); 1261 1262 if ((error = ccdlock(cs)) != 0) 1263 return (error); 1264 1265 cs->sc_flags |= CCDF_LABELLING; 1266 1267 error = setdisklabel(&cs->sc_label, 1268 (struct disklabel *)data, 0); 1269 if (error == 0) { 1270 if (cmd == DIOCWDINFO) 1271 error = writedisklabel(CCDLABELDEV(dev), 1272 &cs->sc_label); 1273 } 1274 1275 cs->sc_flags &= ~CCDF_LABELLING; 1276 1277 ccdunlock(cs); 1278 1279 if (error) 1280 return (error); 1281 break; 1282 1283 case DIOCWLABEL: 1284 if ((cs->sc_flags & CCDF_INITED) == 0) 1285 return (ENXIO); 1286 1287 if ((flag & FWRITE) == 0) 1288 return (EBADF); 1289 if (*(int *)data != 0) 1290 cs->sc_flags |= CCDF_WLABEL; 1291 else 1292 cs->sc_flags &= ~CCDF_WLABEL; 1293 break; 1294 1295 default: 1296 return (ENOTTY); 1297 } 1298 1299 return (0); 1300 } 1301 1302 static int 1303 ccdsize(dev) 1304 dev_t dev; 1305 { 1306 struct ccd_softc *cs; 1307 int part, size; 1308 1309 if (ccdopen(dev, 0, S_IFBLK, curproc)) 1310 return (-1); 1311 1312 cs = &ccd_softc[ccdunit(dev)]; 1313 part = ccdpart(dev); 1314 1315 if ((cs->sc_flags & CCDF_INITED) == 0) 1316 return (-1); 1317 1318 if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP) 1319 size = -1; 1320 else 1321 size = cs->sc_label.d_partitions[part].p_size; 1322 1323 if (ccdclose(dev, 0, S_IFBLK, curproc)) 1324 return (-1); 1325 1326 return (size); 1327 } 1328 1329 static int 1330 ccddump(dev) 1331 dev_t dev; 1332 { 1333 1334 /* Not implemented. */ 1335 return ENXIO; 1336 } 1337 1338 /* 1339 * Lookup the provided name in the filesystem. If the file exists, 1340 * is a valid block device, and isn't being used by anyone else, 1341 * set *vpp to the file's vnode. 1342 */ 1343 static int 1344 ccdlookup(path, p, vpp) 1345 char *path; 1346 struct proc *p; 1347 struct vnode **vpp; /* result */ 1348 { 1349 struct nameidata nd; 1350 struct vnode *vp; 1351 struct vattr va; 1352 int error; 1353 1354 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1355 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 1356 #ifdef DEBUG 1357 if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1358 printf("ccdlookup: vn_open error = %d\n", error); 1359 #endif 1360 return (error); 1361 } 1362 vp = nd.ni_vp; 1363 1364 if (vp->v_usecount > 1) { 1365 VOP_UNLOCK(vp, 0, p); 1366 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1367 return (EBUSY); 1368 } 1369 1370 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) { 1371 #ifdef DEBUG 1372 if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1373 printf("ccdlookup: getattr error = %d\n", error); 1374 #endif 1375 VOP_UNLOCK(vp, 0, p); 1376 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1377 return (error); 1378 } 1379 1380 /* XXX: eventually we should handle VREG, too. */ 1381 if (va.va_type != VBLK) { 1382 VOP_UNLOCK(vp, 0, p); 1383 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1384 return (ENOTBLK); 1385 } 1386 1387 #ifdef DEBUG 1388 if (ccddebug & CCDB_VNODE) 1389 vprint("ccdlookup: vnode info", vp); 1390 #endif 1391 1392 VOP_UNLOCK(vp, 0, p); 1393 *vpp = vp; 1394 return (0); 1395 } 1396 1397 /* 1398 * Read the disklabel from the ccd. If one is not present, fake one 1399 * up. 1400 */ 1401 static void 1402 ccdgetdisklabel(dev) 1403 dev_t dev; 1404 { 1405 int unit = ccdunit(dev); 1406 struct ccd_softc *cs = &ccd_softc[unit]; 1407 char *errstring; 1408 struct disklabel *lp = &cs->sc_label; 1409 struct ccdgeom *ccg = &cs->sc_geom; 1410 1411 bzero(lp, sizeof(*lp)); 1412 1413 lp->d_secperunit = cs->sc_size; 1414 lp->d_secsize = ccg->ccg_secsize; 1415 lp->d_nsectors = ccg->ccg_nsectors; 1416 lp->d_ntracks = ccg->ccg_ntracks; 1417 lp->d_ncylinders = ccg->ccg_ncylinders; 1418 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1419 1420 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1421 lp->d_type = DTYPE_CCD; 1422 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1423 lp->d_rpm = 3600; 1424 lp->d_interleave = 1; 1425 lp->d_flags = 0; 1426 1427 lp->d_partitions[RAW_PART].p_offset = 0; 1428 lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1429 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1430 lp->d_npartitions = RAW_PART + 1; 1431 1432 lp->d_bbsize = BBSIZE; /* XXX */ 1433 lp->d_sbsize = SBSIZE; /* XXX */ 1434 1435 lp->d_magic = DISKMAGIC; 1436 lp->d_magic2 = DISKMAGIC; 1437 lp->d_checksum = dkcksum(&cs->sc_label); 1438 1439 /* 1440 * Call the generic disklabel extraction routine. 1441 */ 1442 errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label); 1443 if (errstring != NULL) 1444 ccdmakedisklabel(cs); 1445 1446 #ifdef DEBUG 1447 /* It's actually extremely common to have unlabeled ccds. */ 1448 if (ccddebug & CCDB_LABEL) 1449 if (errstring != NULL) 1450 printf("ccd%d: %s\n", unit, errstring); 1451 #endif 1452 } 1453 1454 /* 1455 * Take care of things one might want to take care of in the event 1456 * that a disklabel isn't present. 1457 */ 1458 static void 1459 ccdmakedisklabel(cs) 1460 struct ccd_softc *cs; 1461 { 1462 struct disklabel *lp = &cs->sc_label; 1463 1464 /* 1465 * For historical reasons, if there's no disklabel present 1466 * the raw partition must be marked FS_BSDFFS. 1467 */ 1468 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1469 1470 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1471 } 1472 1473 /* 1474 * Wait interruptibly for an exclusive lock. 1475 * 1476 * XXX 1477 * Several drivers do this; it should be abstracted and made MP-safe. 1478 */ 1479 static int 1480 ccdlock(cs) 1481 struct ccd_softc *cs; 1482 { 1483 int error; 1484 1485 while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1486 cs->sc_flags |= CCDF_WANTED; 1487 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1488 return (error); 1489 } 1490 cs->sc_flags |= CCDF_LOCKED; 1491 return (0); 1492 } 1493 1494 /* 1495 * Unlock and wake up any waiters. 1496 */ 1497 static void 1498 ccdunlock(cs) 1499 struct ccd_softc *cs; 1500 { 1501 1502 cs->sc_flags &= ~CCDF_LOCKED; 1503 if ((cs->sc_flags & CCDF_WANTED) != 0) { 1504 cs->sc_flags &= ~CCDF_WANTED; 1505 wakeup(cs); 1506 } 1507 } 1508 1509 #ifdef DEBUG 1510 static void 1511 printiinfo(ii) 1512 struct ccdiinfo *ii; 1513 { 1514 register int ix, i; 1515 1516 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1517 printf(" itab[%d]: #dk %d sblk %d soff %d", 1518 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1519 for (i = 0; i < ii->ii_ndisk; i++) 1520 printf(" %d", ii->ii_index[i]); 1521 printf("\n"); 1522 } 1523 } 1524 #endif 1525 1526 #endif /* NCCD > 0 */ 1527 1528 /* Local Variables: */ 1529 /* c-argdecl-indent: 8 */ 1530 /* c-continued-statement-offset: 8 */ 1531 /* c-indent-level: 8 */ 1532 /* End: */ 1533