1 /* $Id$ */ 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 #ifdef DEVFS 97 #include <sys/devfsext.h> 98 #endif /*DEVFS*/ 99 #include <sys/proc.h> 100 #include <sys/errno.h> 101 #include <sys/dkstat.h> 102 #include <sys/buf.h> 103 #include <sys/malloc.h> 104 #include <sys/namei.h> 105 #include <sys/conf.h> 106 #include <sys/stat.h> 107 #include <sys/ioctl.h> 108 #include <sys/disklabel.h> 109 #include <ufs/ffs/fs.h> 110 #include <sys/device.h> 111 #undef KERNEL /* XXX */ 112 #include <sys/disk.h> 113 #define KERNEL 114 #include <sys/syslog.h> 115 #include <sys/fcntl.h> 116 #include <sys/vnode.h> 117 #include <sys/dkbad.h> 118 119 #include <sys/ccdvar.h> 120 121 #if defined(CCDDEBUG) && !defined(DEBUG) 122 #define DEBUG 123 #endif 124 125 #ifdef DEBUG 126 #define CCDB_FOLLOW 0x01 127 #define CCDB_INIT 0x02 128 #define CCDB_IO 0x04 129 #define CCDB_LABEL 0x08 130 #define CCDB_VNODE 0x10 131 int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | CCDB_VNODE; 132 #undef DEBUG 133 #endif 134 135 #define ccdunit(x) dkunit(x) 136 #define ccdpart(x) dkpart(x) 137 138 /* 139 This is how mirroring works (only writes are special): 140 141 When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s 142 linked together by the cb_mirror field. "cb_pflags & 143 CCDPF_MIRROR_DONE" is set to 0 on both of them. 144 145 When a component returns to ccdiodone(), it checks if "cb_pflags & 146 CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's 147 flag and returns. If it is, it means its partner has already 148 returned, so it will go to the regular cleanup. 149 150 */ 151 152 struct ccdbuf { 153 struct buf cb_buf; /* new I/O buf */ 154 struct buf *cb_obp; /* ptr. to original I/O buf */ 155 int cb_unit; /* target unit */ 156 int cb_comp; /* target component */ 157 int cb_pflags; /* mirror/parity status flag */ 158 struct ccdbuf *cb_mirror; /* mirror counterpart */ 159 }; 160 161 /* bits in cb_pflags */ 162 #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ 163 164 #define getccdbuf() \ 165 ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) 166 #define putccdbuf(cbp) \ 167 free((caddr_t)(cbp), M_DEVBUF) 168 169 #define CCDLABELDEV(dev) \ 170 (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART))) 171 172 d_open_t ccdopen; 173 d_close_t ccdclose; 174 d_strategy_t ccdstrategy; 175 d_ioctl_t ccdioctl; 176 d_dump_t ccddump; 177 d_psize_t ccdsize; 178 d_read_t ccdread; 179 d_write_t ccdwrite; 180 181 #define CDEV_MAJOR 74 182 #define BDEV_MAJOR 21 183 184 static struct cdevsw ccd_cdevsw; 185 static struct bdevsw ccd_bdevsw = { 186 ccdopen, ccdclose, ccdstrategy, ccdioctl, 187 ccddump, ccdsize, 0, 188 "ccd", &ccd_cdevsw, -1 189 }; 190 191 /* Called by main() during pseudo-device attachment */ 192 static void ccdattach __P((void *)); 193 PSEUDO_SET(ccdattach, ccd); 194 195 /* called by biodone() at interrupt time */ 196 void ccdiodone __P((struct ccdbuf *cbp)); 197 198 static void ccdstart __P((struct ccd_softc *, struct buf *)); 199 static void ccdinterleave __P((struct ccd_softc *, int)); 200 static void ccdintr __P((struct ccd_softc *, struct buf *)); 201 static int ccdinit __P((struct ccddevice *, char **, struct proc *)); 202 static int ccdlookup __P((char *, struct proc *p, struct vnode **)); 203 static void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *, 204 struct buf *, daddr_t, caddr_t, long)); 205 static void ccdgetdisklabel __P((dev_t)); 206 static void ccdmakedisklabel __P((struct ccd_softc *)); 207 static int ccdlock __P((struct ccd_softc *)); 208 static void ccdunlock __P((struct ccd_softc *)); 209 210 #ifdef DEBUG 211 static void printiinfo __P((struct ccdiinfo *)); 212 #endif 213 214 /* Non-private for the benefit of libkvm. */ 215 struct ccd_softc *ccd_softc; 216 struct ccddevice *ccddevs; 217 int numccd = 0; 218 219 static int ccd_devsw_installed = 0; 220 221 /* 222 * Number of blocks to untouched in front of a component partition. 223 * This is to avoid violating its disklabel area when it starts at the 224 * beginning of the slice. 225 */ 226 #if !defined(CCD_OFFSET) 227 #define CCD_OFFSET 16 228 #endif 229 230 /* 231 * Called by main() during pseudo-device attachment. All we need 232 * to do is allocate enough space for devices to be configured later, and 233 * add devsw entries. 234 */ 235 void 236 ccdattach(dummy) 237 void *dummy; 238 { 239 int i; 240 int num = NCCD; 241 242 if (num > 1) 243 printf("ccd0-%d: Concatenated disk drivers\n", num-1); 244 else 245 printf("ccd0: Concatenated disk driver\n"); 246 247 ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), 248 M_DEVBUF, M_NOWAIT); 249 ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice), 250 M_DEVBUF, M_NOWAIT); 251 if ((ccd_softc == NULL) || (ccddevs == NULL)) { 252 printf("WARNING: no memory for concatenated disks\n"); 253 if (ccd_softc != NULL) 254 free(ccd_softc, M_DEVBUF); 255 if (ccddevs != NULL) 256 free(ccddevs, M_DEVBUF); 257 return; 258 } 259 numccd = num; 260 bzero(ccd_softc, num * sizeof(struct ccd_softc)); 261 bzero(ccddevs, num * sizeof(struct ccddevice)); 262 263 /* XXX: is this necessary? */ 264 for (i = 0; i < numccd; ++i) 265 ccddevs[i].ccd_dk = -1; 266 267 if( ! ccd_devsw_installed ) { 268 bdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &ccd_bdevsw); 269 ccd_devsw_installed = 1; 270 } 271 else { 272 printf("huh?\n"); 273 } 274 } 275 276 static int 277 ccdinit(ccd, cpaths, p) 278 struct ccddevice *ccd; 279 char **cpaths; 280 struct proc *p; 281 { 282 register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; 283 register struct ccdcinfo *ci = NULL; /* XXX */ 284 register size_t size; 285 register int ix; 286 struct vnode *vp; 287 struct vattr va; 288 size_t minsize; 289 int maxsecsize; 290 struct partinfo dpart; 291 struct ccdgeom *ccg = &cs->sc_geom; 292 char tmppath[MAXPATHLEN]; 293 int error; 294 295 #ifdef DEBUG 296 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 297 printf("ccdinit: unit %d\n", ccd->ccd_unit); 298 #endif 299 300 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 301 cs->sc_dk = ccd->ccd_dk; 302 #endif 303 cs->sc_size = 0; 304 cs->sc_ileave = ccd->ccd_interleave; 305 cs->sc_nccdisks = ccd->ccd_ndev; 306 307 /* Allocate space for the component info. */ 308 cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), 309 M_DEVBUF, M_WAITOK); 310 311 /* 312 * Verify that each component piece exists and record 313 * relevant information about it. 314 */ 315 maxsecsize = 0; 316 minsize = 0; 317 for (ix = 0; ix < cs->sc_nccdisks; ix++) { 318 vp = ccd->ccd_vpp[ix]; 319 ci = &cs->sc_cinfo[ix]; 320 ci->ci_vp = vp; 321 322 /* 323 * Copy in the pathname of the component. 324 */ 325 bzero(tmppath, sizeof(tmppath)); /* sanity */ 326 if (error = copyinstr(cpaths[ix], tmppath, 327 MAXPATHLEN, &ci->ci_pathlen)) { 328 #ifdef DEBUG 329 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 330 printf("ccd%d: can't copy path, error = %d\n", 331 ccd->ccd_unit, error); 332 #endif 333 while (ci > cs->sc_cinfo) { 334 ci--; 335 free(ci->ci_path, M_DEVBUF); 336 } 337 free(cs->sc_cinfo, M_DEVBUF); 338 return (error); 339 } 340 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); 341 bcopy(tmppath, ci->ci_path, ci->ci_pathlen); 342 343 /* 344 * XXX: Cache the component's dev_t. 345 */ 346 if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { 347 #ifdef DEBUG 348 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 349 printf("ccd%d: %s: getattr failed %s = %d\n", 350 ccd->ccd_unit, ci->ci_path, 351 "error", error); 352 #endif 353 while (ci >= cs->sc_cinfo) { 354 free(ci->ci_path, M_DEVBUF); 355 ci--; 356 } 357 free(cs->sc_cinfo, M_DEVBUF); 358 return (error); 359 } 360 ci->ci_dev = va.va_rdev; 361 362 /* 363 * Get partition information for the component. 364 */ 365 if (error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, 366 FREAD, p->p_ucred, p)) { 367 #ifdef DEBUG 368 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 369 printf("ccd%d: %s: ioctl failed, error = %d\n", 370 ccd->ccd_unit, ci->ci_path, 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 if (dpart.part->p_fstype == FS_BSDFFS) { 380 maxsecsize = 381 ((dpart.disklab->d_secsize > maxsecsize) ? 382 dpart.disklab->d_secsize : maxsecsize); 383 size = dpart.part->p_size - CCD_OFFSET; 384 } else { 385 #ifdef DEBUG 386 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 387 printf("ccd%d: %s: incorrect partition type\n", 388 ccd->ccd_unit, ci->ci_path); 389 #endif 390 while (ci >= cs->sc_cinfo) { 391 free(ci->ci_path, M_DEVBUF); 392 ci--; 393 } 394 free(cs->sc_cinfo, M_DEVBUF); 395 return (EFTYPE); 396 } 397 398 /* 399 * Calculate the size, truncating to an interleave 400 * boundary if necessary. 401 */ 402 #ifndef __FreeBSD__ 403 if (size < 0) 404 size = 0; 405 #endif 406 407 if (cs->sc_ileave > 1) 408 size -= size % cs->sc_ileave; 409 410 if (size == 0) { 411 #ifdef DEBUG 412 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 413 printf("ccd%d: %s: size == 0\n", 414 ccd->ccd_unit, ci->ci_path); 415 #endif 416 while (ci >= cs->sc_cinfo) { 417 free(ci->ci_path, M_DEVBUF); 418 ci--; 419 } 420 free(cs->sc_cinfo, M_DEVBUF); 421 return (ENODEV); 422 } 423 424 if (minsize == 0 || size < minsize) 425 minsize = size; 426 ci->ci_size = size; 427 cs->sc_size += size; 428 } 429 430 /* 431 * Don't allow the interleave to be smaller than 432 * the biggest component sector. 433 */ 434 if ((cs->sc_ileave > 0) && 435 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { 436 #ifdef DEBUG 437 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 438 printf("ccd%d: interleave must be at least %d\n", 439 ccd->ccd_unit, (maxsecsize / DEV_BSIZE)); 440 #endif 441 while (ci >= cs->sc_cinfo) { 442 free(ci->ci_path, M_DEVBUF); 443 ci--; 444 } 445 free(cs->sc_cinfo, M_DEVBUF); 446 return (EINVAL); 447 } 448 449 /* 450 * If uniform interleave is desired set all sizes to that of 451 * the smallest component. 452 */ 453 if (ccd->ccd_flags & CCDF_UNIFORM) { 454 for (ci = cs->sc_cinfo; 455 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 456 ci->ci_size = minsize; 457 if (ccd->ccd_flags & CCDF_MIRROR) { 458 /* 459 * Check to see if an even number of components 460 * have been specified. 461 */ 462 if (cs->sc_nccdisks % 2) { 463 printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit ); 464 while (ci > cs->sc_cinfo) { 465 ci--; 466 free(ci->ci_path, M_DEVBUF); 467 } 468 free(cs->sc_cinfo, M_DEVBUF); 469 return (EINVAL); 470 } 471 cs->sc_size = (cs->sc_nccdisks/2) * minsize; 472 } 473 else if (ccd->ccd_flags & CCDF_PARITY) 474 cs->sc_size = (cs->sc_nccdisks-1) * minsize; 475 else 476 cs->sc_size = cs->sc_nccdisks * minsize; 477 } 478 479 /* 480 * Construct the interleave table. 481 */ 482 ccdinterleave(cs, ccd->ccd_unit); 483 484 /* 485 * Create pseudo-geometry based on 1MB cylinders. It's 486 * pretty close. 487 */ 488 ccg->ccg_secsize = DEV_BSIZE; 489 ccg->ccg_ntracks = 1; 490 ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); 491 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; 492 493 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 494 if (ccd->ccd_dk >= 0) 495 dk_wpms[ccd->ccd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 496 #endif 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 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)) 629 return (error); 630 631 lp = &cs->sc_dkdev.dk_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_dkdev.dk_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_dkdev.dk_copenmask |= pmask; 655 break; 656 657 case S_IFBLK: 658 cs->sc_dkdev.dk_bopenmask |= pmask; 659 break; 660 } 661 cs->sc_dkdev.dk_openmask = 662 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 663 664 done: 665 ccdunlock(cs); 666 return (0); 667 } 668 669 /* ARGSUSED */ 670 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)) 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_dkdev.dk_copenmask &= ~(1 << part); 698 break; 699 700 case S_IFBLK: 701 cs->sc_dkdev.dk_bopenmask &= ~(1 << part); 702 break; 703 } 704 cs->sc_dkdev.dk_openmask = 705 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; 706 707 ccdunlock(cs); 708 return (0); 709 } 710 711 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_dkdev.dk_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 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 777 /* 778 * Instrumentation (not very meaningful) 779 */ 780 cs->sc_nactive++; 781 if (cs->sc_dk >= 0) { 782 dk_busy |= 1 << cs->sc_dk; 783 dk_xfer[cs->sc_dk]++; 784 dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 785 } 786 #endif 787 788 /* 789 * Translate the partition-relative block number to an absolute. 790 */ 791 bn = bp->b_blkno; 792 if (ccdpart(bp->b_dev) != RAW_PART) { 793 pp = &cs->sc_dkdev.dk_label.d_partitions[ccdpart(bp->b_dev)]; 794 bn += pp->p_offset; 795 } 796 797 /* 798 * Allocate component buffers and fire off the requests 799 */ 800 addr = bp->b_data; 801 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 802 ccdbuffer(cbp, cs, bp, bn, addr, bcount); 803 rcount = cbp[0]->cb_buf.b_bcount; 804 if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) 805 cbp[0]->cb_buf.b_vp->v_numoutput++; 806 VOP_STRATEGY(&cbp[0]->cb_buf); 807 if (cs->sc_cflags & CCDF_MIRROR && 808 (cbp[0]->cb_buf.b_flags & B_READ) == 0) { 809 /* mirror, start another write */ 810 cbp[1]->cb_buf.b_vp->v_numoutput++; 811 VOP_STRATEGY(&cbp[1]->cb_buf); 812 } 813 bn += btodb(rcount); 814 addr += rcount; 815 } 816 } 817 818 /* 819 * Build a component buffer header. 820 */ 821 void 822 ccdbuffer(cb, cs, bp, bn, addr, bcount) 823 register struct ccdbuf **cb; 824 register struct ccd_softc *cs; 825 struct buf *bp; 826 daddr_t bn; 827 caddr_t addr; 828 long bcount; 829 { 830 register struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ 831 register struct ccdbuf *cbp; 832 register daddr_t cbn, cboff; 833 834 #ifdef DEBUG 835 if (ccddebug & CCDB_IO) 836 printf("ccdbuffer(%x, %x, %d, %x, %d)\n", 837 cs, bp, bn, addr, bcount); 838 #endif 839 /* 840 * Determine which component bn falls in. 841 */ 842 cbn = bn; 843 cboff = 0; 844 845 /* 846 * Serially concatenated 847 */ 848 if (cs->sc_ileave == 0) { 849 register daddr_t sblk; 850 851 sblk = 0; 852 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 853 sblk += ci->ci_size; 854 cbn -= sblk; 855 } 856 /* 857 * Interleaved 858 */ 859 else { 860 register struct ccdiinfo *ii; 861 int ccdisk, off; 862 863 cboff = cbn % cs->sc_ileave; 864 cbn /= cs->sc_ileave; 865 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 866 if (ii->ii_startblk > cbn) 867 break; 868 ii--; 869 off = cbn - ii->ii_startblk; 870 if (ii->ii_ndisk == 1) { 871 ccdisk = ii->ii_index[0]; 872 cbn = ii->ii_startoff + off; 873 } else { 874 if (cs->sc_cflags & CCDF_MIRROR) { 875 ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)]; 876 cbn = ii->ii_startoff + off / (ii->ii_ndisk/2); 877 /* mirrored data */ 878 ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2]; 879 } 880 else if (cs->sc_cflags & CCDF_PARITY) { 881 ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)]; 882 cbn = ii->ii_startoff + off / (ii->ii_ndisk-1); 883 if (cbn % ii->ii_ndisk <= ccdisk) 884 ccdisk++; 885 } 886 else { 887 ccdisk = ii->ii_index[off % ii->ii_ndisk]; 888 cbn = ii->ii_startoff + off / ii->ii_ndisk; 889 } 890 } 891 cbn *= cs->sc_ileave; 892 ci = &cs->sc_cinfo[ccdisk]; 893 } 894 895 /* 896 * Fill in the component buf structure. 897 */ 898 cbp = getccdbuf(); 899 cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 900 cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone; 901 cbp->cb_buf.b_proc = bp->b_proc; 902 cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */ 903 cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET; 904 cbp->cb_buf.b_data = addr; 905 cbp->cb_buf.b_vp = ci->ci_vp; 906 if (cs->sc_ileave == 0) 907 cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn); 908 else 909 cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff); 910 if (cbp->cb_buf.b_bcount > bcount) 911 cbp->cb_buf.b_bcount = bcount; 912 913 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount; 914 915 /* 916 * context for ccdiodone 917 */ 918 cbp->cb_obp = bp; 919 cbp->cb_unit = cs - ccd_softc; 920 cbp->cb_comp = ci - cs->sc_cinfo; 921 922 #ifdef DEBUG 923 if (ccddebug & CCDB_IO) 924 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 925 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 926 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 927 #endif 928 cb[0] = cbp; 929 if (cs->sc_cflags & CCDF_MIRROR && 930 (cbp->cb_buf.b_flags & B_READ) == 0) { 931 /* mirror, start one more write */ 932 cbp = getccdbuf(); 933 *cbp = *cb[0]; 934 cbp->cb_buf.b_dev = ci2->ci_dev; 935 cbp->cb_buf.b_vp = ci2->ci_vp; 936 cbp->cb_comp = ci2 - cs->sc_cinfo; 937 cb[1] = cbp; 938 /* link together the ccdbuf's and clear "mirror done" flag */ 939 cb[0]->cb_mirror = cb[1]; 940 cb[1]->cb_mirror = cb[0]; 941 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; 942 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; 943 } 944 } 945 946 static void 947 ccdintr(cs, bp) 948 register struct ccd_softc *cs; 949 register struct buf *bp; 950 { 951 952 #ifdef DEBUG 953 if (ccddebug & CCDB_FOLLOW) 954 printf("ccdintr(%x, %x)\n", cs, bp); 955 #endif 956 /* 957 * Request is done for better or worse, wakeup the top half. 958 */ 959 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 960 --cs->sc_nactive; 961 #ifdef DIAGNOSTIC 962 if (cs->sc_nactive < 0) 963 panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit); 964 #endif 965 966 if (cs->sc_nactive == 0 && cs->sc_dk >= 0) 967 dk_busy &= ~(1 << cs->sc_dk); 968 #endif 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 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 int 1036 ccdioctl(dev, cmd, data, flag, p) 1037 dev_t dev; 1038 int 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 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1052 extern int dkn; 1053 #endif 1054 1055 if (unit >= numccd) 1056 return (ENXIO); 1057 cs = &ccd_softc[unit]; 1058 1059 bzero(&ccd, sizeof(ccd)); 1060 1061 switch (cmd) { 1062 case CCDIOCSET: 1063 if (cs->sc_flags & CCDF_INITED) 1064 return (EBUSY); 1065 1066 if ((flag & FWRITE) == 0) 1067 return (EBADF); 1068 1069 if (error = ccdlock(cs)) 1070 return (error); 1071 1072 /* Fill in some important bits. */ 1073 ccd.ccd_unit = unit; 1074 ccd.ccd_interleave = ccio->ccio_ileave; 1075 if (ccd.ccd_interleave == 0 && 1076 ((ccio->ccio_flags & CCDF_MIRROR) || 1077 (ccio->ccio_flags & CCDF_PARITY))) { 1078 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit); 1079 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY); 1080 } 1081 if ((ccio->ccio_flags & CCDF_MIRROR) && 1082 (ccio->ccio_flags & CCDF_PARITY)) { 1083 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit); 1084 ccio->ccio_flags &= ~CCDF_PARITY; 1085 } 1086 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) && 1087 !(ccio->ccio_flags & CCDF_UNIFORM)) { 1088 printf("ccd%d: mirror/parity forces uniform flag\n", 1089 unit); 1090 ccio->ccio_flags |= CCDF_UNIFORM; 1091 } 1092 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; 1093 1094 /* 1095 * Allocate space for and copy in the array of 1096 * componet pathnames and device numbers. 1097 */ 1098 cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1099 M_DEVBUF, M_WAITOK); 1100 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1101 M_DEVBUF, M_WAITOK); 1102 1103 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1104 ccio->ccio_ndisks * sizeof(char **)); 1105 if (error) { 1106 free(vpp, M_DEVBUF); 1107 free(cpp, M_DEVBUF); 1108 ccdunlock(cs); 1109 return (error); 1110 } 1111 1112 #ifdef DEBUG 1113 if (ccddebug & CCDB_INIT) 1114 for (i = 0; i < ccio->ccio_ndisks; ++i) 1115 printf("ccdioctl: component %d: 0x%x\n", 1116 i, cpp[i]); 1117 #endif 1118 1119 for (i = 0; i < ccio->ccio_ndisks; ++i) { 1120 #ifdef DEBUG 1121 if (ccddebug & CCDB_INIT) 1122 printf("ccdioctl: lookedup = %d\n", lookedup); 1123 #endif 1124 if (error = ccdlookup(cpp[i], p, &vpp[i])) { 1125 for (j = 0; j < lookedup; ++j) 1126 (void)vn_close(vpp[j], FREAD|FWRITE, 1127 p->p_ucred, p); 1128 free(vpp, M_DEVBUF); 1129 free(cpp, M_DEVBUF); 1130 ccdunlock(cs); 1131 return (error); 1132 } 1133 ++lookedup; 1134 } 1135 ccd.ccd_cpp = cpp; 1136 ccd.ccd_vpp = vpp; 1137 ccd.ccd_ndev = ccio->ccio_ndisks; 1138 1139 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1140 /* 1141 * Assign disk index first so that init routine 1142 * can use it (saves having the driver drag around 1143 * the ccddevice pointer just to set up the dk_* 1144 * info in the open routine). 1145 */ 1146 if (dkn < DK_NDRIVE) 1147 ccd.ccd_dk = dkn++; 1148 else 1149 ccd.ccd_dk = -1; 1150 #endif 1151 1152 /* 1153 * Initialize the ccd. Fills in the softc for us. 1154 */ 1155 if (error = ccdinit(&ccd, cpp, p)) { 1156 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1157 if (ccd.ccd_dk >= 0) 1158 --dkn; 1159 #endif 1160 for (j = 0; j < lookedup; ++j) 1161 (void)vn_close(vpp[j], FREAD|FWRITE, 1162 p->p_ucred, p); 1163 bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); 1164 free(vpp, M_DEVBUF); 1165 free(cpp, M_DEVBUF); 1166 ccdunlock(cs); 1167 return (error); 1168 } 1169 1170 /* 1171 * The ccd has been successfully initialized, so 1172 * we can place it into the array and read the disklabel. 1173 */ 1174 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1175 ccio->ccio_unit = unit; 1176 ccio->ccio_size = cs->sc_size; 1177 ccdgetdisklabel(dev); 1178 1179 ccdunlock(cs); 1180 1181 break; 1182 1183 case CCDIOCCLR: 1184 if ((cs->sc_flags & CCDF_INITED) == 0) 1185 return (ENXIO); 1186 1187 if ((flag & FWRITE) == 0) 1188 return (EBADF); 1189 1190 if (error = ccdlock(cs)) 1191 return (error); 1192 1193 /* 1194 * Don't unconfigure if any other partitions are open 1195 * or if both the character and block flavors of this 1196 * partition are open. 1197 */ 1198 part = ccdpart(dev); 1199 pmask = (1 << part); 1200 if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1201 ((cs->sc_dkdev.dk_bopenmask & pmask) && 1202 (cs->sc_dkdev.dk_copenmask & pmask))) { 1203 ccdunlock(cs); 1204 return (EBUSY); 1205 } 1206 1207 /* 1208 * Free ccd_softc information and clear entry. 1209 */ 1210 1211 /* Close the components and free their pathnames. */ 1212 for (i = 0; i < cs->sc_nccdisks; ++i) { 1213 /* 1214 * XXX: this close could potentially fail and 1215 * cause Bad Things. Maybe we need to force 1216 * the close to happen? 1217 */ 1218 #ifdef DEBUG 1219 if (ccddebug & CCDB_VNODE) 1220 vprint("CCDIOCCLR: vnode info", 1221 cs->sc_cinfo[i].ci_vp); 1222 #endif 1223 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1224 p->p_ucred, p); 1225 free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1226 } 1227 1228 /* Free interleave index. */ 1229 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1230 free(cs->sc_itable[i].ii_index, M_DEVBUF); 1231 1232 /* Free component info and interleave table. */ 1233 free(cs->sc_cinfo, M_DEVBUF); 1234 free(cs->sc_itable, M_DEVBUF); 1235 cs->sc_flags &= ~CCDF_INITED; 1236 1237 /* 1238 * Free ccddevice information and clear entry. 1239 */ 1240 free(ccddevs[unit].ccd_cpp, M_DEVBUF); 1241 free(ccddevs[unit].ccd_vpp, M_DEVBUF); 1242 ccd.ccd_dk = -1; 1243 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1244 1245 /* This must be atomic. */ 1246 s = splhigh(); 1247 ccdunlock(cs); 1248 bzero(cs, sizeof(struct ccd_softc)); 1249 splx(s); 1250 1251 break; 1252 1253 case DIOCGDINFO: 1254 if ((cs->sc_flags & CCDF_INITED) == 0) 1255 return (ENXIO); 1256 1257 *(struct disklabel *)data = cs->sc_dkdev.dk_label; 1258 break; 1259 1260 case DIOCGPART: 1261 if ((cs->sc_flags & CCDF_INITED) == 0) 1262 return (ENXIO); 1263 1264 ((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label; 1265 ((struct partinfo *)data)->part = 1266 &cs->sc_dkdev.dk_label.d_partitions[ccdpart(dev)]; 1267 break; 1268 1269 case DIOCWDINFO: 1270 case DIOCSDINFO: 1271 if ((cs->sc_flags & CCDF_INITED) == 0) 1272 return (ENXIO); 1273 1274 if ((flag & FWRITE) == 0) 1275 return (EBADF); 1276 1277 if (error = ccdlock(cs)) 1278 return (error); 1279 1280 cs->sc_flags |= CCDF_LABELLING; 1281 1282 error = setdisklabel(&cs->sc_dkdev.dk_label, 1283 (struct disklabel *)data, 0); 1284 /*, &cs->sc_dkdev.dk_cpulabel); */ 1285 if (error == 0) { 1286 if (cmd == DIOCWDINFO) 1287 error = writedisklabel(CCDLABELDEV(dev), 1288 ccdstrategy, &cs->sc_dkdev.dk_label); 1289 /* 1290 &cs->sc_dkdev.dk_cpulabel); */ 1291 } 1292 1293 cs->sc_flags &= ~CCDF_LABELLING; 1294 1295 ccdunlock(cs); 1296 1297 if (error) 1298 return (error); 1299 break; 1300 1301 case DIOCWLABEL: 1302 if ((cs->sc_flags & CCDF_INITED) == 0) 1303 return (ENXIO); 1304 1305 if ((flag & FWRITE) == 0) 1306 return (EBADF); 1307 if (*(int *)data != 0) 1308 cs->sc_flags |= CCDF_WLABEL; 1309 else 1310 cs->sc_flags &= ~CCDF_WLABEL; 1311 break; 1312 1313 default: 1314 return (ENOTTY); 1315 } 1316 1317 return (0); 1318 } 1319 1320 int 1321 ccdsize(dev) 1322 dev_t dev; 1323 { 1324 struct ccd_softc *cs; 1325 int part, size; 1326 1327 if (ccdopen(dev, 0, S_IFBLK, curproc)) 1328 return (-1); 1329 1330 cs = &ccd_softc[ccdunit(dev)]; 1331 part = ccdpart(dev); 1332 1333 if ((cs->sc_flags & CCDF_INITED) == 0) 1334 return (-1); 1335 1336 if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP) 1337 size = -1; 1338 else 1339 size = cs->sc_dkdev.dk_label.d_partitions[part].p_size; 1340 1341 if (ccdclose(dev, 0, S_IFBLK, curproc)) 1342 return (-1); 1343 1344 return (size); 1345 } 1346 1347 int 1348 ccddump(dev) 1349 dev_t dev; 1350 { 1351 1352 /* Not implemented. */ 1353 return ENXIO; 1354 } 1355 1356 /* 1357 * Lookup the provided name in the filesystem. If the file exists, 1358 * is a valid block device, and isn't being used by anyone else, 1359 * set *vpp to the file's vnode. 1360 */ 1361 static int 1362 ccdlookup(path, p, vpp) 1363 char *path; 1364 struct proc *p; 1365 struct vnode **vpp; /* result */ 1366 { 1367 struct nameidata nd; 1368 struct vnode *vp; 1369 struct vattr va; 1370 int error; 1371 1372 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1373 if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 1374 #ifdef DEBUG 1375 if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1376 printf("ccdlookup: vn_open error = %d\n", error); 1377 #endif 1378 return (error); 1379 } 1380 vp = nd.ni_vp; 1381 1382 if (vp->v_usecount > 1) { 1383 VOP_UNLOCK(vp, 0, p); 1384 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1385 return (EBUSY); 1386 } 1387 1388 if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { 1389 #ifdef DEBUG 1390 if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1391 printf("ccdlookup: getattr error = %d\n", error); 1392 #endif 1393 VOP_UNLOCK(vp, 0, p); 1394 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1395 return (error); 1396 } 1397 1398 /* XXX: eventually we should handle VREG, too. */ 1399 if (va.va_type != VBLK) { 1400 VOP_UNLOCK(vp, 0, p); 1401 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1402 return (ENOTBLK); 1403 } 1404 1405 #ifdef DEBUG 1406 if (ccddebug & CCDB_VNODE) 1407 vprint("ccdlookup: vnode info", vp); 1408 #endif 1409 1410 VOP_UNLOCK(vp, 0, p); 1411 *vpp = vp; 1412 return (0); 1413 } 1414 1415 /* 1416 * Read the disklabel from the ccd. If one is not present, fake one 1417 * up. 1418 */ 1419 static void 1420 ccdgetdisklabel(dev) 1421 dev_t dev; 1422 { 1423 int unit = ccdunit(dev); 1424 struct ccd_softc *cs = &ccd_softc[unit]; 1425 char *errstring; 1426 struct disklabel *lp = &cs->sc_dkdev.dk_label; 1427 struct ccdgeom *ccg = &cs->sc_geom; 1428 1429 bzero(lp, sizeof(*lp)); 1430 1431 lp->d_secperunit = cs->sc_size; 1432 lp->d_secsize = ccg->ccg_secsize; 1433 lp->d_nsectors = ccg->ccg_nsectors; 1434 lp->d_ntracks = ccg->ccg_ntracks; 1435 lp->d_ncylinders = ccg->ccg_ncylinders; 1436 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1437 1438 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1439 lp->d_type = DTYPE_CCD; 1440 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1441 lp->d_rpm = 3600; 1442 lp->d_interleave = 1; 1443 lp->d_flags = 0; 1444 1445 lp->d_partitions[RAW_PART].p_offset = 0; 1446 lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1447 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1448 lp->d_npartitions = RAW_PART + 1; 1449 1450 lp->d_bbsize = BBSIZE; /* XXX */ 1451 lp->d_sbsize = SBSIZE; /* XXX */ 1452 1453 lp->d_magic = DISKMAGIC; 1454 lp->d_magic2 = DISKMAGIC; 1455 lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label); 1456 1457 /* 1458 * Call the generic disklabel extraction routine. 1459 */ 1460 if (errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1461 &cs->sc_dkdev.dk_label)) 1462 ccdmakedisklabel(cs); 1463 1464 #ifdef DEBUG 1465 /* It's actually extremely common to have unlabeled ccds. */ 1466 if (ccddebug & CCDB_LABEL) 1467 if (errstring != NULL) 1468 printf("ccd%d: %s\n", unit, errstring); 1469 #endif 1470 } 1471 1472 /* 1473 * Take care of things one might want to take care of in the event 1474 * that a disklabel isn't present. 1475 */ 1476 static void 1477 ccdmakedisklabel(cs) 1478 struct ccd_softc *cs; 1479 { 1480 struct disklabel *lp = &cs->sc_dkdev.dk_label; 1481 1482 /* 1483 * For historical reasons, if there's no disklabel present 1484 * the raw partition must be marked FS_BSDFFS. 1485 */ 1486 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1487 1488 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1489 } 1490 1491 /* 1492 * Wait interruptibly for an exclusive lock. 1493 * 1494 * XXX 1495 * Several drivers do this; it should be abstracted and made MP-safe. 1496 */ 1497 static int 1498 ccdlock(cs) 1499 struct ccd_softc *cs; 1500 { 1501 int error; 1502 1503 while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1504 cs->sc_flags |= CCDF_WANTED; 1505 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1506 return (error); 1507 } 1508 cs->sc_flags |= CCDF_LOCKED; 1509 return (0); 1510 } 1511 1512 /* 1513 * Unlock and wake up any waiters. 1514 */ 1515 static void 1516 ccdunlock(cs) 1517 struct ccd_softc *cs; 1518 { 1519 1520 cs->sc_flags &= ~CCDF_LOCKED; 1521 if ((cs->sc_flags & CCDF_WANTED) != 0) { 1522 cs->sc_flags &= ~CCDF_WANTED; 1523 wakeup(cs); 1524 } 1525 } 1526 1527 #ifdef DEBUG 1528 static void 1529 printiinfo(ii) 1530 struct ccdiinfo *ii; 1531 { 1532 register int ix, i; 1533 1534 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1535 printf(" itab[%d]: #dk %d sblk %d soff %d", 1536 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1537 for (i = 0; i < ii->ii_ndisk; i++) 1538 printf(" %d", ii->ii_index[i]); 1539 printf("\n"); 1540 } 1541 } 1542 #endif 1543 1544 #endif /* NCCD > 0 */ 1545 1546 /* Local Variables: */ 1547 /* c-argdecl-indent: 8 */ 1548 /* c-continued-statement-offset: 8 */ 1549 /* c-indent-level: 8 */ 1550 /* End: */ 1551