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