splx(s);
aha_scsi_cmd(xs)	struct scsi_xfer *xs;{	struct scsi_link *sc_link = xs->sc_link;	struct aha_softc *sc = sc_link->adapter_softc;	struct aha_ccb *ccb;	struct aha_scat_gath *sg;	int seg, datalen, flags, mflags;	struct iovec *iovp;	int s;	SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));	/*	 * get a ccb to use. If the transfer	 * is from a buf (possibly from interrupt time)	 * then we can't allow it to sleep	 */	flags = xs->flags;	if (flags & SCSI_NOSLEEP)		mflags = ISADMA_MAP_BOUNCE;	else		mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;	if ((ccb = aha_get_ccb(sc, flags)) == NULL) {		xs->error = XS_DRIVER_STUFFUP;		return TRY_AGAIN_LATER;	}	ccb->xs = xs;	ccb->timeout = xs->timeout;	/*	 * Put all the arguments for the xfer in the ccb	 */	if (flags & SCSI_RESET) {		ccb->opcode = AHA_RESET_CCB;		ccb->scsi_cmd_length = 0;	} else {		/* can't use S/G if zero length */		ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB					   : AHA_INITIATOR_CCB);		bcopy(xs->cmd, &ccb->scsi_cmd,		    ccb->scsi_cmd_length = xs->cmdlen);	}	if (xs->datalen) {		sg = ccb->scat_gath;		seg = 0;#ifdef	TFS		if (flags & SCSI_DATA_UIO) {			iovp = ((struct uio *)xs->data)->uio_iov;			datalen = ((struct uio *)xs->data)->uio_iovcnt;			xs->datalen = 0;			while (datalen && seg < AHA_NSEG) {				ltophys(iovp->iov_base, sg->seg_addr);				ltophys(iovp->iov_len, sg->seg_len);				xs->datalen += iovp->iov_len;				SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)",				    iovp->iov_len, iovp->iov_base));				sg++;				iovp++;				seg++;				datalen--;			}		} else#endif /* TFS */		{			/*			 * Set up the scatter-gather block.			 */			ccb->data_nseg = isadma_map(xs->data, xs->datalen,						    ccb->data_phys, mflags);			for (seg = 0; seg < ccb->data_nseg; seg++) {				ltophys(ccb->data_phys[seg].addr,				       sg[seg].seg_addr);				ltophys(ccb->data_phys[seg].length,				       sg[seg].seg_len);			}		}		/* end of iov/kv decision */		if (ccb->data_nseg == 0) {			printf("%s: aha_scsi_cmd, cannot map\n",			       sc->sc_dev.dv_xname);			goto bad;		} else if (flags & SCSI_DATA_OUT)			isadma_copytobuf(xs->data, xs->datalen,					 ccb->data_nseg, ccb->data_phys);		ltophys((unsigned)((struct aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath,			ccb->data_addr);		ltophys(ccb->data_nseg * sizeof(struct aha_scat_gath),			ccb->data_length);	} else {		/* No data xfer, use non S/G values */		ltophys(0, ccb->data_addr);		ltophys(0, ccb->data_length);	}	ccb->data_out = 0;	ccb->data_in = 0;	ccb->target = sc_link->target;	ccb->lun = sc_link->lun;	ccb->req_sense_length = sizeof(ccb->scsi_sense);	ccb->host_stat = 0x00;	ccb->target_stat = 0x00;	ccb->link_id = 0;	ltophys(0, ccb->link_addr);	s = splbio();	aha_queue_ccb(sc, ccb);	splx(s);	/*	 * Usually return SUCCESSFULLY QUEUED	 */	SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));	if (VOLATILE_XS(xs)) {		while ((ccb->xs->flags & ITSDONE) == 0) {			tsleep(ccb, PRIBIO, "ahawait", 0);		}		splx(s);		if (ccb->data_nseg) {			if (flags & SCSI_DATA_IN)				isadma_copyfrombuf(xs->data, xs->datalen,				    ccb->data_nseg, ccb->data_phys);			isadma_unmap(xs->data, xs->datalen,			    ccb->data_nseg, ccb->data_phys);		}		aha_free_ccb(sc, ccb);		scsi_done(xs);		return COMPLETE;	}	if ((flags & SCSI_POLL) == 0)		return SUCCESSFULLY_QUEUED;	/*	 * If we can't use interrupts, poll on completion	 */	if (aha_poll(sc, xs, ccb->timeout)) {		aha_timeout(ccb);		if (aha_poll(sc, xs, ccb->timeout))			aha_timeout(ccb);	}	return COMPLETE;bad:	xs->error = XS_DRIVER_STUFFUP;	aha_free_ccb(sc, ccb);	return COMPLETE;}