cbpp[1] = cbp;
cbp->cb_dep = cbpp[0]; cbpp[0]->cb_dep = cbpp[1] = cbp;
ccdbuffer(cs, bp, bn, addr, bcount, cbpp, old_io)	struct ccd_softc *cs;	struct buf *bp;	daddr_t bn;	caddr_t addr;	long bcount;	struct ccdbuf **cbpp;	int old_io;{	struct ccdcinfo *ci, *ci2 = NULL;	struct ccdbuf *cbp;	daddr_t cbn, cboff, sblk;	int ccdisk, off;	long old_bcount, cnt;	struct ccdiinfo *ii;	struct buf *nbp;#ifdef DEBUG	if (ccddebug & CCDB_IO)		printf("ccdbuffer(%p, %p, %d, %p, %ld)\n", cs, bp, bn, addr,		    bcount);#endif	/*	 * Determine which component bn falls in.	 */	cbn = bn;	cboff = 0;	if (cs->sc_ileave == 0) {		/*		 * Serially concatenated		 */		sblk = 0;		for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];		    cbn >= sblk + ci->ci_size;		    ccdisk++, ci = &cs->sc_cinfo[ccdisk])			sblk += ci->ci_size;		cbn -= sblk;	} else {		/*		 * Interleaved		 */		cboff = cbn % cs->sc_ileave;		cbn /= cs->sc_ileave;		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)			if (ii->ii_startblk > cbn)				break;		ii--;		off = cbn - ii->ii_startblk;		if (ii->ii_ndisk == 1) {			ccdisk = ii->ii_index[0];			cbn = ii->ii_startoff + off;		} else {			if (cs->sc_cflags & CCDF_MIRROR) {				ccdisk =				    ii->ii_index[off % (ii->ii_ndisk / 2)];				cbn = ii->ii_startoff +				    (off / (ii->ii_ndisk / 2));				/* Mirrored data */				ci2 =				    &cs->sc_cinfo[ccdisk + (ii->ii_ndisk / 2)];			} else {				/* Normal case. */				ccdisk = ii->ii_index[off % ii->ii_ndisk];				cbn = ii->ii_startoff + off / ii->ii_ndisk;			}		}		cbn *= cs->sc_ileave;		ci = &cs->sc_cinfo[ccdisk];	}	/* Limit the operation at next component border */	if (cs->sc_ileave == 0)		cnt = dbtob(ci->ci_size - cbn);	else		cnt = dbtob(cs->sc_ileave - cboff);	if (cnt < bcount)		bcount = cnt;	if (old_io || cbpp[ccdisk] == NULL) {		/*		 * Setup new component buffer.		 */		cbp = cbpp[old_io ? 0 : ccdisk] = getccdbuf();		cbp->cb_flags = old_io ? CBF_OLD : 0;		nbp = &cbp->cb_buf;		nbp->b_flags = bp->b_flags | B_CALL;		nbp->b_iodone = ccdiodone;		nbp->b_proc = bp->b_proc;		nbp->b_dev = ci->ci_dev;		/* XXX */		nbp->b_blkno = cbn + cboff;		nbp->b_vp = ci->ci_vp;		nbp->b_bcount = bcount;		LIST_INIT(&nbp->b_dep);		/*		 * context for ccdiodone		 */		cbp->cb_obp = bp;		cbp->cb_unit = cs->sc_unit;		cbp->cb_comp = ccdisk;		/* Deal with the different algorithms */		if (old_io)			nbp->b_data = addr;		else {			do {				nbp->b_data = (caddr_t) uvm_km_valloc(ccdmap,							    bp->b_bcount);				/*				 * XXX Instead of sleeping, we might revert				 * XXX to old I/O policy for this buffer set.				 */				if (nbp->b_data == NULL) {					ccd_need_kvm++;					tsleep(ccdmap, PRIBIO, "ccdbuffer", 0);				}			} while (nbp->b_data == NULL);			cbp->cb_sgcnt = 0;			old_bcount = 0;		}		/*		 * Mirrors have an additional write operation that is nearly		 * identical to the first.		 */		if ((cs->sc_cflags & CCDF_MIRROR) &&		    ((cbp->cb_buf.b_flags & B_READ) == 0)) {			cbp = getccdbuf();			*cbp = *cbpp[0];			cbp->cb_flags = CBF_MIRROR | (old_io ? CBF_OLD : 0);			cbp->cb_buf.b_dev = ci2->ci_dev;	/* XXX */			cbp->cb_buf.b_vp = ci2->ci_vp;			LIST_INIT(&cbp->cb_buf.b_dep);			cbp->cb_comp = ci2 - cs->sc_cinfo;			cbpp[1] = cbp;		}	} else {		/*		 * Continue on an already started component buffer		 */		cbp = cbpp[ccdisk];		nbp = &cbp->cb_buf;		/*		 * Map the new pages at the end of the buffer.		 */		old_bcount = nbp->b_bcount;		nbp->b_bcount += bcount;	}	if (!old_io) {#ifdef DEBUG		if (ccddebug & CCDB_IO)			printf("ccdbuffer: sg %d (%p/%x) off %x\n",			    cbp->cb_sgcnt, addr, bcount, old_bcount);#endif		pagemove(addr, nbp->b_data + old_bcount, round_page(bcount));		nbp->b_bufsize += round_page(bcount);		cbp->cb_sg[cbp->cb_sgcnt].cs_sgaddr = addr;		cbp->cb_sg[cbp->cb_sgcnt].cs_sglen = bcount;		cbp->cb_sgcnt++;	}#ifdef DEBUG	if (ccddebug & CCDB_IO)		printf(" dev %x(u%d): cbp %p bn %d addr %p bcnt %ld\n",		    ci->ci_dev, ci-cs->sc_cinfo, cbp, bp->b_blkno,		    bp->b_data, bp->b_bcount);#endif	return (bcount);}