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