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