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