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