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