1 /* $NetBSD: ccd.c,v 1.8 1995/03/09 02:20:34 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: Utah $Hdr: cd.c 1.6 90/11/28$ 41 * 42 * @(#)cd.c 8.2 (Berkeley) 11/16/93 43 */ 44 45 /* 46 * "Concatenated" disk driver. 47 */ 48 #include "ccd.h" 49 #if NCCD > 0 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/proc.h> 54 #include <sys/errno.h> 55 #include <sys/dkstat.h> 56 #include <sys/buf.h> 57 #include <sys/malloc.h> 58 #include <sys/conf.h> 59 #include <sys/stat.h> 60 #include <sys/ioctl.h> 61 #include <sys/disklabel.h> 62 #include <sys/fcntl.h> 63 64 #include <dev/ccdvar.h> 65 66 #ifdef DEBUG 67 int ccddebug = 0x00; 68 #define CCDB_FOLLOW 0x01 69 #define CCDB_INIT 0x02 70 #define CCDB_IO 0x04 71 #endif 72 73 #define ccdunit(x) DISKUNIT(x) 74 75 struct ccdbuf { 76 struct buf cb_buf; /* new I/O buf */ 77 struct buf *cb_obp; /* ptr. to original I/O buf */ 78 int cb_unit; /* target unit */ 79 int cb_comp; /* target component */ 80 }; 81 82 #define getccdbuf() \ 83 ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) 84 #define putccdbuf(cbp) \ 85 free((caddr_t)(cbp), M_DEVBUF) 86 87 struct ccd_softc { 88 int sc_flags; /* flags */ 89 size_t sc_size; /* size of ccd */ 90 int sc_ileave; /* interleave */ 91 int sc_nccdisks; /* number of components */ 92 struct ccdcinfo sc_cinfo[NCCDISKS]; /* component info */ 93 struct ccdiinfo *sc_itable; /* interleave table */ 94 int sc_usecnt; /* number of requests active */ 95 int sc_dk; /* disk index */ 96 }; 97 98 struct ccdbuf *ccdbuffer __P((struct ccd_softc *cs, struct buf *bp, 99 daddr_t bn, caddr_t addr, long bcount)); 100 char *ccddevtostr __P((dev_t)); 101 void ccdiodone __P((struct ccdbuf *cbp)); 102 103 /* sc_flags */ 104 #define CCDF_ALIVE 0x01 105 #define CCDF_INITED 0x02 106 107 struct ccd_softc *ccd_softc; 108 int numccd; 109 110 /* 111 * Since this is called after auto-configuration of devices, 112 * we can handle the initialization here. 113 * 114 * XXX this will not work if you want to use a ccd as your primary 115 * swap device since swapconf() has been called before now. 116 */ 117 void 118 ccdattach(num) 119 int num; 120 { 121 char *mem; 122 register u_long size; 123 register struct ccddevice *ccd; 124 extern int dkn; 125 126 if (num <= 0) 127 return; 128 size = num * sizeof(struct ccd_softc); 129 mem = malloc(size, M_DEVBUF, M_NOWAIT); 130 if (mem == NULL) { 131 printf("WARNING: no memory for concatonated disks\n"); 132 return; 133 } 134 bzero(mem, size); 135 ccd_softc = (struct ccd_softc *)mem; 136 numccd = num; 137 for (ccd = ccddevice; ccd->ccd_unit >= 0; ccd++) { 138 /* 139 * XXX 140 * Assign disk index first so that init routine 141 * can use it (saves having the driver drag around 142 * the ccddevice pointer just to set up the dk_* 143 * info in the open routine). 144 */ 145 if (dkn < DK_NDRIVE) 146 ccd->ccd_dk = dkn++; 147 else 148 ccd->ccd_dk = -1; 149 if (ccdinit(ccd)) 150 printf("ccd%d configured\n", ccd->ccd_unit); 151 else if (ccd->ccd_dk >= 0) { 152 ccd->ccd_dk = -1; 153 dkn--; 154 } 155 } 156 } 157 158 ccdinit(ccd) 159 struct ccddevice *ccd; 160 { 161 register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; 162 register struct ccdcinfo *ci; 163 register size_t size; 164 register int ix; 165 size_t minsize; 166 dev_t dev; 167 struct bdevsw *bsw; 168 struct partinfo dpart; 169 int error, (*ioctl)(); 170 struct proc *p = curproc; /* XXX */ 171 172 #ifdef DEBUG 173 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) 174 printf("ccdinit: unit %d\n", ccd->ccd_unit); 175 #endif 176 cs->sc_dk = ccd->ccd_dk; 177 cs->sc_size = 0; 178 cs->sc_ileave = ccd->ccd_interleave; 179 cs->sc_nccdisks = 0; 180 /* 181 * Verify that each component piece exists and record 182 * relevant information about it. 183 */ 184 minsize = 0; 185 for (ix = 0; ix < NCCDISKS; ix++) { 186 if ((dev = ccd->ccd_dev[ix]) == NODEV) 187 break; 188 ci = &cs->sc_cinfo[ix]; 189 ci->ci_dev = dev; 190 bsw = &bdevsw[major(dev)]; 191 /* 192 * Open the partition 193 */ 194 if (bsw->d_open && 195 (error = (*bsw->d_open)(dev, 0, S_IFBLK, p))) { 196 printf("ccd%d: component %s open failed, error = %d\n", 197 ccd->ccd_unit, ccddevtostr(dev), error); 198 return(0); 199 } 200 /* 201 * Calculate size (truncated to interleave boundary 202 * if necessary. 203 */ 204 if ((ioctl = bdevsw[major(dev)].d_ioctl) != NULL && 205 (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) 206 if (dpart.part->p_fstype == FS_BSDFFS) 207 size = dpart.part->p_size; 208 else 209 size = 0; 210 else 211 size = 0; 212 213 if (size < 0) 214 size = 0; 215 216 if (cs->sc_ileave > 1) 217 size -= size % cs->sc_ileave; 218 if (size == 0) { 219 printf("ccd%d: not configured (component %s missing)\n", 220 ccd->ccd_unit, ccddevtostr(dev)); 221 return(0); 222 } 223 #ifdef COMPAT_NOLABEL 224 /* 225 * XXX if this is a 'c' partition then we need to mark the 226 * label area writeable since there cannot be a label. 227 */ 228 if ((minor(dev) & 7) == 2 && bsw->d_open) { 229 int i, flag; 230 231 for (i = 0; i < nchrdev; i++) 232 if (cdevsw[i].d_open == bsw->d_open) 233 break; 234 if (i != nchrdev && cdevsw[i].d_ioctl) { 235 flag = 1; 236 (void)(*cdevsw[i].d_ioctl)(dev, DIOCWLABEL, 237 (caddr_t)&flag, FWRITE, p); 238 } 239 } 240 #endif 241 if (minsize == 0 || size < minsize) 242 minsize = size; 243 ci->ci_size = size; 244 cs->sc_size += size; 245 cs->sc_nccdisks++; 246 } 247 /* 248 * If uniform interleave is desired set all sizes to that of 249 * the smallest component. 250 */ 251 if (ccd->ccd_flags & CCDF_UNIFORM) { 252 for (ci = cs->sc_cinfo; 253 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 254 ci->ci_size = minsize; 255 cs->sc_size = cs->sc_nccdisks * minsize; 256 } 257 /* 258 * Construct the interleave table 259 */ 260 if (!ccdinterleave(cs)) 261 return(0); 262 if (ccd->ccd_dk >= 0) 263 dk_wpms[ccd->ccd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 264 printf("ccd%d: %d components ", ccd->ccd_unit, cs->sc_nccdisks); 265 for (ix = 0; ix < cs->sc_nccdisks; ix++) 266 printf("%c%s%c", 267 ix == 0 ? '(' : ' ', 268 ccddevtostr(cs->sc_cinfo[ix].ci_dev), 269 ix == cs->sc_nccdisks - 1 ? ')' : ','); 270 printf(", %d blocks ", cs->sc_size); 271 if (cs->sc_ileave) 272 printf("interleaved at %d blocks\n", cs->sc_ileave); 273 else 274 printf("concatenated\n"); 275 cs->sc_flags = CCDF_ALIVE | CCDF_INITED; 276 return(1); 277 } 278 279 /* 280 * XXX not really ccd specific. 281 * Could be called something like bdevtostr in machine/conf.c. 282 */ 283 char * 284 ccddevtostr(dev) 285 dev_t dev; 286 { 287 static char dbuf[5]; 288 289 switch (major(dev)) { 290 #ifdef hp300 291 case 2: 292 dbuf[0] = 'r'; dbuf[1] = 'd'; 293 break; 294 case 4: 295 dbuf[0] = 's'; dbuf[1] = 'd'; 296 break; 297 case 5: 298 dbuf[0] = 'c'; dbuf[1] = 'd'; 299 break; 300 case 6: 301 dbuf[0] = 'v'; dbuf[1] = 'n'; 302 break; 303 #endif 304 #ifdef i386 305 case 0: 306 dbuf[0] = 'w'; dbuf[1] = 'd'; 307 break; 308 case 2: 309 dbuf[0] = 'f'; dbuf[1] = 'd'; 310 break; 311 case 4: 312 dbuf[0] = 's'; dbuf[1] = 'd'; 313 break; 314 case 14: 315 dbuf[0] = 'v'; dbuf[1] = 'n'; 316 break; 317 #endif 318 default: 319 dbuf[0] = dbuf[1] = '?'; 320 break; 321 } 322 dbuf[2] = (minor(dev) >> 3) + '0'; 323 dbuf[3] = (minor(dev) & 7) + 'a'; 324 dbuf[4] = '\0'; 325 return (dbuf); 326 } 327 328 ccdinterleave(cs) 329 register struct ccd_softc *cs; 330 { 331 register struct ccdcinfo *ci, *smallci; 332 register struct ccdiinfo *ii; 333 register daddr_t bn, lbn; 334 register int ix; 335 u_long size; 336 337 #ifdef DEBUG 338 if (ccddebug & CCDB_INIT) 339 printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); 340 #endif 341 /* 342 * Allocate an interleave table. 343 * Chances are this is too big, but we don't care. 344 */ 345 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); 346 cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 347 bzero((caddr_t)cs->sc_itable, size); 348 /* 349 * Trivial case: no interleave (actually interleave of disk size). 350 * Each table entry represent a single component in its entirety. 351 */ 352 if (cs->sc_ileave == 0) { 353 bn = 0; 354 ii = cs->sc_itable; 355 for (ix = 0; ix < cs->sc_nccdisks; ix++) { 356 ii->ii_ndisk = 1; 357 ii->ii_startblk = bn; 358 ii->ii_startoff = 0; 359 ii->ii_index[0] = ix; 360 bn += cs->sc_cinfo[ix].ci_size; 361 ii++; 362 } 363 ii->ii_ndisk = 0; 364 #ifdef DEBUG 365 if (ccddebug & CCDB_INIT) 366 printiinfo(cs->sc_itable); 367 #endif 368 return(1); 369 } 370 /* 371 * The following isn't fast or pretty; it doesn't have to be. 372 */ 373 size = 0; 374 bn = lbn = 0; 375 for (ii = cs->sc_itable; ; ii++) { 376 /* 377 * Locate the smallest of the remaining components 378 */ 379 smallci = NULL; 380 for (ci = cs->sc_cinfo; 381 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 382 if (ci->ci_size > size && 383 (smallci == NULL || 384 ci->ci_size < smallci->ci_size)) 385 smallci = ci; 386 /* 387 * Nobody left, all done 388 */ 389 if (smallci == NULL) { 390 ii->ii_ndisk = 0; 391 break; 392 } 393 /* 394 * Record starting logical block and component offset 395 */ 396 ii->ii_startblk = bn / cs->sc_ileave; 397 ii->ii_startoff = lbn; 398 /* 399 * Determine how many disks take part in this interleave 400 * and record their indices. 401 */ 402 ix = 0; 403 for (ci = cs->sc_cinfo; 404 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) 405 if (ci->ci_size >= smallci->ci_size) 406 ii->ii_index[ix++] = ci - cs->sc_cinfo; 407 ii->ii_ndisk = ix; 408 bn += ix * (smallci->ci_size - size); 409 lbn = smallci->ci_size / cs->sc_ileave; 410 size = smallci->ci_size; 411 } 412 #ifdef DEBUG 413 if (ccddebug & CCDB_INIT) 414 printiinfo(cs->sc_itable); 415 #endif 416 return(1); 417 } 418 419 #ifdef DEBUG 420 printiinfo(ii) 421 struct ccdiinfo *ii; 422 { 423 register int ix, i; 424 425 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 426 printf(" itab[%d]: #dk %d sblk %d soff %d", 427 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 428 for (i = 0; i < ii->ii_ndisk; i++) 429 printf(" %d", ii->ii_index[i]); 430 printf("\n"); 431 } 432 } 433 #endif 434 435 ccdopen(dev, flags) 436 dev_t dev; 437 { 438 int unit = ccdunit(dev); 439 register struct ccd_softc *cs = &ccd_softc[unit]; 440 441 #ifdef DEBUG 442 if (ccddebug & CCDB_FOLLOW) 443 printf("ccdopen(%x, %x)\n", dev, flags); 444 #endif 445 if (unit >= numccd || (cs->sc_flags & CCDF_ALIVE) == 0) 446 return(ENXIO); 447 return(0); 448 } 449 450 ccdclose(dev, flags) 451 dev_t dev; 452 int flags; 453 { 454 #ifdef DEBUG 455 if (ccddebug & CCDB_FOLLOW) 456 printf("ccdclose(%x, %x)\n", dev, flags); 457 #endif 458 return (0); 459 } 460 461 ccdstrategy(bp) 462 register struct buf *bp; 463 { 464 register int unit = ccdunit(bp->b_dev); 465 register struct ccd_softc *cs = &ccd_softc[unit]; 466 register daddr_t bn; 467 register int sz, s; 468 469 #ifdef DEBUG 470 if (ccddebug & CCDB_FOLLOW) 471 printf("ccdstrategy(%x): unit %d\n", bp, unit); 472 #endif 473 if ((cs->sc_flags & CCDF_INITED) == 0) { 474 bp->b_error = ENXIO; 475 bp->b_flags |= B_ERROR; 476 goto done; 477 } 478 bn = bp->b_blkno; 479 sz = howmany(bp->b_bcount, DEV_BSIZE); 480 if (bn < 0 || bn + sz > cs->sc_size) { 481 sz = cs->sc_size - bn; 482 if (sz == 0) { 483 bp->b_resid = bp->b_bcount; 484 goto done; 485 } 486 if (sz < 0) { 487 bp->b_error = EINVAL; 488 bp->b_flags |= B_ERROR; 489 goto done; 490 } 491 bp->b_bcount = dbtob(sz); 492 } 493 bp->b_resid = bp->b_bcount; 494 /* 495 * "Start" the unit. 496 */ 497 s = splbio(); 498 ccdstart(cs, bp); 499 splx(s); 500 return; 501 done: 502 biodone(bp); 503 } 504 505 ccdstart(cs, bp) 506 register struct ccd_softc *cs; 507 register struct buf *bp; 508 { 509 register long bcount, rcount; 510 struct ccdbuf *cbp; 511 caddr_t addr; 512 daddr_t bn; 513 514 #ifdef DEBUG 515 if (ccddebug & CCDB_FOLLOW) 516 printf("ccdstart(%x, %x)\n", cs, bp); 517 #endif 518 /* 519 * Instumentation (not real meaningful) 520 */ 521 cs->sc_usecnt++; 522 if (cs->sc_dk >= 0) { 523 dk_busy |= 1 << cs->sc_dk; 524 dk_xfer[cs->sc_dk]++; 525 dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 526 } 527 /* 528 * Allocate component buffers and fire off the requests 529 */ 530 bn = bp->b_blkno; 531 addr = bp->b_data; 532 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 533 cbp = ccdbuffer(cs, bp, bn, addr, bcount); 534 rcount = cbp->cb_buf.b_bcount; 535 (*bdevsw[major(cbp->cb_buf.b_dev)].d_strategy)(&cbp->cb_buf); 536 bn += btodb(rcount); 537 addr += rcount; 538 } 539 } 540 541 /* 542 * Build a component buffer header. 543 */ 544 struct ccdbuf * 545 ccdbuffer(cs, bp, bn, addr, bcount) 546 register struct ccd_softc *cs; 547 struct buf *bp; 548 daddr_t bn; 549 caddr_t addr; 550 long bcount; 551 { 552 register struct ccdcinfo *ci; 553 register struct ccdbuf *cbp; 554 register daddr_t cbn, cboff; 555 556 #ifdef DEBUG 557 if (ccddebug & CCDB_IO) 558 printf("ccdbuffer(%x, %x, %d, %x, %d)\n", 559 cs, bp, bn, addr, bcount); 560 #endif 561 /* 562 * Determine which component bn falls in. 563 */ 564 cbn = bn; 565 cboff = 0; 566 /* 567 * Serially concatenated 568 */ 569 if (cs->sc_ileave == 0) { 570 register daddr_t sblk; 571 572 sblk = 0; 573 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 574 sblk += ci->ci_size; 575 cbn -= sblk; 576 } 577 /* 578 * Interleaved 579 */ 580 else { 581 register struct ccdiinfo *ii; 582 int ccdisk, off; 583 584 cboff = cbn % cs->sc_ileave; 585 cbn /= cs->sc_ileave; 586 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 587 if (ii->ii_startblk > cbn) 588 break; 589 ii--; 590 off = cbn - ii->ii_startblk; 591 if (ii->ii_ndisk == 1) { 592 ccdisk = ii->ii_index[0]; 593 cbn = ii->ii_startoff + off; 594 } else { 595 ccdisk = ii->ii_index[off % ii->ii_ndisk]; 596 cbn = ii->ii_startoff + off / ii->ii_ndisk; 597 } 598 cbn *= cs->sc_ileave; 599 ci = &cs->sc_cinfo[ccdisk]; 600 } 601 /* 602 * Fill in the component buf structure. 603 */ 604 cbp = getccdbuf(); 605 cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 606 cbp->cb_buf.b_iodone = (void (*)())ccdiodone; 607 cbp->cb_buf.b_proc = bp->b_proc; 608 cbp->cb_buf.b_dev = ci->ci_dev; 609 cbp->cb_buf.b_blkno = cbn + cboff; 610 cbp->cb_buf.b_data = addr; 611 cbp->cb_buf.b_vp = 0; 612 if (cs->sc_ileave == 0) 613 cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn); 614 else 615 cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff); 616 if (cbp->cb_buf.b_bcount > bcount) 617 cbp->cb_buf.b_bcount = bcount; 618 619 /* 620 * context for ccdiodone 621 */ 622 cbp->cb_obp = bp; 623 cbp->cb_unit = cs - ccd_softc; 624 cbp->cb_comp = ci - cs->sc_cinfo; 625 626 #ifdef DEBUG 627 if (ccddebug & CCDB_IO) 628 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 629 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, 630 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); 631 #endif 632 return (cbp); 633 } 634 635 ccdintr(cs, bp) 636 register struct ccd_softc *cs; 637 register struct buf *bp; 638 { 639 640 #ifdef DEBUG 641 if (ccddebug & CCDB_FOLLOW) 642 printf("ccdintr(%x, %x)\n", cs, bp); 643 #endif 644 /* 645 * Request is done for better or worse, wakeup the top half. 646 */ 647 if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0) 648 dk_busy &= ~(1 << cs->sc_dk); 649 if (bp->b_flags & B_ERROR) 650 bp->b_resid = bp->b_bcount; 651 biodone(bp); 652 } 653 654 /* 655 * Called by biodone at interrupt time. 656 * Mark the component as done and if all components are done, 657 * take a ccd interrupt. 658 */ 659 void 660 ccdiodone(cbp) 661 register struct ccdbuf *cbp; 662 { 663 register struct buf *bp = cbp->cb_obp; 664 register int unit = cbp->cb_unit; 665 int count, s; 666 667 s = splbio(); 668 #ifdef DEBUG 669 if (ccddebug & CCDB_FOLLOW) 670 printf("ccdiodone(%x)\n", cbp); 671 if (ccddebug & CCDB_IO) { 672 printf("ccdiodone: bp %x bcount %d resid %d\n", 673 bp, bp->b_bcount, bp->b_resid); 674 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 675 cbp->cb_buf.b_dev, cbp->cb_comp, cbp, 676 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 677 cbp->cb_buf.b_bcount); 678 } 679 #endif 680 681 if (cbp->cb_buf.b_flags & B_ERROR) { 682 bp->b_flags |= B_ERROR; 683 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO; 684 #ifdef DEBUG 685 printf("ccd%d: error %d on component %d\n", 686 unit, bp->b_error, cbp->cb_comp); 687 #endif 688 } 689 count = cbp->cb_buf.b_bcount; 690 putccdbuf(cbp); 691 692 /* 693 * If all done, "interrupt". 694 */ 695 bp->b_resid -= count; 696 if (bp->b_resid < 0) 697 panic("ccdiodone: count"); 698 if (bp->b_resid == 0) 699 ccdintr(&ccd_softc[unit], bp); 700 splx(s); 701 } 702 703 ccdread(dev, uio) 704 dev_t dev; 705 struct uio *uio; 706 { 707 register int unit = ccdunit(dev); 708 709 #ifdef DEBUG 710 if (ccddebug & CCDB_FOLLOW) 711 printf("ccdread(%x, %x)\n", dev, uio); 712 #endif 713 return(physio(ccdstrategy, NULL, dev, B_READ, minphys, uio)); 714 } 715 716 ccdwrite(dev, uio) 717 dev_t dev; 718 struct uio *uio; 719 { 720 register int unit = ccdunit(dev); 721 722 #ifdef DEBUG 723 if (ccddebug & CCDB_FOLLOW) 724 printf("ccdwrite(%x, %x)\n", dev, uio); 725 #endif 726 return(physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio)); 727 } 728 729 ccdioctl(dev, cmd, data, flag) 730 dev_t dev; 731 u_long cmd; 732 caddr_t data; 733 int flag; 734 { 735 return(EINVAL); 736 } 737 738 ccdsize(dev) 739 dev_t dev; 740 { 741 int unit = ccdunit(dev); 742 register struct ccd_softc *cs = &ccd_softc[unit]; 743 744 if (unit >= numccd || (cs->sc_flags & CCDF_INITED) == 0) 745 return(-1); 746 return(cs->sc_size); 747 } 748 749 ccddump(dev) 750 { 751 return(ENXIO); 752 } 753 #endif 754