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