cmd->acc_mbox.amb_nsect = blockcnt; cmd->acc_mbox.amb_lba = blockno;
cmd->acc_mbox.amb_nsect = htole16(blockcnt); cmd->acc_mbox.amb_lba = htole32(blockno);
ami_scsi_cmd(xs)	struct scsi_xfer *xs;{	struct scsi_link *link = xs->sc_link;	struct ami_softc *sc = link->adapter_softc;	struct ami_ccb *ccb;	struct ami_iocmd *cmd;	struct scsi_inquiry_data inq;	struct scsi_sense_data sd;	struct {		struct scsi_mode_header hd;		struct scsi_blk_desc bd;		union scsi_disk_pages dp;	} mpd;	struct scsi_read_cap_data rcd;	u_int8_t target = link->target;	u_int32_t blockno, blockcnt;	struct scsi_rw *rw;	struct scsi_rw_big *rwb;	int error, flags;	ami_lock_t lock;	if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present ||	    link->lun != 0) {		/* XXX should be XS_SENSE and sense filled out */		xs->error = XS_DRIVER_STUFFUP;		xs->flags |= ITSDONE;		scsi_done(xs);		return (COMPLETE);	}	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd "));	error = 0;	xs->error = XS_NOERROR;	switch (xs->cmd->opcode) {	case TEST_UNIT_READY:	case START_STOP:#if 0	case VERIFY:#endif		AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,		    target));		break;	case REQUEST_SENSE:		AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target));		bzero(&sd, sizeof sd);		sd.error_code = 0x70;		sd.segment = 0;		sd.flags = SKEY_NO_SENSE;		*(u_int32_t*)sd.info = htole32(0);		sd.extra_len = 0;		ami_copy_internal_data(xs, &sd, sizeof sd);		break;	case INQUIRY:		AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target));		bzero(&inq, sizeof inq);		inq.device = T_DIRECT;		inq.dev_qual2 = 0;		inq.version = 2;		inq.response_format = 2;		inq.additional_length = 32;		strcpy(inq.vendor, "AMI    ");		sprintf(inq.product, "Host drive  #%02d", target);		strcpy(inq.revision, "   ");		ami_copy_internal_data(xs, &inq, sizeof inq);		break;	case MODE_SENSE:		AMI_DPRINTF(AMI_D_CMD, ("MODE SENSE tgt %d ", target));		bzero(&mpd, sizeof mpd);		switch (((struct scsi_mode_sense *)xs->cmd)->page) {		case 4:			/* scsi_disk.h says this should be 0x16 */			mpd.dp.rigid_geometry.pg_length = 0x16;			mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd +			    mpd.dp.rigid_geometry.pg_length;			mpd.hd.blk_desc_len = sizeof mpd.bd;			mpd.hd.dev_spec = 0;	/* writeprotect ? XXX */			_lto3b(AMI_SECTOR_SIZE, mpd.bd.blklen);			mpd.dp.rigid_geometry.pg_code = 4;			_lto3b(sc->sc_hdr[target].hd_size /			    sc->sc_hdr[target].hd_heads /			    sc->sc_hdr[target].hd_secs,			    mpd.dp.rigid_geometry.ncyl);			mpd.dp.rigid_geometry.nheads =			    sc->sc_hdr[target].hd_heads;			ami_copy_internal_data(xs, (u_int8_t *)&mpd,			    sizeof mpd);			break;		default:			printf("%s: mode sense page %d not simulated\n",			    sc->sc_dev.dv_xname,			    ((struct scsi_mode_sense *)xs->cmd)->page);			xs->error = XS_DRIVER_STUFFUP;		}		break;	case READ_CAPACITY:		AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target));		bzero(&rcd, sizeof rcd);		_lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr);		_lto4b(AMI_SECTOR_SIZE, rcd.length);		ami_copy_internal_data(xs, &rcd, sizeof rcd);		break;	case PREVENT_ALLOW:		AMI_DPRINTF(AMI_D_CMD, ("PREVENT/ALLOW "));		return (COMPLETE);	case SYNCHRONIZE_CACHE:		AMI_DPRINTF(AMI_D_CMD, ("SYNCHRONIZE CACHE "));		error++;	case READ_COMMAND:		if (!error) {			AMI_DPRINTF(AMI_D_CMD, ("READ "));			error++;		}	case READ_BIG:		if (!error) {			AMI_DPRINTF(AMI_D_CMD, ("READ BIG "));			error++;		}	case WRITE_COMMAND:		if (!error) {			AMI_DPRINTF(AMI_D_CMD, ("WRITE "));			error++;		}	case WRITE_BIG:		if (!error) {			AMI_DPRINTF(AMI_D_CMD, ("WRITE BIG "));			error++;		}		lock = AMI_LOCK_AMI(sc);		flags = 0;		if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {			/* A read or write operation. */			if (xs->cmdlen == 6) {				rw = (struct scsi_rw *)xs->cmd;				blockno = _3btol(rw->addr) &				    (SRW_TOPADDR << 16 | 0xffff);				blockcnt = rw->length ? rw->length : 0x100;			} else {				rwb = (struct scsi_rw_big *)xs->cmd;				blockno = _4btol(rwb->addr);				blockcnt = _2btol(rwb->length);				/* TODO: reflect DPO & FUA flags */				if (xs->cmd->opcode == WRITE_BIG &&				    rwb->byte2 & 0x18)					flags = 0;			}			if (blockno >= sc->sc_hdr[target].hd_size ||			    blockno + blockcnt > sc->sc_hdr[target].hd_size) {				AMI_UNLOCK_AMI(sc, lock);				printf("%s: out of bounds %u-%u >= %u\n",				    sc->sc_dev.dv_xname, blockno, blockcnt,				    sc->sc_hdr[target].hd_size);				xs->error = XS_DRIVER_STUFFUP;				break;			}		}		if ((ccb = ami_get_ccb(sc)) == NULL) {			AMI_UNLOCK_AMI(sc, lock);			AMI_DPRINTF(AMI_D_CMD, ("no more ccbs "));			xs->error = XS_DRIVER_STUFFUP;		__asm __volatile(".globl _bpamiccb\n_bpamiccb:");			break;		}		ccb->ccb_xs = xs;		ccb->ccb_ccb1 = NULL;		ccb->ccb_len  = xs->datalen;		ccb->ccb_data = xs->data;		cmd = ccb->ccb_cmd;		cmd->acc_mbox.amb_nsect = blockcnt;		cmd->acc_mbox.amb_lba = blockno;		cmd->acc_mbox.amb_ldn = target;		cmd->acc_mbox.amb_data = 0;		switch (xs->cmd->opcode) {		case SYNCHRONIZE_CACHE:				cmd->acc_cmd = AMI_FLUSH;			/* XXX do other fields matter ? */			break;		case READ_COMMAND: case READ_BIG:			cmd->acc_cmd = AMI_READ;			break;		case WRITE_COMMAND: case WRITE_BIG:			cmd->acc_cmd = AMI_WRITE;			break;		}		if ((error = ami_cmd(ccb, ((xs->flags & SCSI_NOSLEEP)?		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK), xs->flags & SCSI_POLL))) {			AMI_UNLOCK_AMI(sc, lock);			AMI_DPRINTF(AMI_D_CMD, ("failed %p ", xs));		__asm __volatile(".globl _bpamifail\n_bpamifail:");			if (xs->flags & SCSI_POLL) {				xs->error = XS_TIMEOUT;				return (TRY_AGAIN_LATER);			} else {				xs->error = XS_DRIVER_STUFFUP;				break;			}		}		AMI_UNLOCK_AMI(sc, lock);		if (xs->flags & SCSI_POLL)			break;		return (SUCCESSFULLY_QUEUED);	default:		AMI_DPRINTF(AMI_D_CMD, ("unknown opc %d ", xs->cmd->opcode));		xs->error = XS_DRIVER_STUFFUP;	}	xs->flags |= ITSDONE;	scsi_done(xs);	return (xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED);}