1 /* $Id: ccd.c,v 1.16 1996/07/24 23:45:24 asami 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/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 /* 914 * context for ccdiodone 915 */ 916 cbp->cb_obp = bp; 917 cbp->cb_unit = cs - ccd_softc; 918 cbp->cb_comp = ci - cs->sc_cinfo; 919 920 #ifdef DEBUG 921 if (ccddebug & CCDB_IO) 922 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 923 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 924 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 925 #endif 926 cb[0] = cbp; 927 if (cs->sc_cflags & CCDF_MIRROR && 928 (cbp->cb_buf.b_flags & B_READ) == 0) { 929 /* mirror, start one more write */ 930 cbp = getccdbuf(); 931 *cbp = *cb[0]; 932 cbp->cb_buf.b_dev = ci2->ci_dev; 933 cbp->cb_buf.b_vp = ci2->ci_vp; 934 cbp->cb_comp = ci2 - cs->sc_cinfo; 935 cb[1] = cbp; 936 /* link together the ccdbuf's and clear "mirror done" flag */ 937 cb[0]->cb_mirror = cb[1]; 938 cb[1]->cb_mirror = cb[0]; 939 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; 940 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; 941 } 942 } 943 944 static void 945 ccdintr(cs, bp) 946 register struct ccd_softc *cs; 947 register struct buf *bp; 948 { 949 950 #ifdef DEBUG 951 if (ccddebug & CCDB_FOLLOW) 952 printf("ccdintr(%x, %x)\n", cs, bp); 953 #endif 954 /* 955 * Request is done for better or worse, wakeup the top half. 956 */ 957 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 958 --cs->sc_nactive; 959 #ifdef DIAGNOSTIC 960 if (cs->sc_nactive < 0) 961 panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit); 962 #endif 963 964 if (cs->sc_nactive == 0 && cs->sc_dk >= 0) 965 dk_busy &= ~(1 << cs->sc_dk); 966 #endif 967 if (bp->b_flags & B_ERROR) 968 bp->b_resid = bp->b_bcount; 969 biodone(bp); 970 } 971 972 /* 973 * Called at interrupt time. 974 * Mark the component as done and if all components are done, 975 * take a ccd interrupt. 976 */ 977 void 978 ccdiodone(cbp) 979 struct ccdbuf *cbp; 980 { 981 register struct buf *bp = cbp->cb_obp; 982 register int unit = cbp->cb_unit; 983 int count, s; 984 985 s = splbio(); 986 #ifdef DEBUG 987 if (ccddebug & CCDB_FOLLOW) 988 printf("ccdiodone(%x)\n", cbp); 989 if (ccddebug & CCDB_IO) { 990 printf("ccdiodone: bp %x bcount %d resid %d\n", 991 bp, bp->b_bcount, bp->b_resid); 992 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 993 cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 994 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 995 cbp->cb_buf.b_bcount); 996 } 997 #endif 998 999 if (cbp->cb_buf.b_flags & B_ERROR) { 1000 bp->b_flags |= B_ERROR; 1001 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO; 1002 #ifdef DEBUG 1003 printf("ccd%d: error %d on component %d\n", 1004 unit, bp->b_error, cbp->cb_comp); 1005 #endif 1006 } 1007 1008 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR && 1009 (cbp->cb_buf.b_flags & B_READ) == 0) 1010 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { 1011 /* I'm done before my counterpart, so just set 1012 partner's flag and return */ 1013 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; 1014 putccdbuf(cbp); 1015 splx(s); 1016 return; 1017 } 1018 1019 count = cbp->cb_buf.b_bcount; 1020 putccdbuf(cbp); 1021 1022 /* 1023 * If all done, "interrupt". 1024 */ 1025 bp->b_resid -= count; 1026 if (bp->b_resid < 0) 1027 panic("ccdiodone: count"); 1028 if (bp->b_resid == 0) 1029 ccdintr(&ccd_softc[unit], bp); 1030 splx(s); 1031 } 1032 1033 int 1034 ccdioctl(dev, cmd, data, flag, p) 1035 dev_t dev; 1036 int cmd; 1037 caddr_t data; 1038 int flag; 1039 struct proc *p; 1040 { 1041 int unit = ccdunit(dev); 1042 int i, j, lookedup = 0, error = 0; 1043 int part, pmask, s; 1044 struct ccd_softc *cs; 1045 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; 1046 struct ccddevice ccd; 1047 char **cpp; 1048 struct vnode **vpp; 1049 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1050 extern int dkn; 1051 #endif 1052 1053 if (unit >= numccd) 1054 return (ENXIO); 1055 cs = &ccd_softc[unit]; 1056 1057 bzero(&ccd, sizeof(ccd)); 1058 1059 switch (cmd) { 1060 case CCDIOCSET: 1061 if (cs->sc_flags & CCDF_INITED) 1062 return (EBUSY); 1063 1064 if ((flag & FWRITE) == 0) 1065 return (EBADF); 1066 1067 if (error = ccdlock(cs)) 1068 return (error); 1069 1070 /* Fill in some important bits. */ 1071 ccd.ccd_unit = unit; 1072 ccd.ccd_interleave = ccio->ccio_ileave; 1073 if (ccd.ccd_interleave == 0 && 1074 ((ccio->ccio_flags & CCDF_MIRROR) || 1075 (ccio->ccio_flags & CCDF_PARITY))) { 1076 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit); 1077 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY); 1078 } 1079 if ((ccio->ccio_flags & CCDF_MIRROR) && 1080 (ccio->ccio_flags & CCDF_PARITY)) { 1081 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit); 1082 ccio->ccio_flags &= ~CCDF_PARITY; 1083 } 1084 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) && 1085 !(ccio->ccio_flags & CCDF_UNIFORM)) { 1086 printf("ccd%d: mirror/parity forces uniform flag\n", 1087 unit); 1088 ccio->ccio_flags |= CCDF_UNIFORM; 1089 } 1090 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; 1091 1092 /* 1093 * Allocate space for and copy in the array of 1094 * componet pathnames and device numbers. 1095 */ 1096 cpp = malloc(ccio->ccio_ndisks * sizeof(char *), 1097 M_DEVBUF, M_WAITOK); 1098 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), 1099 M_DEVBUF, M_WAITOK); 1100 1101 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, 1102 ccio->ccio_ndisks * sizeof(char **)); 1103 if (error) { 1104 free(vpp, M_DEVBUF); 1105 free(cpp, M_DEVBUF); 1106 ccdunlock(cs); 1107 return (error); 1108 } 1109 1110 #ifdef DEBUG 1111 if (ccddebug & CCDB_INIT) 1112 for (i = 0; i < ccio->ccio_ndisks; ++i) 1113 printf("ccdioctl: component %d: 0x%x\n", 1114 i, cpp[i]); 1115 #endif 1116 1117 for (i = 0; i < ccio->ccio_ndisks; ++i) { 1118 #ifdef DEBUG 1119 if (ccddebug & CCDB_INIT) 1120 printf("ccdioctl: lookedup = %d\n", lookedup); 1121 #endif 1122 if (error = ccdlookup(cpp[i], p, &vpp[i])) { 1123 for (j = 0; j < lookedup; ++j) 1124 (void)vn_close(vpp[j], FREAD|FWRITE, 1125 p->p_ucred, p); 1126 free(vpp, M_DEVBUF); 1127 free(cpp, M_DEVBUF); 1128 ccdunlock(cs); 1129 return (error); 1130 } 1131 ++lookedup; 1132 } 1133 ccd.ccd_cpp = cpp; 1134 ccd.ccd_vpp = vpp; 1135 ccd.ccd_ndev = ccio->ccio_ndisks; 1136 1137 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1138 /* 1139 * Assign disk index first so that init routine 1140 * can use it (saves having the driver drag around 1141 * the ccddevice pointer just to set up the dk_* 1142 * info in the open routine). 1143 */ 1144 if (dkn < DK_NDRIVE) 1145 ccd.ccd_dk = dkn++; 1146 else 1147 ccd.ccd_dk = -1; 1148 #endif 1149 1150 /* 1151 * Initialize the ccd. Fills in the softc for us. 1152 */ 1153 if (error = ccdinit(&ccd, cpp, p)) { 1154 #ifdef WORKING_DISK_STATISTICS /* XXX !! */ 1155 if (ccd.ccd_dk >= 0) 1156 --dkn; 1157 #endif 1158 for (j = 0; j < lookedup; ++j) 1159 (void)vn_close(vpp[j], FREAD|FWRITE, 1160 p->p_ucred, p); 1161 bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); 1162 free(vpp, M_DEVBUF); 1163 free(cpp, M_DEVBUF); 1164 ccdunlock(cs); 1165 return (error); 1166 } 1167 1168 /* 1169 * The ccd has been successfully initialized, so 1170 * we can place it into the array and read the disklabel. 1171 */ 1172 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1173 ccio->ccio_unit = unit; 1174 ccio->ccio_size = cs->sc_size; 1175 ccdgetdisklabel(dev); 1176 1177 ccdunlock(cs); 1178 1179 break; 1180 1181 case CCDIOCCLR: 1182 if ((cs->sc_flags & CCDF_INITED) == 0) 1183 return (ENXIO); 1184 1185 if ((flag & FWRITE) == 0) 1186 return (EBADF); 1187 1188 if (error = ccdlock(cs)) 1189 return (error); 1190 1191 /* 1192 * Don't unconfigure if any other partitions are open 1193 * or if both the character and block flavors of this 1194 * partition are open. 1195 */ 1196 part = ccdpart(dev); 1197 pmask = (1 << part); 1198 if ((cs->sc_dkdev.dk_openmask & ~pmask) || 1199 ((cs->sc_dkdev.dk_bopenmask & pmask) && 1200 (cs->sc_dkdev.dk_copenmask & pmask))) { 1201 ccdunlock(cs); 1202 return (EBUSY); 1203 } 1204 1205 /* 1206 * Free ccd_softc information and clear entry. 1207 */ 1208 1209 /* Close the components and free their pathnames. */ 1210 for (i = 0; i < cs->sc_nccdisks; ++i) { 1211 /* 1212 * XXX: this close could potentially fail and 1213 * cause Bad Things. Maybe we need to force 1214 * the close to happen? 1215 */ 1216 #ifdef DEBUG 1217 if (ccddebug & CCDB_VNODE) 1218 vprint("CCDIOCCLR: vnode info", 1219 cs->sc_cinfo[i].ci_vp); 1220 #endif 1221 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, 1222 p->p_ucred, p); 1223 free(cs->sc_cinfo[i].ci_path, M_DEVBUF); 1224 } 1225 1226 /* Free interleave index. */ 1227 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) 1228 free(cs->sc_itable[i].ii_index, M_DEVBUF); 1229 1230 /* Free component info and interleave table. */ 1231 free(cs->sc_cinfo, M_DEVBUF); 1232 free(cs->sc_itable, M_DEVBUF); 1233 cs->sc_flags &= ~CCDF_INITED; 1234 1235 /* 1236 * Free ccddevice information and clear entry. 1237 */ 1238 free(ccddevs[unit].ccd_cpp, M_DEVBUF); 1239 free(ccddevs[unit].ccd_vpp, M_DEVBUF); 1240 ccd.ccd_dk = -1; 1241 bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); 1242 1243 /* This must be atomic. */ 1244 s = splhigh(); 1245 ccdunlock(cs); 1246 bzero(cs, sizeof(struct ccd_softc)); 1247 splx(s); 1248 1249 break; 1250 1251 case DIOCGDINFO: 1252 if ((cs->sc_flags & CCDF_INITED) == 0) 1253 return (ENXIO); 1254 1255 *(struct disklabel *)data = cs->sc_dkdev.dk_label; 1256 break; 1257 1258 case DIOCGPART: 1259 if ((cs->sc_flags & CCDF_INITED) == 0) 1260 return (ENXIO); 1261 1262 ((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label; 1263 ((struct partinfo *)data)->part = 1264 &cs->sc_dkdev.dk_label.d_partitions[ccdpart(dev)]; 1265 break; 1266 1267 case DIOCWDINFO: 1268 case DIOCSDINFO: 1269 if ((cs->sc_flags & CCDF_INITED) == 0) 1270 return (ENXIO); 1271 1272 if ((flag & FWRITE) == 0) 1273 return (EBADF); 1274 1275 if (error = ccdlock(cs)) 1276 return (error); 1277 1278 cs->sc_flags |= CCDF_LABELLING; 1279 1280 error = setdisklabel(&cs->sc_dkdev.dk_label, 1281 (struct disklabel *)data, 0); 1282 /*, &cs->sc_dkdev.dk_cpulabel); */ 1283 if (error == 0) { 1284 if (cmd == DIOCWDINFO) 1285 error = writedisklabel(CCDLABELDEV(dev), 1286 ccdstrategy, &cs->sc_dkdev.dk_label); 1287 /* 1288 &cs->sc_dkdev.dk_cpulabel); */ 1289 } 1290 1291 cs->sc_flags &= ~CCDF_LABELLING; 1292 1293 ccdunlock(cs); 1294 1295 if (error) 1296 return (error); 1297 break; 1298 1299 case DIOCWLABEL: 1300 if ((cs->sc_flags & CCDF_INITED) == 0) 1301 return (ENXIO); 1302 1303 if ((flag & FWRITE) == 0) 1304 return (EBADF); 1305 if (*(int *)data != 0) 1306 cs->sc_flags |= CCDF_WLABEL; 1307 else 1308 cs->sc_flags &= ~CCDF_WLABEL; 1309 break; 1310 1311 default: 1312 return (ENOTTY); 1313 } 1314 1315 return (0); 1316 } 1317 1318 int 1319 ccdsize(dev) 1320 dev_t dev; 1321 { 1322 struct ccd_softc *cs; 1323 int part, size; 1324 1325 if (ccdopen(dev, 0, S_IFBLK, curproc)) 1326 return (-1); 1327 1328 cs = &ccd_softc[ccdunit(dev)]; 1329 part = ccdpart(dev); 1330 1331 if ((cs->sc_flags & CCDF_INITED) == 0) 1332 return (-1); 1333 1334 if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP) 1335 size = -1; 1336 else 1337 size = cs->sc_dkdev.dk_label.d_partitions[part].p_size; 1338 1339 if (ccdclose(dev, 0, S_IFBLK, curproc)) 1340 return (-1); 1341 1342 return (size); 1343 } 1344 1345 int 1346 ccddump(dev) 1347 dev_t dev; 1348 { 1349 1350 /* Not implemented. */ 1351 return ENXIO; 1352 } 1353 1354 /* 1355 * Lookup the provided name in the filesystem. If the file exists, 1356 * is a valid block device, and isn't being used by anyone else, 1357 * set *vpp to the file's vnode. 1358 */ 1359 static int 1360 ccdlookup(path, p, vpp) 1361 char *path; 1362 struct proc *p; 1363 struct vnode **vpp; /* result */ 1364 { 1365 struct nameidata nd; 1366 struct vnode *vp; 1367 struct vattr va; 1368 int error; 1369 1370 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); 1371 if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 1372 #ifdef DEBUG 1373 if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1374 printf("ccdlookup: vn_open error = %d\n", error); 1375 #endif 1376 return (error); 1377 } 1378 vp = nd.ni_vp; 1379 1380 if (vp->v_usecount > 1) { 1381 VOP_UNLOCK(vp); 1382 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1383 return (EBUSY); 1384 } 1385 1386 if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { 1387 #ifdef DEBUG 1388 if (ccddebug & CCDB_FOLLOW|CCDB_INIT) 1389 printf("ccdlookup: getattr error = %d\n", error); 1390 #endif 1391 VOP_UNLOCK(vp); 1392 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1393 return (error); 1394 } 1395 1396 /* XXX: eventually we should handle VREG, too. */ 1397 if (va.va_type != VBLK) { 1398 VOP_UNLOCK(vp); 1399 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 1400 return (ENOTBLK); 1401 } 1402 1403 #ifdef DEBUG 1404 if (ccddebug & CCDB_VNODE) 1405 vprint("ccdlookup: vnode info", vp); 1406 #endif 1407 1408 VOP_UNLOCK(vp); 1409 *vpp = vp; 1410 return (0); 1411 } 1412 1413 /* 1414 * Read the disklabel from the ccd. If one is not present, fake one 1415 * up. 1416 */ 1417 static void 1418 ccdgetdisklabel(dev) 1419 dev_t dev; 1420 { 1421 int unit = ccdunit(dev); 1422 struct ccd_softc *cs = &ccd_softc[unit]; 1423 char *errstring; 1424 struct disklabel *lp = &cs->sc_dkdev.dk_label; 1425 struct ccdgeom *ccg = &cs->sc_geom; 1426 1427 bzero(lp, sizeof(*lp)); 1428 1429 lp->d_secperunit = cs->sc_size; 1430 lp->d_secsize = ccg->ccg_secsize; 1431 lp->d_nsectors = ccg->ccg_nsectors; 1432 lp->d_ntracks = ccg->ccg_ntracks; 1433 lp->d_ncylinders = ccg->ccg_ncylinders; 1434 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1435 1436 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); 1437 lp->d_type = DTYPE_CCD; 1438 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 1439 lp->d_rpm = 3600; 1440 lp->d_interleave = 1; 1441 lp->d_flags = 0; 1442 1443 lp->d_partitions[RAW_PART].p_offset = 0; 1444 lp->d_partitions[RAW_PART].p_size = cs->sc_size; 1445 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 1446 lp->d_npartitions = RAW_PART + 1; 1447 1448 lp->d_bbsize = BBSIZE; /* XXX */ 1449 lp->d_sbsize = SBSIZE; /* XXX */ 1450 1451 lp->d_magic = DISKMAGIC; 1452 lp->d_magic2 = DISKMAGIC; 1453 lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label); 1454 1455 /* 1456 * Call the generic disklabel extraction routine. 1457 */ 1458 if (errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, 1459 &cs->sc_dkdev.dk_label)) 1460 ccdmakedisklabel(cs); 1461 1462 #ifdef DEBUG 1463 /* It's actually extremely common to have unlabeled ccds. */ 1464 if (ccddebug & CCDB_LABEL) 1465 if (errstring != NULL) 1466 printf("ccd%d: %s\n", unit, errstring); 1467 #endif 1468 } 1469 1470 /* 1471 * Take care of things one might want to take care of in the event 1472 * that a disklabel isn't present. 1473 */ 1474 static void 1475 ccdmakedisklabel(cs) 1476 struct ccd_softc *cs; 1477 { 1478 struct disklabel *lp = &cs->sc_dkdev.dk_label; 1479 1480 /* 1481 * For historical reasons, if there's no disklabel present 1482 * the raw partition must be marked FS_BSDFFS. 1483 */ 1484 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; 1485 1486 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); 1487 } 1488 1489 /* 1490 * Wait interruptibly for an exclusive lock. 1491 * 1492 * XXX 1493 * Several drivers do this; it should be abstracted and made MP-safe. 1494 */ 1495 static int 1496 ccdlock(cs) 1497 struct ccd_softc *cs; 1498 { 1499 int error; 1500 1501 while ((cs->sc_flags & CCDF_LOCKED) != 0) { 1502 cs->sc_flags |= CCDF_WANTED; 1503 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) 1504 return (error); 1505 } 1506 cs->sc_flags |= CCDF_LOCKED; 1507 return (0); 1508 } 1509 1510 /* 1511 * Unlock and wake up any waiters. 1512 */ 1513 static void 1514 ccdunlock(cs) 1515 struct ccd_softc *cs; 1516 { 1517 1518 cs->sc_flags &= ~CCDF_LOCKED; 1519 if ((cs->sc_flags & CCDF_WANTED) != 0) { 1520 cs->sc_flags &= ~CCDF_WANTED; 1521 wakeup(cs); 1522 } 1523 } 1524 1525 #ifdef DEBUG 1526 static void 1527 printiinfo(ii) 1528 struct ccdiinfo *ii; 1529 { 1530 register int ix, i; 1531 1532 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 1533 printf(" itab[%d]: #dk %d sblk %d soff %d", 1534 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 1535 for (i = 0; i < ii->ii_ndisk; i++) 1536 printf(" %d", ii->ii_index[i]); 1537 printf("\n"); 1538 } 1539 } 1540 #endif 1541 1542 #endif /* NCCD > 0 */ 1543 1544 /* Local Variables: */ 1545 /* c-argdecl-indent: 8 */ 1546 /* c-continued-statement-offset: 8 */ 1547 /* c-indent-level: 8 */ 1548 /* End: */ 1549