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