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