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