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