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