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