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