struct scsi_xfer *xs;
twe_done(sc, idx)	struct twe_softc *sc;	int	idx;{	struct scsi_xfer *xs;	struct twe_ccb *ccb = &sc->sc_ccbs[idx];	struct twe_cmd *cmd = ccb->ccb_cmd;	TWE_DPRINTF(TWE_D_CMD, ("done(%d) ", idx));	xs = ccb->ccb_xs;	if (ccb->ccb_state != TWE_CCB_QUEUED) {		printf("%s: unqueued ccb %d ready\n",		    sc->sc_dev.dv_xname, idx);		return 1;	}	if (xs) {		if (xs->cmd->opcode != PREVENT_ALLOW &&		    xs->cmd->opcode != SYNCHRONIZE_CACHE) {			bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap,			    (xs->flags & SCSI_DATA_IN) ?			    BUS_DMASYNC_POSTREAD :			    BUS_DMASYNC_POSTWRITE);			bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);		}	} else {		switch (cmd->cmd_op) {		case TWE_CMD_GPARAM:		case TWE_CMD_READ:			bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap,			    BUS_DMASYNC_POSTREAD);			bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);			break;		case TWE_CMD_SPARAM:		case TWE_CMD_WRITE:			bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap,			    BUS_DMASYNC_POSTWRITE);			bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);			break;		default:			/* no data */		}	}	if (ccb->ccb_realdata) {		bcopy(ccb->ccb_data, ccb->ccb_realdata, ccb->ccb_length);		uvm_km_free(kmem_map, (vaddr_t)ccb->ccb_data, ccb->ccb_length);		ccb->ccb_data = ccb->ccb_realdata;		ccb->ccb_realdata = NULL;	}	TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link);	twe_put_ccb(ccb);	if (xs) {		xs->resid = 0;		xs->flags |= ITSDONE;		scsi_done(xs);	}	return 0;}