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