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