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