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