/*
 *      O.S   : FreeBSD CAM
 *	FILE NAME  : trm.c					      
 *	     BY    : C.L. Huang 	(ching@tekram.com.tw)
 *                   Erich Chen     (erich@tekram.com.tw)
 *      Description: Device Driver for Tekram SCSI adapters
 *                   DC395U/UW/F ,DC315/U(TRM-S1040)
 *                   DC395U2D/U2W(TRM-S2080)
 *                   PCI SCSI Bus Master Host Adapter	
 *                   (SCSI chip set used Tekram ASIC TRM-S1040,TRM-S2080)
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.2.0/sys/dev/trm/trm.c 251874 2013-06-18 00:36:53Z scottl $");

/*
 *	HISTORY:					
 *						
 *	REV#	DATE	NAME    	DESCRIPTION	
 *  1.05   05/01/1999  ERICH CHEN  First released for 3.x.x (CAM)
 *  1.06   07/29/1999  ERICH CHEN  Modify for NEW PCI
 *  1.07   12/12/1999  ERICH CHEN  Modify for 3.3.x ,DCB no free
 *  1.08   06/12/2000  ERICH CHEN  Modify for 4.x.x 
 *  1.09   11/03/2000  ERICH CHEN  Modify for 4.1.R ,new sim
 *  1.10   10/10/2001  Oscar Feng  Fixed CAM rescan hang up bug.	
 *  1.11   10/13/2001  Oscar Feng  Fixed wrong Async speed display bug.	
 */

/*-
 * (C)Copyright 1995-2001 Tekram Technology Co.,Ltd.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/*
 * Imported into FreeBSD source repository, and updated to compile under  
 * FreeBSD-3.0-DEVELOPMENT, by Stefan Esser <se@FreeBSD.Org>, 1996-12-17  
 */

/*
 * Updated to compile under FreeBSD 5.0-CURRENT by Olivier Houchard
 * <doginou@ci0.org>, 2002-03-04
 */

#include <sys/param.h>

#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#if __FreeBSD_version >= 500000
#include <sys/bio.h>
#endif
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>

#include <vm/vm.h>
#include <vm/pmap.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>

#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_debug.h>

#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_message.h>

#include <dev/trm/trm.h>

#define trm_reg_read8(reg)	bus_space_read_1(pACB->tag, pACB->bsh, reg)
#define trm_reg_read16(reg)	bus_space_read_2(pACB->tag, pACB->bsh, reg)
#define trm_reg_read32(reg)	bus_space_read_4(pACB->tag, pACB->bsh, reg)
#define trm_reg_write8(value,reg)	bus_space_write_1(pACB->tag, pACB->bsh,\
		reg, value)
#define trm_reg_write16(value,reg)	bus_space_write_2(pACB->tag, pACB->bsh,\
		reg, value)
#define trm_reg_write32(value,reg)	bus_space_write_4(pACB->tag, pACB->bsh,\
		reg, value)

#define PCI_Vendor_ID_TEKRAM	0x1DE1
#define PCI_Device_ID_TRM_S1040	0x0391
#define PCI_DEVICEID_TRMS1040	0x03911DE1
#define PCI_DEVICEID_TRMS2080   0x03921DE1

#ifdef trm_DEBUG1
#define TRM_DPRINTF(fmt, arg...) printf("trm: " fmt, ##arg)
#else
#define TRM_DPRINTF(fmt, arg...) {}
#endif /* TRM_DEBUG */

static void	trm_check_eeprom(PNVRAMTYPE pEEpromBuf,PACB pACB);
static void	NVRAM_trm_read_all(PNVRAMTYPE pEEpromBuf,PACB pACB);
static u_int8_t	NVRAM_trm_get_data(PACB pACB, u_int8_t bAddr);
static void	NVRAM_trm_write_all(PNVRAMTYPE pEEpromBuf,PACB pACB);
static void	NVRAM_trm_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData);
static void	NVRAM_trm_write_cmd(PACB pACB, u_int8_t bCmd, u_int8_t bAddr);
static void	NVRAM_trm_wait_30us(PACB pACB);

static void	trm_Interrupt(void *vpACB);
static void	trm_DataOutPhase0(PACB pACB, PSRB pSRB, 
					 u_int16_t * pscsi_status);
static void	trm_DataInPhase0(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_CommandPhase0(PACB pACB, PSRB pSRB, 
					 u_int16_t * pscsi_status);
static void	trm_StatusPhase0(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_MsgOutPhase0(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_MsgInPhase0(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_DataOutPhase1(PACB pACB, PSRB pSRB, 
					 u_int16_t * pscsi_status);
static void	trm_DataInPhase1(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_CommandPhase1(PACB pACB, PSRB pSRB, 
					 u_int16_t * pscsi_status);
static void	trm_StatusPhase1(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_MsgOutPhase1(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_MsgInPhase1(PACB pACB, PSRB pSRB, 
					u_int16_t * pscsi_status);
static void	trm_Nop0(PACB pACB, PSRB pSRB, u_int16_t * pscsi_status);
static void	trm_Nop1(PACB pACB, PSRB pSRB, u_int16_t * pscsi_status);
static void	trm_SetXferRate(PACB pACB, PSRB pSRB,PDCB pDCB);
static void	trm_DataIO_transfer(PACB pACB, PSRB pSRB, u_int16_t ioDir);
static void	trm_Disconnect(PACB pACB);
static void	trm_Reselect(PACB pACB);
static void	trm_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB);
static void	trm_DoingSRB_Done(PACB pACB);
static void	trm_ScsiRstDetect(PACB pACB);
static void	trm_ResetSCSIBus(PACB pACB);
static void	trm_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB);
static void	trm_EnableMsgOutAbort2(PACB pACB, PSRB pSRB);
static void	trm_EnableMsgOutAbort1(PACB pACB, PSRB pSRB);
static void	trm_SendSRB(PACB pACB, PSRB pSRB);
static int	trm_probe(device_t tag);
static int	trm_attach(device_t tag);
static void	trm_reset(PACB pACB);

static u_int16_t	trm_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB);

static int	trm_initAdapter(PACB pACB, u_int16_t unit); 
static void	trm_initDCB(PACB pACB, PDCB pDCB, u_int16_t unit, 
    					u_int32_t i, u_int32_t j);
static int	trm_initSRB(PACB pACB);
static void	trm_initACB(PACB pACB, u_int8_t adaptType, u_int16_t unit);
/* CAM SIM entry points */
#define ccb_trmsrb_ptr spriv_ptr0
#define ccb_trmacb_ptr spriv_ptr1
static void	trm_action(struct cam_sim *psim, union ccb *pccb);
static void	trm_poll(struct cam_sim *psim);


static void * trm_SCSI_phase0[] = {
	trm_DataOutPhase0,    /* phase:0 */
	trm_DataInPhase0,     /* phase:1 */
	trm_CommandPhase0,    /* phase:2 */
	trm_StatusPhase0,     /* phase:3 */
	trm_Nop0,             /* phase:4 */
	trm_Nop1,             /* phase:5 */
	trm_MsgOutPhase0,     /* phase:6 */
	trm_MsgInPhase0,      /* phase:7 */
};

/*
 *
 *          stateV = (void *) trm_SCSI_phase1[phase]
 *
 */
static void * trm_SCSI_phase1[] = {
	trm_DataOutPhase1,    /* phase:0 */
	trm_DataInPhase1,     /* phase:1 */
	trm_CommandPhase1,    /* phase:2 */
	trm_StatusPhase1,     /* phase:3 */
	trm_Nop0,             /* phase:4 */
	trm_Nop1,             /* phase:5 */
	trm_MsgOutPhase1,     /* phase:6 */
	trm_MsgInPhase1,      /* phase:7 */
};


NVRAMTYPE trm_eepromBuf[TRM_MAX_ADAPTER_NUM];
/*
 *Fast20:  000	 50ns, 20.0 Mbytes/s
 *	       001	 75ns, 13.3 Mbytes/s
 *	       010	100ns, 10.0 Mbytes/s
 *	       011	125ns,  8.0 Mbytes/s
 *	       100	150ns,  6.6 Mbytes/s
 *	       101	175ns,  5.7 Mbytes/s
 *	       110	200ns,  5.0 Mbytes/s
 *	       111	250ns,  4.0 Mbytes/s
 *
 *Fast40:  000	 25ns, 40.0 Mbytes/s
 *	       001	 50ns, 20.0 Mbytes/s
 *	       010	 75ns, 13.3 Mbytes/s
 *	       011	100ns, 10.0 Mbytes/s
 *	       100	125ns,  8.0 Mbytes/s
 *	       101	150ns,  6.6 Mbytes/s
 *	       110	175ns,  5.7 Mbytes/s
 *	       111	200ns,  5.0 Mbytes/s
 */
                                             /* real period: */
u_int8_t dc395x_clock_period[] = {
	12,/*  48  ns 20   MB/sec */
	18,/*  72  ns 13.3 MB/sec */
	25,/* 100  ns 10.0 MB/sec */
	31,/* 124  ns  8.0 MB/sec */
	37,/* 148  ns  6.6 MB/sec */
	43,/* 172  ns  5.7 MB/sec */
	50,/* 200  ns  5.0 MB/sec */
	62 /* 248  ns  4.0 MB/sec */
};

u_int8_t dc395u2x_clock_period[]={
	10,/*  25  ns 40.0 MB/sec */
	12,/*  48  ns 20.0 MB/sec */
	18,/*  72  ns 13.3 MB/sec */
	25,/* 100  ns 10.0 MB/sec */
	31,/* 124  ns  8.0 MB/sec */
	37,/* 148  ns  6.6 MB/sec */
	43,/* 172  ns  5.7 MB/sec */
	50,/* 200  ns  5.0 MB/sec */
};

#define  dc395x_tinfo_period           dc395x_clock_period
#define  dc395u2x_tinfo_period         dc395u2x_clock_period

static PSRB
trm_GetSRB(PACB pACB)
{
	int	intflag;
	PSRB	pSRB;

	intflag = splcam();
    	pSRB = pACB->pFreeSRB;
	if (pSRB) {
		pACB->pFreeSRB = pSRB->pNextSRB;
		pSRB->pNextSRB = NULL;
	}
	splx(intflag);
    	return (pSRB);
}

static void
trm_RewaitSRB0(PDCB pDCB, PSRB pSRB)
{
	PSRB	psrb1;
	int	intflag;

	intflag = splcam();
    	if ((psrb1 = pDCB->pWaitingSRB)) {
		pSRB->pNextSRB = psrb1;
		pDCB->pWaitingSRB = pSRB;
	} else {
	  	pSRB->pNextSRB = NULL;
		pDCB->pWaitingSRB = pSRB;
		pDCB->pWaitingLastSRB = pSRB;
	}
	splx(intflag);
}

static void
trm_RewaitSRB(PDCB pDCB, PSRB pSRB)
{
	PSRB	psrb1;
	int	intflag;

	intflag = splcam();
    	pDCB->GoingSRBCnt--;
	psrb1 = pDCB->pGoingSRB;
	if (pSRB == psrb1)
		/*
		 * if this SRB is GoingSRB
		 * remove this SRB from GoingSRB Q
		 */
		pDCB->pGoingSRB = psrb1->pNextSRB;
	else {
		/*
		 * if this SRB is not current GoingSRB
		 * remove this SRB from GoingSRB Q
		 */
		while (pSRB != psrb1->pNextSRB)
			psrb1 = psrb1->pNextSRB;
		psrb1->pNextSRB = pSRB->pNextSRB;
		if (pSRB == pDCB->pGoingLastSRB)
			pDCB->pGoingLastSRB = psrb1;
	}
	if ((psrb1 = pDCB->pWaitingSRB)) {
		/*
		 * if WaitingSRB Q is not NULL
		 * Q back this SRB into WaitingSRB
		 */

		pSRB->pNextSRB = psrb1;
		pDCB->pWaitingSRB = pSRB;
	} else {
		pSRB->pNextSRB = NULL;
		pDCB->pWaitingSRB = pSRB;
		pDCB->pWaitingLastSRB = pSRB;
	}
	splx(intflag);
}

static void
trm_DoWaitingSRB(PACB pACB)
{
	int	intflag;
	PDCB	ptr, ptr1;
	PSRB	pSRB;

	intflag = splcam();
    	if (!(pACB->pActiveDCB) && 
	    !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV))) {
		ptr = pACB->pDCBRunRobin;
		if (!ptr) {
			ptr = pACB->pLinkDCB;
			pACB->pDCBRunRobin = ptr;
		}
		ptr1 = ptr;
		for (;ptr1 ;) {
			pACB->pDCBRunRobin = ptr1->pNextDCB;
			if (!(ptr1->MaxActiveCommandCnt > ptr1->GoingSRBCnt) 
			    || !(pSRB = ptr1->pWaitingSRB)) {
				if (pACB->pDCBRunRobin == ptr)
					break;
				ptr1 = ptr1->pNextDCB;
			} else {
				if (!trm_StartSCSI(pACB, ptr1, pSRB)) {
				/* 
				 * If trm_StartSCSI return 0 :
				 * current interrupt status is interrupt enable 
				 * It's said that SCSI processor is unoccupied 
				 */
					ptr1->GoingSRBCnt++;
					if (ptr1->pWaitingLastSRB == pSRB) {
						ptr1->pWaitingSRB = NULL;
						ptr1->pWaitingLastSRB = NULL;
					} else
						ptr1->pWaitingSRB = pSRB->pNextSRB;
					pSRB->pNextSRB = NULL;
					if (ptr1->pGoingSRB) 
						ptr1->pGoingLastSRB->pNextSRB = pSRB;
					else
						ptr1->pGoingSRB = pSRB;
					ptr1->pGoingLastSRB = pSRB;
				}
				break;
			}
		}
	}
	splx(intflag);
	return;
}

static void
trm_SRBwaiting(PDCB pDCB, PSRB pSRB)
{
  
	if (pDCB->pWaitingSRB) {
		pDCB->pWaitingLastSRB->pNextSRB = pSRB;
		pDCB->pWaitingLastSRB = pSRB;
		pSRB->pNextSRB = NULL;
	} else {
		pDCB->pWaitingSRB = pSRB;
		pDCB->pWaitingLastSRB = pSRB;
	}
}

static u_int32_t
trm_get_sense_bufaddr(PACB pACB, PSRB pSRB)
{
	int offset;

	offset = pSRB->TagNumber;
	return (pACB->sense_busaddr + 
	    (offset * sizeof(struct scsi_sense_data)));
}

static struct scsi_sense_data *
trm_get_sense_buf(PACB pACB, PSRB pSRB)
{
	int offset;

	offset = pSRB->TagNumber;
	return (&pACB->sense_buffers[offset]);
}
static void
trm_ExecuteSRB(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{
	int		flags;
	PACB		pACB;
	PSRB		pSRB;
	union ccb	*ccb;
	u_long		totalxferlen=0;

	flags = splcam();
	pSRB = (PSRB)arg;
	ccb = pSRB->pccb;
	pACB = (PACB)ccb->ccb_h.ccb_trmacb_ptr;
	TRM_DPRINTF("trm_ExecuteSRB..........\n");        
	if (nseg != 0) {
		PSEG			psg;
		bus_dma_segment_t	*end_seg;
		int			op;

		/* Copy the segments into our SG list */
		end_seg = dm_segs + nseg;
		psg = pSRB->pSRBSGL;
		while (dm_segs < end_seg) {
			psg->address = dm_segs->ds_addr;
			psg->length = (u_long)dm_segs->ds_len;
			totalxferlen += dm_segs->ds_len;
			psg++;
			dm_segs++;
		}
		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
			op = BUS_DMASYNC_PREREAD;
		} else {
			op = BUS_DMASYNC_PREWRITE;
		}
		bus_dmamap_sync(pACB->buffer_dmat, pSRB->dmamap, op);
	}
	pSRB->RetryCnt = 0;
	pSRB->SRBTotalXferLength = totalxferlen;
	pSRB->SRBSGCount = nseg;
	pSRB->SRBSGIndex = 0;
	pSRB->AdaptStatus = 0;
	pSRB->TargetStatus = 0;
	pSRB->MsgCnt = 0;
	pSRB->SRBStatus = 0;
	pSRB->SRBFlag = 0;
	pSRB->SRBState = 0;
	pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */

	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
		if (nseg != 0)
			bus_dmamap_unload(pACB->buffer_dmat, pSRB->dmamap);
		pSRB->pNextSRB = pACB->pFreeSRB;
		pACB->pFreeSRB = pSRB;
		xpt_done(ccb);
		splx(flags);
		return;
	}
	ccb->ccb_h.status |= CAM_SIM_QUEUED;
#if 0
	/* XXX Need a timeout handler */
	ccb->ccb_h.timeout_ch = timeout(trmtimeout, (caddr_t)srb, (ccb->ccb_h.timeout * hz) / 1000);
#endif
	trm_SendSRB(pACB, pSRB);
	splx(flags);
	return;
}

static void
trm_SendSRB(PACB pACB, PSRB pSRB)
{
	PDCB	pDCB;

	pDCB = pSRB->pSRBDCB;
	if (!(pDCB->MaxActiveCommandCnt > pDCB->GoingSRBCnt) || (pACB->pActiveDCB)
	    || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV))) {
		TRM_DPRINTF("pDCB->MaxCommand=%d \n",pDCB->MaxActiveCommandCnt);        
		TRM_DPRINTF("pDCB->GoingSRBCnt=%d \n",pDCB->GoingSRBCnt);
		TRM_DPRINTF("pACB->pActiveDCB=%8x \n",(u_int)pACB->pActiveDCB);
		TRM_DPRINTF("pACB->ACBFlag=%x \n",pACB->ACBFlag);
	    	trm_SRBwaiting(pDCB, pSRB);
		goto SND_EXIT;
	}

	if (pDCB->pWaitingSRB) {
		trm_SRBwaiting(pDCB, pSRB);
		pSRB = pDCB->pWaitingSRB;
		pDCB->pWaitingSRB = pSRB->pNextSRB;
		pSRB->pNextSRB = NULL;
	}

	if (!trm_StartSCSI(pACB, pDCB, pSRB)) { 
	/* 
	 * If trm_StartSCSI return 0 :
	 * current interrupt status is interrupt enable 
	 * It's said that SCSI processor is unoccupied 
	 */
		pDCB->GoingSRBCnt++; /* stack waiting SRB*/
		if (pDCB->pGoingSRB) {
			pDCB->pGoingLastSRB->pNextSRB = pSRB;
			pDCB->pGoingLastSRB = pSRB;
		} else {
			pDCB->pGoingSRB = pSRB;
			pDCB->pGoingLastSRB = pSRB;
		}
	} else {
	/* 
	 * If trm_StartSCSI return 1 :
	 * current interrupt status is interrupt disreenable 
	 * It's said that SCSI processor has more one SRB need to do
	 */
		trm_RewaitSRB0(pDCB, pSRB);
	}
SND_EXIT:
	return;
}


static void
trm_action(struct cam_sim *psim, union ccb *pccb) 
{
	PACB	pACB;
	int	actionflags;
	u_int	target_id,target_lun;

	CAM_DEBUG(pccb->ccb_h.path, CAM_DEBUG_TRACE, ("trm_action\n"));

	actionflags = splcam();
	pACB = (PACB) cam_sim_softc(psim);
    	target_id  = pccb->ccb_h.target_id;
	target_lun = pccb->ccb_h.target_lun;

	switch (pccb->ccb_h.func_code) {
		case XPT_NOOP:	        	
			TRM_DPRINTF(" XPT_NOOP \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Execute the requested I/O operation 
	 	 */
		case XPT_SCSI_IO: {
			PDCB			pDCB = NULL;
			PSRB			pSRB;
			struct ccb_scsiio	*pcsio;
			int			error;
     
			pcsio = &pccb->csio;
			TRM_DPRINTF(" XPT_SCSI_IO \n");
			TRM_DPRINTF("trm: target_id= %d target_lun= %d \n"
			     ,target_id, target_lun);
			TRM_DPRINTF(
			    "pACB->scan_devices[target_id][target_lun]= %d \n"
			    ,pACB->scan_devices[target_id][target_lun]);
			if ((pccb->ccb_h.status & CAM_STATUS_MASK) !=
			    CAM_REQ_INPROG) {
				xpt_done(pccb);
				splx(actionflags);
				return;
			}
			pDCB = &pACB->DCBarray[target_id][target_lun];
			if (!(pDCB->DCBstatus & DS_IN_QUEUE)) {
				pACB->scan_devices[target_id][target_lun] = 1;
				trm_initDCB(pACB, pDCB, pACB->AdapterUnit, 
				    target_id, target_lun); 
			}
			/*
			 * Assign an SRB and connect it with this ccb.
			 */
			pSRB = trm_GetSRB(pACB);
			if (!pSRB) {
				/* Freeze SIMQ */
				pccb->ccb_h.status = CAM_RESRC_UNAVAIL;
				xpt_done(pccb);
				splx(actionflags);
				return;
			}
	    		pSRB->pSRBDCB = pDCB;
	    		pccb->ccb_h.ccb_trmsrb_ptr = pSRB;
	    		pccb->ccb_h.ccb_trmacb_ptr = pACB;
		    	pSRB->pccb = pccb;
			pSRB->ScsiCmdLen = pcsio->cdb_len;
			/* 
			 * move layer of CAM command block to layer of SCSI
			 * Request Block for SCSI processor command doing
			 */
			if ((pccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
				if ((pccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
					bcopy(pcsio->cdb_io.cdb_ptr,pSRB->CmdBlock
					    ,pcsio->cdb_len);
				} else {
					pccb->ccb_h.status = CAM_REQ_INVALID;
					pSRB->pNextSRB = pACB->pFreeSRB;
					pACB->pFreeSRB=  pSRB;
					xpt_done(pccb);
					splx(actionflags);
					return;
				}		
			} else
				bcopy(pcsio->cdb_io.cdb_bytes,
				    pSRB->CmdBlock, pcsio->cdb_len);
			error = bus_dmamap_load_ccb(pACB->buffer_dmat,
						    pSRB->dmamap,
						    pccb,
						    trm_ExecuteSRB,
						    pSRB,
						    0);
			if (error == EINPROGRESS) {
				xpt_freeze_simq(pACB->psim, 1);
				pccb->ccb_h.status |= CAM_RELEASE_SIMQ;
			}
			break;
		}
		case XPT_GDEV_TYPE:		    
			TRM_DPRINTF(" XPT_GDEV_TYPE \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		case XPT_GDEVLIST:		    
			TRM_DPRINTF(" XPT_GDEVLIST \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Path routing inquiry 
	       	 * Path Inquiry CCB 
		 */
		case XPT_PATH_INQ: {
			struct ccb_pathinq *cpi = &pccb->cpi;

			TRM_DPRINTF(" XPT_PATH_INQ \n");
			cpi->version_num = 1; 
			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
			cpi->target_sprt = 0;
			cpi->hba_misc = 0;
			cpi->hba_eng_cnt = 0;
			cpi->max_target = 15 ; 
			cpi->max_lun = pACB->max_lun;        /* 7 or 0 */
			cpi->initiator_id = pACB->AdaptSCSIID;
			cpi->bus_id = cam_sim_bus(psim);
			cpi->base_transfer_speed = 3300;
			strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
			strncpy(cpi->hba_vid, "Tekram_TRM", HBA_IDLEN);
			strncpy(cpi->dev_name, cam_sim_name(psim), DEV_IDLEN);
			cpi->unit_number = cam_sim_unit(psim);
			cpi->transport = XPORT_SPI;
			cpi->transport_version = 2;
			cpi->protocol = PROTO_SCSI;
			cpi->protocol_version = SCSI_REV_2;
			cpi->ccb_h.status = CAM_REQ_CMP;
			xpt_done(pccb);
				   }
			break;
		/*
		 * Release a frozen SIM queue 
		 * Release SIM Queue 
		 */
		case XPT_REL_SIMQ:		    
			TRM_DPRINTF(" XPT_REL_SIMQ \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Set Asynchronous Callback Parameters 
		 * Set Asynchronous Callback CCB
 		 */
		case XPT_SASYNC_CB:		    
			TRM_DPRINTF(" XPT_SASYNC_CB \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Set device type information 
		 * Set Device Type CCB 
 		 */
		case XPT_SDEV_TYPE:		    
			TRM_DPRINTF(" XPT_SDEV_TYPE \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Get EDT entries matching the given pattern 
 		 */
		case XPT_DEV_MATCH:	    	
			TRM_DPRINTF(" XPT_DEV_MATCH \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Turn on debugging for a bus, target or lun 
      		 */
		case XPT_DEBUG:	    	    
			TRM_DPRINTF(" XPT_DEBUG \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
			/*
			 * XPT_ABORT = 0x10, Abort the specified CCB 
			 * Abort XPT request CCB 
			 */
		case XPT_ABORT:             
			TRM_DPRINTF(" XPT_ABORT \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Reset the specified SCSI bus 
		 * Reset SCSI Bus CCB 
 		 */
		case XPT_RESET_BUS: {		
			int i;

			TRM_DPRINTF(" XPT_RESET_BUS \n");
	    		trm_reset(pACB);
			pACB->ACBFlag=0;
			for (i=0; i<500; i++)
				DELAY(1000);
			pccb->ccb_h.status = CAM_REQ_CMP;
			xpt_done(pccb);
				    }
			break;
		/*
		 * Bus Device Reset the specified SCSI device 
		 * Reset SCSI Device CCB 
 		 */
		case XPT_RESET_DEV:	    	
		/*
		 * Don't (yet?) support vendor
		 * specific commands.
		 */
			TRM_DPRINTF(" XPT_RESET_DEV \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Terminate the I/O process 
		 * Terminate I/O Process Request CCB 
 		 */
		case XPT_TERM_IO:	    	
			TRM_DPRINTF(" XPT_TERM_IO \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Get/Set transfer rate/width/disconnection/tag queueing 
		 * settings 
		 * (GET) default/user transfer settings for the target 
	 	 */
		case XPT_GET_TRAN_SETTINGS: {
			struct	ccb_trans_settings *cts = &pccb->cts;
			int	intflag;
			struct	trm_transinfo *tinfo;
			PDCB	pDCB;	
			struct ccb_trans_settings_scsi *scsi =
			    &cts->proto_specific.scsi;
			struct ccb_trans_settings_spi *spi =
			    &cts->xport_specific.spi;

			cts->protocol = PROTO_SCSI;
			cts->protocol_version = SCSI_REV_2;
			cts->transport = XPORT_SPI;
			cts->transport_version = 2;

			TRM_DPRINTF(" XPT_GET_TRAN_SETTINGS \n");
			pDCB = &pACB->DCBarray[target_id][target_lun];
			intflag = splcam();
			/*
			 * disable interrupt
			 */
			if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
				/* current transfer settings */
				if (pDCB->tinfo.disc_tag & TRM_CUR_DISCENB)
					spi->flags = CTS_SPI_FLAGS_DISC_ENB;
				else
					spi->flags = 0;/* no tag & disconnect */
				if (pDCB->tinfo.disc_tag & TRM_CUR_TAGENB)
					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
				tinfo = &pDCB->tinfo.current;
				TRM_DPRINTF("CURRENT:  cts->flags= %2x \n",
				    cts->flags);
			} else {
		  	  /* default(user) transfer settings */
				if (pDCB->tinfo.disc_tag & TRM_USR_DISCENB)
					spi->flags = CTS_SPI_FLAGS_DISC_ENB;
				else
					spi->flags = 0;
				if (pDCB->tinfo.disc_tag & TRM_USR_TAGENB)
					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
				tinfo = &pDCB->tinfo.user;
				TRM_DPRINTF("USER: cts->flags= %2x \n",
					cts->flags);
			}
			spi->sync_period = tinfo->period;
			spi->sync_offset = tinfo->offset;
			spi->bus_width   = tinfo->width;
			TRM_DPRINTF("pDCB->SyncPeriod: %d  \n", 
				pDCB->SyncPeriod);
			TRM_DPRINTF("period: %d  \n", tinfo->period);
			TRM_DPRINTF("offset: %d  \n", tinfo->offset);
			TRM_DPRINTF("width: %d  \n", tinfo->width);

	    		splx(intflag);
			spi->valid = CTS_SPI_VALID_SYNC_RATE |
			    CTS_SPI_VALID_SYNC_OFFSET |
			    CTS_SPI_VALID_BUS_WIDTH |
			    CTS_SPI_VALID_DISC;
			scsi->valid = CTS_SCSI_VALID_TQ;
			pccb->ccb_h.status = CAM_REQ_CMP;
			xpt_done(pccb);
					    }
			break;
		/* 
		 * Get/Set transfer rate/width/disconnection/tag queueing 
		 * settings
		 * (Set) transfer rate/width negotiation settings 
		 */
		case XPT_SET_TRAN_SETTINGS: {
			struct	ccb_trans_settings *cts =  &pccb->cts;
			u_int	update_type;
			int	intflag;
			PDCB	pDCB;
			struct ccb_trans_settings_scsi *scsi =
			    &cts->proto_specific.scsi;
			struct ccb_trans_settings_spi *spi =
			    &cts->xport_specific.spi;

			TRM_DPRINTF(" XPT_SET_TRAN_SETTINGS \n");
			update_type = 0;
			if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
				update_type |= TRM_TRANS_GOAL;
			if (cts->type == CTS_TYPE_USER_SETTINGS)
				update_type |= TRM_TRANS_USER;
			intflag = splcam();
	    		pDCB = &pACB->DCBarray[target_id][target_lun];

			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
			  /*ccb disc enables */
				if (update_type & TRM_TRANS_GOAL) {
					if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB)
					    != 0) 
				    		pDCB->tinfo.disc_tag 
						    |= TRM_CUR_DISCENB;
					else
						pDCB->tinfo.disc_tag &=
						    ~TRM_CUR_DISCENB;
				}
				if (update_type & TRM_TRANS_USER) {
					if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB)
					    != 0)
						pDCB->tinfo.disc_tag 
						    |= TRM_USR_DISCENB;
					else
						pDCB->tinfo.disc_tag &=
						    ~TRM_USR_DISCENB;
				}
			}
			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
			  /* if ccb tag q active */
				if (update_type & TRM_TRANS_GOAL) {
					if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB)
					    != 0)
						pDCB->tinfo.disc_tag |= 
						    TRM_CUR_TAGENB;
					else
						pDCB->tinfo.disc_tag &= 
						    ~TRM_CUR_TAGENB;
				}
				if (update_type & TRM_TRANS_USER) {
					if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB)
					    != 0)
				  		pDCB->tinfo.disc_tag |= 
						    TRM_USR_TAGENB;
					else
						pDCB->tinfo.disc_tag &= 
						    ~TRM_USR_TAGENB;
				}	
			}
			/* Minimum sync period factor	*/

			if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
				/* if ccb sync active */
				/* TRM-S1040 MinSyncPeriod = 4 clocks/byte */
				if ((spi->sync_period != 0) &&
				    (spi->sync_period < 125))
					spi->sync_period = 125;
				/* 1/(125*4) minsync 2 MByte/sec */
				if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET)
				    != 0) {
					if (spi->sync_offset == 0)
				 		spi->sync_period = 0;
					/* TRM-S1040 MaxSyncOffset = 15 bytes*/
					if (spi->sync_offset > 15) 
						spi->sync_offset = 15;
				}
			}
			if ((update_type & TRM_TRANS_USER) != 0) {
				pDCB->tinfo.user.period = spi->sync_period;
				pDCB->tinfo.user.offset = spi->sync_offset;
				pDCB->tinfo.user.width  = spi->bus_width;
			}
			if ((update_type & TRM_TRANS_GOAL) != 0) {
				pDCB->tinfo.goal.period = spi->sync_period;
				pDCB->tinfo.goal.offset = spi->sync_offset;
				pDCB->tinfo.goal.width  = spi->bus_width;
			}
			splx(intflag);
			pccb->ccb_h.status = CAM_REQ_CMP;
			xpt_done(pccb);
			break;
					    }
		/*
		 * Calculate the geometry parameters for a device give
		 * the sector size and volume size. 
   		 */
		case XPT_CALC_GEOMETRY:
			TRM_DPRINTF(" XPT_CALC_GEOMETRY \n");
			cam_calc_geometry(&pccb->ccg, /*extended*/1);
			xpt_done(pccb);
			break;
		case XPT_ENG_INQ:           
			TRM_DPRINTF(" XPT_ENG_INQ \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * HBA execute engine request 
		 * This structure must match SCSIIO size 
		 */
		case XPT_ENG_EXEC:		    
			TRM_DPRINTF(" XPT_ENG_EXEC \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * XPT_EN_LUN = 0x30, Enable LUN as a target 
		 * Target mode structures. 
	 	 */
		case XPT_EN_LUN:            
		/*
		 * Don't (yet?) support vendor
		 * specific commands.
		 */
			TRM_DPRINTF(" XPT_EN_LUN \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		* Execute target I/O request 
		*/
		case XPT_TARGET_IO:		    
		/*
		 * Don't (yet?) support vendor
		 * specific commands.
		 */
			TRM_DPRINTF(" XPT_TARGET_IO \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Accept Host Target Mode CDB 
       		 */
		case XPT_ACCEPT_TARGET_IO:	
		/*
		 * Don't (yet?) support vendor
		 * specific commands.
		 */
			TRM_DPRINTF(" XPT_ACCEPT_TARGET_IO \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Continue Host Target I/O Connection 
 		 */
		case XPT_CONT_TARGET_IO:  	
		/*
		 * Don't (yet?) support vendor
		 * specific commands.
		 */
			TRM_DPRINTF(" XPT_CONT_TARGET_IO \n");
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Notify Host Target driver of event 
 		 */
		case XPT_IMMED_NOTIFY:	    
			TRM_DPRINTF(" XPT_IMMED_NOTIFY \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * Acknowledgement of event
       		 */
		case XPT_NOTIFY_ACK:	    
			TRM_DPRINTF(" XPT_NOTIFY_ACK \n");
	    		pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		/*
		 * XPT_VUNIQUE = 0x80
		 */
		case XPT_VUNIQUE:   
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
		default:
			pccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(pccb);
			break;
	}
	splx(actionflags);
}

static void 
trm_poll(struct cam_sim *psim)
{       
	trm_Interrupt(cam_sim_softc(psim));	
}

static void
trm_ResetDevParam(PACB pACB)
{
	PDCB		pDCB, pdcb;
	PNVRAMTYPE 	pEEpromBuf;
	u_int8_t	PeriodIndex;

	pDCB = pACB->pLinkDCB;
	if (pDCB == NULL)
		return;
	pdcb = pDCB;
	do {
		pDCB->SyncMode  &= ~(SYNC_NEGO_DONE+ WIDE_NEGO_DONE);
		pDCB->SyncPeriod = 0;
		pDCB->SyncOffset = 0;
		pEEpromBuf = &trm_eepromBuf[pACB->AdapterUnit];
		pDCB->DevMode = 
		  pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0;
		pDCB->AdpMode = pEEpromBuf->NvramChannelCfg;
		PeriodIndex =
		   pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod & 0x07;
		if (pACB->AdaptType == 1) /* is U2? */
			pDCB->MaxNegoPeriod = dc395u2x_clock_period[PeriodIndex];
		else
			pDCB->MaxNegoPeriod = dc395x_clock_period[PeriodIndex];
		if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && 
		    (pACB->Config & HCC_WIDE_CARD))
			pDCB->SyncMode |= WIDE_NEGO_ENABLE;
		pDCB = pDCB->pNextDCB;
	}
	while (pdcb != pDCB);
}

static void
trm_RecoverSRB(PACB pACB)
{
	PDCB		pDCB, pdcb;
	PSRB		psrb, psrb2;
       	u_int16_t	cnt, i;

	pDCB = pACB->pLinkDCB;
	if (pDCB == NULL)
		return;
	pdcb = pDCB;
	do {
		cnt = pdcb->GoingSRBCnt;
		psrb = pdcb->pGoingSRB;
		for (i = 0; i < cnt; i++) {
			psrb2 = psrb;
			psrb = psrb->pNextSRB;
			if (pdcb->pWaitingSRB) {
				psrb2->pNextSRB = pdcb->pWaitingSRB;
				pdcb->pWaitingSRB = psrb2;
			} else {
				pdcb->pWaitingSRB = psrb2;
				pdcb->pWaitingLastSRB = psrb2;
				psrb2->pNextSRB = NULL;
			}
		}
		pdcb->GoingSRBCnt = 0;
		pdcb->pGoingSRB = NULL;
		pdcb = pdcb->pNextDCB;
	}
	while (pdcb != pDCB);
}

static void
trm_reset(PACB pACB)
{
	int		intflag;
	u_int16_t	i;

    	TRM_DPRINTF("trm: RESET");
    	intflag = splcam();
	trm_reg_write8(0x00, TRMREG_DMA_INTEN);
	trm_reg_write8(0x00, TRMREG_SCSI_INTEN);

	trm_ResetSCSIBus(pACB);
	for (i = 0; i < 500; i++)
		DELAY(1000);
    	trm_reg_write8(0x7F, TRMREG_SCSI_INTEN); 
	/* Enable DMA interrupt	*/
	trm_reg_write8(EN_SCSIINTR, TRMREG_DMA_INTEN);
	/* Clear DMA FIFO */
	trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL);
	/* Clear SCSI FIFO */
	trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL);
	trm_ResetDevParam(pACB);
	trm_DoingSRB_Done(pACB);
	pACB->pActiveDCB = NULL;
	pACB->ACBFlag = 0;/* RESET_DETECT, RESET_DONE ,RESET_DEV */
	trm_DoWaitingSRB(pACB);
	/* Tell the XPT layer that a bus reset occured    */
	if (pACB->ppath != NULL)
		xpt_async(AC_BUS_RESET, pACB->ppath, NULL);
	splx(intflag);
    	return;
}

static u_int16_t
trm_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB)
{
	u_int16_t	return_code;
	u_int8_t	scsicommand, i,command,identify_message;
	u_int8_t *	ptr;
	union  ccb	*pccb;
	struct ccb_scsiio *pcsio;

	pccb  = pSRB->pccb;
	pcsio = &pccb->csio;

	trm_reg_write8(pACB->AdaptSCSIID, TRMREG_SCSI_HOSTID);
	trm_reg_write8(pDCB->TargetID, TRMREG_SCSI_TARGETID);
	trm_reg_write8(pDCB->SyncPeriod, TRMREG_SCSI_SYNC);
	trm_reg_write8(pDCB->SyncOffset, TRMREG_SCSI_OFFSET);
	pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */
	/* Flush FIFO */
	trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL);

	identify_message = pDCB->IdentifyMsg;

   	if ((pSRB->CmdBlock[0] == INQUIRY) ||
	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
	    (pSRB->SRBFlag & AUTO_REQSENSE)) {
		if (((pDCB->SyncMode & WIDE_NEGO_ENABLE) &&
		      !(pDCB->SyncMode & WIDE_NEGO_DONE)) 
		|| ((pDCB->SyncMode & SYNC_NEGO_ENABLE) &&
		  !(pDCB->SyncMode & SYNC_NEGO_DONE))) {
			if (!(pDCB->IdentifyMsg & 7) ||
			    (pSRB->CmdBlock[0] != INQUIRY)) {
				scsicommand = SCMD_SEL_ATNSTOP;
				pSRB->SRBState = SRB_MSGOUT;
				goto polling;
			}
		}
       	/* 
       	* Send identify message	
       	*/
		trm_reg_write8((identify_message & 0xBF) ,TRMREG_SCSI_FIFO); 
		scsicommand = SCMD_SEL_ATN;
		pSRB->SRBState = SRB_START_;
	} else {
		/* not inquiry,request sense,auto request sense */
		/* 
		 * Send identify message	
		 */
		trm_reg_write8(identify_message,TRMREG_SCSI_FIFO);
		scsicommand = SCMD_SEL_ATN;
		pSRB->SRBState = SRB_START_;
		if (pDCB->SyncMode & EN_TAG_QUEUING) {
		  /* Send Tag message */
 			trm_reg_write8(MSG_SIMPLE_QTAG, TRMREG_SCSI_FIFO);
			trm_reg_write8(pSRB->TagNumber, TRMREG_SCSI_FIFO);
			scsicommand = SCMD_SEL_ATN3;
		}
	}
polling:
	/*
	 * 	 Send CDB ..command block .........			
	 */
   	if (pSRB->SRBFlag & AUTO_REQSENSE) {
		trm_reg_write8(REQUEST_SENSE, TRMREG_SCSI_FIFO);
		trm_reg_write8((pDCB->IdentifyMsg << 5), TRMREG_SCSI_FIFO);
		trm_reg_write8(0, TRMREG_SCSI_FIFO);
		trm_reg_write8(0, TRMREG_SCSI_FIFO);
		trm_reg_write8(pcsio->sense_len, TRMREG_SCSI_FIFO);
		trm_reg_write8(0, TRMREG_SCSI_FIFO);
	} else {
		ptr = (u_int8_t *) pSRB->CmdBlock;
		for (i = 0; i < pSRB->ScsiCmdLen ; i++) {
			command = *ptr++;
			trm_reg_write8(command,TRMREG_SCSI_FIFO);
		}
	}
	if (trm_reg_read16(TRMREG_SCSI_STATUS) & SCSIINTERRUPT) { 
	    /* 
	     * If trm_StartSCSI return 1 :
	     * current interrupt status is interrupt disreenable 
	     * It's said that SCSI processor has more one SRB need to do,
     	     * SCSI processor has been occupied by one SRB.
	     */
		pSRB->SRBState = SRB_READY;
		return_code = 1;
	} else { 
	  /* 
	   * If trm_StartSCSI return 0 :
	   * current interrupt status is interrupt enable 
	   * It's said that SCSI processor is unoccupied 
	   */
		pSRB->ScsiPhase  = SCSI_NOP1; /* SCSI bus free Phase */
		pACB->pActiveDCB = pDCB;
		pDCB->pActiveSRB = pSRB;
		return_code = 0;
		trm_reg_write16(DO_DATALATCH | DO_HWRESELECT, 
		    TRMREG_SCSI_CONTROL);/* it's important for atn stop*/
		/*
		 * SCSI cammand 
		 */
		trm_reg_write8(scsicommand,TRMREG_SCSI_COMMAND);
	}
	return (return_code);	
}

static void 
trm_Interrupt(vpACB)
void *vpACB;
{
	PACB		pACB;
	PDCB		pDCB;
	PSRB		pSRB;
	u_int16_t	phase;
	void		(*stateV)(PACB, PSRB, u_int16_t *);
	u_int16_t	scsi_status=0;
	u_int8_t	scsi_intstatus;

	pACB = vpACB;

	scsi_status = trm_reg_read16(TRMREG_SCSI_STATUS);
	if (!(scsi_status & SCSIINTERRUPT)) {
		TRM_DPRINTF("trm_Interrupt: TRMREG_SCSI_STATUS scsi_status = NULL ,return......");
	    	return;
	}
	TRM_DPRINTF("scsi_status=%2x,",scsi_status);

    	scsi_intstatus = trm_reg_read8(TRMREG_SCSI_INTSTATUS);

	TRM_DPRINTF("scsi_intstatus=%2x,",scsi_intstatus);

    	if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) {
		trm_Disconnect(pACB);
		return;
	}

	if (scsi_intstatus & INT_RESELECTED) {
		trm_Reselect(pACB);
		return;
	}
	if (scsi_intstatus & INT_SCSIRESET) {
		trm_ScsiRstDetect(pACB);
		return;
	}

	if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) {
		pDCB = pACB->pActiveDCB;
		KASSERT(pDCB != NULL, ("no active DCB"));
		pSRB = pDCB->pActiveSRB;
		if (pDCB->DCBFlag & ABORT_DEV_)
				trm_EnableMsgOutAbort1(pACB, pSRB);
		phase = (u_int16_t) pSRB->ScsiPhase;  /* phase: */
		stateV = (void *) trm_SCSI_phase0[phase];
		stateV(pACB, pSRB, &scsi_status);
		pSRB->ScsiPhase = scsi_status & PHASEMASK; 
		/* phase:0,1,2,3,4,5,6,7 */
		phase = (u_int16_t) scsi_status & PHASEMASK;       
		stateV = (void *) trm_SCSI_phase1[phase];
		stateV(pACB, pSRB, &scsi_status);  
	}
}

static void
trm_MsgOutPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

	if (pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT))
		*pscsi_status = PH_BUS_FREE;
	/*.. initial phase*/
}

static void
trm_MsgOutPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	u_int8_t	bval;
	u_int16_t	i, cnt;
	u_int8_t *	ptr;
	PDCB		pDCB;

	trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL);
	pDCB = pACB->pActiveDCB;
	if (!(pSRB->SRBState & SRB_MSGOUT)) {
		cnt = pSRB->MsgCnt;
		if (cnt) {
			ptr = (u_int8_t *) pSRB->MsgOutBuf;
			for (i = 0; i < cnt; i++) {
				trm_reg_write8(*ptr, TRMREG_SCSI_FIFO);
				ptr++;
			}
			pSRB->MsgCnt = 0;
			if ((pDCB->DCBFlag & ABORT_DEV_) &&
			    (pSRB->MsgOutBuf[0] == MSG_ABORT)) {
				pSRB->SRBState = SRB_ABORT_SENT;
			}
		} else {
			bval = MSG_ABORT;	
			if ((pSRB->CmdBlock[0] == INQUIRY) ||
					(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
					(pSRB->SRBFlag & AUTO_REQSENSE)) {
				if (pDCB->SyncMode & SYNC_NEGO_ENABLE) {
					goto  mop1;
				}
			}
			trm_reg_write8(bval, TRMREG_SCSI_FIFO);
		}
	} else {
mop1:   /* message out phase */
		if (!(pSRB->SRBState & SRB_DO_WIDE_NEGO)
		    && (pDCB->SyncMode & WIDE_NEGO_ENABLE)) {
		  /*
	   	   * WIDE DATA TRANSFER REQUEST code (03h)
		   */
			pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP);
			trm_reg_write8((pDCB->IdentifyMsg & 0xBF),
			    TRMREG_SCSI_FIFO); 
			trm_reg_write8(MSG_EXTENDED,TRMREG_SCSI_FIFO);
			/* (01h) */
			trm_reg_write8(2,TRMREG_SCSI_FIFO);	
			/* Message length (02h) */
			trm_reg_write8(3,TRMREG_SCSI_FIFO);
			/* wide data xfer (03h) */
			trm_reg_write8(1,TRMREG_SCSI_FIFO);
			/* width:0(8bit),1(16bit),2(32bit) */
			pSRB->SRBState |= SRB_DO_WIDE_NEGO; 
		} else if (!(pSRB->SRBState & SRB_DO_SYNC_NEGO) 
		    && (pDCB->SyncMode & SYNC_NEGO_ENABLE)) {
		  /*
	   	   * SYNCHRONOUS DATA TRANSFER REQUEST code (01h)
		   */
			if (!(pDCB->SyncMode & WIDE_NEGO_DONE))
				trm_reg_write8((pDCB->IdentifyMsg & 0xBF),
						TRMREG_SCSI_FIFO);
			trm_reg_write8(MSG_EXTENDED,TRMREG_SCSI_FIFO);
		  /* (01h) */
			trm_reg_write8(3,TRMREG_SCSI_FIFO); 
		  /* Message length (03h) */
			trm_reg_write8(1,TRMREG_SCSI_FIFO);
		  /* SYNCHRONOUS DATA TRANSFER REQUEST code (01h) */
			trm_reg_write8(pDCB->MaxNegoPeriod,TRMREG_SCSI_FIFO);
		  /* Transfer peeriod factor */
			trm_reg_write8((pACB->AdaptType == 1) ? 31 : 15,
			    TRMREG_SCSI_FIFO); 
		  /* REQ/ACK offset */
			pSRB->SRBState |= SRB_DO_SYNC_NEGO;
		}
	}
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop */
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_FIFO_OUT, TRMREG_SCSI_COMMAND);
}

static void 
trm_CommandPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

}

static void 
trm_CommandPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	PDCB			pDCB;
	u_int8_t *		ptr;
	u_int16_t		i, cnt;
	union  ccb		*pccb;
	struct ccb_scsiio	*pcsio;

	pccb  = pSRB->pccb;
	pcsio = &pccb->csio;

	trm_reg_write16(DO_CLRATN | DO_CLRFIFO , TRMREG_SCSI_CONTROL);
	if (!(pSRB->SRBFlag & AUTO_REQSENSE)) {
		cnt = (u_int16_t) pSRB->ScsiCmdLen;
		ptr = (u_int8_t *) pSRB->CmdBlock;
		for (i = 0; i < cnt; i++) {
			trm_reg_write8(*ptr, TRMREG_SCSI_FIFO);
			ptr++;
		}
	} else {
		trm_reg_write8(REQUEST_SENSE, TRMREG_SCSI_FIFO);
		pDCB = pACB->pActiveDCB;
		/* target id */
		trm_reg_write8((pDCB->IdentifyMsg << 5), TRMREG_SCSI_FIFO);
		trm_reg_write8(0, TRMREG_SCSI_FIFO);
		trm_reg_write8(0, TRMREG_SCSI_FIFO);
		/* sizeof(struct scsi_sense_data) */
		trm_reg_write8(pcsio->sense_len, TRMREG_SCSI_FIFO);
		trm_reg_write8(0, TRMREG_SCSI_FIFO);
	}
	pSRB->SRBState = SRB_COMMAND;
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop*/
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_FIFO_OUT, TRMREG_SCSI_COMMAND);
}

static void
trm_DataOutPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	PDCB		pDCB;
	u_int8_t	TempDMAstatus,SGIndexTemp;
	u_int16_t	scsi_status;
	PSEG		pseg;
	u_long		TempSRBXferredLength,dLeftCounter=0;

	pDCB = pSRB->pSRBDCB;
	scsi_status = *pscsi_status;

	if (!(pSRB->SRBState & SRB_XFERPAD)) {
		if (scsi_status & PARITYERROR)
			pSRB->SRBStatus |= PARITY_ERROR;
		if (!(scsi_status & SCSIXFERDONE)) {
      		  /*
		   * when data transfer from DMA FIFO to SCSI FIFO
		   * if there was some data left in SCSI FIFO
		   */
  			dLeftCounter = (u_long) 
			  (trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x3F);
			if (pDCB->SyncPeriod & WIDE_SYNC) {
			  /*
		   	   * if WIDE scsi SCSI FIFOCNT unit is word
	   		   * so need to * 2
   			   */
				dLeftCounter <<= 1;
			}
		}
		/*
		 * caculate all the residue data that not yet tranfered
		 * SCSI transfer counter + left in SCSI FIFO data
		 *
		 * .....TRM_SCSI_COUNTER (24bits)
		 * The counter always decrement by one for every SCSI byte 
		 *transfer.
		 * .....TRM_SCSI_FIFOCNT (5bits)
		 * The counter is SCSI FIFO offset counter
		 */
		dLeftCounter += trm_reg_read32(TRMREG_SCSI_COUNTER);
		if (dLeftCounter == 1) {
			dLeftCounter = 0;
			trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL);
		}
		if ((dLeftCounter == 0) || 
		    (scsi_status & SCSIXFERCNT_2_ZERO)) {   
			TempDMAstatus = trm_reg_read8(TRMREG_DMA_STATUS);
			while (!(TempDMAstatus & DMAXFERCOMP)) {
				TempDMAstatus = 
				  trm_reg_read8(TRMREG_DMA_STATUS);
			}
			pSRB->SRBTotalXferLength = 0;
		} else {
		  /* Update SG list		*/
		  /*
	   	   * if transfer not yet complete
   		   * there were some data residue in SCSI FIFO or
		   * SCSI transfer counter not empty
		   */
			if (pSRB->SRBTotalXferLength != dLeftCounter) {
			  /*
		  	   * data that had transferred length
	   		   */
				TempSRBXferredLength = 
				  pSRB->SRBTotalXferLength - dLeftCounter;
				/*
				 * next time to be transferred length
				 */
				pSRB->SRBTotalXferLength = dLeftCounter;
				/*
				 * parsing from last time disconnect SRBSGIndex
				 */
				pseg = 
				  pSRB->pSRBSGL + pSRB->SRBSGIndex;
				for (SGIndexTemp = pSRB->SRBSGIndex;
				    SGIndexTemp < pSRB->SRBSGCount; 
				    SGIndexTemp++) {
					/* 
					 * find last time which SG transfer be 
					 * disconnect 
					 */
					if (TempSRBXferredLength >= 
					    pseg->length) 
						TempSRBXferredLength -= 
						  pseg->length;
					else {
				  	  /*
			   		   * update last time disconnected SG 
					   * list
				   	   */
						pseg->length -= 
						  TempSRBXferredLength; 
						/* residue data length  */
						pseg->address += 
						  TempSRBXferredLength;
						/* residue data pointer */
						pSRB->SRBSGIndex = SGIndexTemp;
						break;
					}
					pseg++;
				}
			}
		}
	}
	trm_reg_write8(STOPDMAXFER ,TRMREG_DMA_CONTROL);
}


static void
trm_DataOutPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	u_int16_t	ioDir;
	/*
	 * do prepare befor transfer when data out phase
	 */

	ioDir = XFERDATAOUT;
	trm_DataIO_transfer(pACB, pSRB, ioDir);
}

static void 
trm_DataInPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	u_int8_t	TempDMAstatus, SGIndexTemp;
	u_int16_t	scsi_status;
	PSEG		pseg;
	u_long		TempSRBXferredLength,dLeftCounter = 0;

    	scsi_status = *pscsi_status;
	if (!(pSRB->SRBState & SRB_XFERPAD)) {
		if (scsi_status & PARITYERROR)
			pSRB->SRBStatus |= PARITY_ERROR;
		dLeftCounter += trm_reg_read32(TRMREG_SCSI_COUNTER);
		if ((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO)) {
			TempDMAstatus = trm_reg_read8(TRMREG_DMA_STATUS);
			while (!(TempDMAstatus & DMAXFERCOMP))
				TempDMAstatus = trm_reg_read8(TRMREG_DMA_STATUS);
			pSRB->SRBTotalXferLength = 0;
		} else {  
	  	  /*
   		   * parsing the case:
	   	   * when a transfer not yet complete 
	   	   * but be disconnected by uper layer
	   	   * if transfer not yet complete
	   	   * there were some data residue in SCSI FIFO or
	   	   * SCSI transfer counter not empty
	   	   */
		  if (pSRB->SRBTotalXferLength != dLeftCounter) {
				/*
				 * data that had transferred length
				 */
		  	TempSRBXferredLength = 
			  pSRB->SRBTotalXferLength - dLeftCounter;
				/*
			 	 * next time to be transferred length
				 */
			pSRB->SRBTotalXferLength = dLeftCounter;
				/*
				 * parsing from last time disconnect SRBSGIndex
				 */
			pseg = pSRB->pSRBSGL + pSRB->SRBSGIndex;
			for (SGIndexTemp = pSRB->SRBSGIndex; 
			    SGIndexTemp < pSRB->SRBSGCount;
			    SGIndexTemp++) {
			  /* 
	   		   * find last time which SG transfer be disconnect 
	   		   */
	 			if (TempSRBXferredLength >= pseg->length)
					TempSRBXferredLength -= pseg->length;
				else {
		  		  /*
   				   * update last time disconnected SG list
				   */
					pseg->length -= TempSRBXferredLength;
					/* residue data length  */
					pseg->address += TempSRBXferredLength;
					/* residue data pointer */
					pSRB->SRBSGIndex = SGIndexTemp;
					break;
				} 
				pseg++;
			}
	  	  }
		}
	}
}

static void
trm_DataInPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	u_int16_t	ioDir;
	/*
	 * do prepare befor transfer when data in phase
	 */
	
	ioDir = XFERDATAIN;
	trm_DataIO_transfer(pACB, pSRB, ioDir);
}

static void
trm_DataIO_transfer(PACB pACB, PSRB pSRB, u_int16_t ioDir)
{
	u_int8_t	bval;
	PDCB		pDCB;

	pDCB = pSRB->pSRBDCB;
	if (pSRB->SRBSGIndex < pSRB->SRBSGCount) {
		if (pSRB->SRBTotalXferLength != 0) {
			/* 
			 * load what physical address of Scatter/Gather list 
			 table want to be transfer
			 */
			TRM_DPRINTF(" SG->address=%8x \n",pSRB->pSRBSGL->address);
			TRM_DPRINTF(" SG->length=%8x \n",pSRB->pSRBSGL->length);
			TRM_DPRINTF(" pDCB->SyncPeriod=%x \n",pDCB->SyncPeriod);
			TRM_DPRINTF(" pSRB->pSRBSGL=%8x \n",(unsigned int)pSRB->pSRBSGL);
			TRM_DPRINTF(" pSRB->SRBSGPhyAddr=%8x \n",pSRB->SRBSGPhyAddr);
			TRM_DPRINTF(" pSRB->SRBSGIndex=%d \n",pSRB->SRBSGIndex);
			TRM_DPRINTF(" pSRB->SRBSGCount=%d \n",pSRB->SRBSGCount);
			TRM_DPRINTF(" pSRB->SRBTotalXferLength=%d \n",pSRB->SRBTotalXferLength);

			pSRB->SRBState = SRB_DATA_XFER;
			trm_reg_write32(0, TRMREG_DMA_XHIGHADDR);
			trm_reg_write32(
			    (pSRB->SRBSGPhyAddr + 
			     ((u_long)pSRB->SRBSGIndex << 3)),
			    TRMREG_DMA_XLOWADDR);
			/*
			 * load how many bytes in the Scatter/Gather 
			 * list table 
			 */
			trm_reg_write32(
			    ((u_long)(pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3),
			    TRMREG_DMA_XCNT);			
			/*
			 * load total transfer length (24bits) max value
			 * 16Mbyte 
			 */
			trm_reg_write32(pSRB->SRBTotalXferLength,
			    TRMREG_SCSI_COUNTER);
			/* Start DMA transfer */
			trm_reg_write16(ioDir, TRMREG_DMA_COMMAND);
			/* Start SCSI transfer */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/* it's important for atn stop */
			/*
			 * SCSI cammand 
			 */
			bval = (ioDir == XFERDATAOUT) ?
			  SCMD_DMA_OUT : SCMD_DMA_IN;
			trm_reg_write8(bval, TRMREG_SCSI_COMMAND);
		} else {
		  /* xfer pad */
			if (pSRB->SRBSGCount) {
				pSRB->AdaptStatus = H_OVER_UNDER_RUN;
				pSRB->SRBStatus |= OVER_RUN;
			}
			if (pDCB->SyncPeriod & WIDE_SYNC)
				trm_reg_write32(2,TRMREG_SCSI_COUNTER);
			else
				trm_reg_write32(1,TRMREG_SCSI_COUNTER);
			if (ioDir == XFERDATAOUT)
				trm_reg_write16(0, TRMREG_SCSI_FIFO);
			else
				trm_reg_read16(TRMREG_SCSI_FIFO);
			pSRB->SRBState |= SRB_XFERPAD;
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/* it's important for atn stop */
			/*
			 * SCSI cammand 
			 */
			bval = (ioDir == XFERDATAOUT) ? 
			  SCMD_FIFO_OUT : SCMD_FIFO_IN;
			trm_reg_write8(bval, TRMREG_SCSI_COMMAND);
		}
	}
}

static void
trm_StatusPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

	pSRB->TargetStatus = trm_reg_read8(TRMREG_SCSI_FIFO);
	pSRB->SRBState = SRB_COMPLETED;
	*pscsi_status = PH_BUS_FREE;  
	/*.. initial phase*/
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop */
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
}



static void
trm_StatusPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

	if (trm_reg_read16(TRMREG_DMA_COMMAND) & 0x0001) {
		if (!(trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x40))
	       		trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL);
		if (!(trm_reg_read16(TRMREG_DMA_FIFOCNT) & 0x8000))
			trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL);
	} else {
		if (!(trm_reg_read16(TRMREG_DMA_FIFOCNT) & 0x8000))
			trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL);
		if (!(trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x40))
			trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL);
	}
	pSRB->SRBState = SRB_STATUS;
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop */
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_COMP, TRMREG_SCSI_COMMAND);
}

/*
 *scsiiom		 
 *       trm_MsgInPhase0: one of trm_SCSI_phase0[] vectors
 *            stateV = (void *) trm_SCSI_phase0[phase]
 *		           if phase =7    
 * extended message codes:
 *
 *   code        description
 *
 *    02h        Reserved
 *    00h        MODIFY DATA  POINTER
 *    01h        SYNCHRONOUS DATA TRANSFER REQUEST
 *    03h        WIDE DATA TRANSFER REQUEST
 * 04h - 7Fh     Reserved
 * 80h - FFh     Vendor specific  
 *		        
 */

static void
trm_MsgInPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
	u_int8_t	message_in_code,bIndex,message_in_tag_id;
	PDCB		pDCB;
	PSRB		pSRBTemp;

	pDCB = pACB->pActiveDCB;

	message_in_code = trm_reg_read8(TRMREG_SCSI_FIFO);
	if (!(pSRB->SRBState & SRB_EXTEND_MSGIN)) {
		if (message_in_code == MSG_DISCONNECT) {
			pSRB->SRBState = SRB_DISCONNECT;
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else if (message_in_code == MSG_SAVE_PTR) {
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else if ((message_in_code == MSG_EXTENDED) ||
		    ((message_in_code >= MSG_SIMPLE_QTAG) &&
		     (message_in_code <= MSG_ORDER_QTAG))) {
			pSRB->SRBState |= SRB_EXTEND_MSGIN;
		    	pSRB->MsgInBuf[0] = message_in_code;
			/* extended message      (01h) */
			pSRB->MsgCnt = 1;
			pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
			/* extended message length (n) */
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else if (message_in_code == MSG_REJECT_) {
			/* Reject message */
			if (pDCB->SyncMode & WIDE_NEGO_ENABLE) {
			  /* do wide nego reject */
				pDCB = pSRB->pSRBDCB;
				pDCB->SyncMode |= WIDE_NEGO_DONE;
				pDCB->SyncMode &= ~(SYNC_NEGO_DONE | 
				    EN_ATN_STOP | WIDE_NEGO_ENABLE);
				pSRB->SRBState &= ~(SRB_DO_WIDE_NEGO+SRB_MSGIN);
				if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) 
				    && !(pDCB->SyncMode & SYNC_NEGO_DONE)) {   
				  /* Set ATN, in case ATN was clear */
					pSRB->SRBState |= SRB_MSGOUT;
					trm_reg_write16(
					    DO_SETATN,
					    TRMREG_SCSI_CONTROL);
				} else {   
			  	  /* Clear ATN */
					trm_reg_write16(
					    DO_CLRATN,
					    TRMREG_SCSI_CONTROL);
				}
			} else if (pDCB->SyncMode & SYNC_NEGO_ENABLE) { 
			  /* do sync nego reject */
				trm_reg_write16(DO_CLRATN,TRMREG_SCSI_CONTROL);
				if (pSRB->SRBState & SRB_DO_SYNC_NEGO) {
					pDCB = pSRB->pSRBDCB;
					pDCB->SyncMode &= 
					  ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); 
					pDCB->SyncPeriod = 0;
					pDCB->SyncOffset = 0;
					/*               
					 *
					 *   program SCSI control register
					 *
					 */
					trm_reg_write8(pDCB->SyncPeriod,
					    TRMREG_SCSI_SYNC);
					trm_reg_write8(pDCB->SyncOffset,
					    TRMREG_SCSI_OFFSET);
					trm_SetXferRate(pACB,pSRB,pDCB);
				}
			}
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else if (message_in_code == MSG_IGNOREWIDE) {
			trm_reg_write32(1, TRMREG_SCSI_COUNTER);
			trm_reg_read8(TRMREG_SCSI_FIFO);
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else {
	  	  /* Restore data pointer message */
  		  /* Save data pointer message	  */
		  /* Completion message		  */
		  /* NOP message       	          */
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		}
	} else {	
	  /* 
   	   * Parsing incomming extented messages 
	   */
		*pSRB->pMsgPtr = message_in_code;
		pSRB->MsgCnt++;
		pSRB->pMsgPtr++;
		TRM_DPRINTF("pSRB->MsgInBuf[0]=%2x \n ",pSRB->MsgInBuf[0]);
		TRM_DPRINTF("pSRB->MsgInBuf[1]=%2x \n ",pSRB->MsgInBuf[1]);
		TRM_DPRINTF("pSRB->MsgInBuf[2]=%2x \n ",pSRB->MsgInBuf[2]);
		TRM_DPRINTF("pSRB->MsgInBuf[3]=%2x \n ",pSRB->MsgInBuf[3]);
		TRM_DPRINTF("pSRB->MsgInBuf[4]=%2x \n ",pSRB->MsgInBuf[4]);
	    	if ((pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG)
		    && (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG)) {
		  /*
	   	   * is QUEUE tag message :
   		   *
	   	   * byte 0:
	   	   * HEAD    QUEUE TAG (20h)
	   	   * ORDERED QUEUE TAG (21h)
	   	   * SIMPLE  QUEUE TAG (22h)
	   	   * byte 1:
	   	   * Queue tag (00h - FFh)
	   	   */
			if (pSRB->MsgCnt == 2) {
				pSRB->SRBState = 0;
				message_in_tag_id = pSRB->MsgInBuf[1];
				pSRB = pDCB->pGoingSRB;
				pSRBTemp = pDCB->pGoingLastSRB;
				if (pSRB) {
					for (;;) {
						if (pSRB->TagNumber != 
						    message_in_tag_id) {
							if (pSRB == pSRBTemp) {
								goto  mingx0;
							}
							pSRB = pSRB->pNextSRB;
						} else
							break;
					}
					if (pDCB->DCBFlag & ABORT_DEV_) {
						pSRB->SRBState = SRB_ABORT_SENT;
						trm_EnableMsgOutAbort1(
						    pACB, pSRB);
					}
					if (!(pSRB->SRBState & SRB_DISCONNECT)) {
						TRM_DPRINTF("SRB not yet disconnect........ \n ");
						goto  mingx0;
					}
					pDCB->pActiveSRB = pSRB;
					pSRB->SRBState = SRB_DATA_XFER;
				} else {
mingx0:
	     				pSRB = &pACB->TmpSRB;
					pSRB->SRBState = SRB_UNEXPECT_RESEL;
					pDCB->pActiveSRB = pSRB;
					pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
					trm_EnableMsgOutAbort2(
					    pACB,
					    pSRB);
				}
			}
			*pscsi_status = PH_BUS_FREE;
			/* .. initial phase */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/* it's important for atn stop */
			/*
			 * SCSI command 
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED) &&
		    (pSRB->MsgInBuf[2] == 3) && (pSRB->MsgCnt == 4)) {
		  /*
	   	   * is Wide data xfer Extended message :
	   	   * ======================================
	   	   * WIDE DATA TRANSFER REQUEST
   		   * ======================================
		   * byte 0 :  Extended message (01h)
		   * byte 1 :  Extended message length (02h)
		   * byte 2 :  WIDE DATA TRANSFER code (03h)
		   * byte 3 :  Transfer width exponent 
		   */
			pDCB = pSRB->pSRBDCB;
			pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_WIDE_NEGO);
			if ((pSRB->MsgInBuf[1] != 2)) {
			  /* Length is wrong, reject it  */
				pDCB->SyncMode &=
				  ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); 
				pSRB->MsgCnt = 1;
				pSRB->MsgInBuf[0] = MSG_REJECT_;
				trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL);
				*pscsi_status = PH_BUS_FREE; /* .. initial phase */
				/* it's important for atn stop */
				trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
				/*
				 * SCSI command
				 */
				trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
				return;
			}
			if (pDCB->SyncMode & WIDE_NEGO_ENABLE) {		
			  /* Do wide negoniation */
				if (pSRB->MsgInBuf[3] > 2) {
				  /* > 32 bit	*/
				  /* reject_msg: */
					pDCB->SyncMode &= 
					  ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); 
					pSRB->MsgCnt = 1;
					pSRB->MsgInBuf[0] = MSG_REJECT_;
					trm_reg_write16(DO_SETATN,
					    TRMREG_SCSI_CONTROL);
					*pscsi_status = PH_BUS_FREE; /* .. initial phase */
					/* it's important for atn stop */
					trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
					/*
					 * SCSI command
					 */
					trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
					return;
				}
				if (pSRB->MsgInBuf[3] == 2) {
					pSRB->MsgInBuf[3] = 1;
					/* do 16 bits	*/
				} else {
					if (!(pDCB->SyncMode 
					      & WIDE_NEGO_DONE)) {
						pSRB->SRBState &=
						  ~(SRB_DO_WIDE_NEGO+SRB_MSGIN);
						pDCB->SyncMode |= 
						  WIDE_NEGO_DONE;
						pDCB->SyncMode &=
						  ~(SYNC_NEGO_DONE |
						      EN_ATN_STOP |
						      WIDE_NEGO_ENABLE);
						if (pSRB->MsgInBuf[3] != 0) {
						  /* is Wide data xfer */
							pDCB->SyncPeriod |=
							  WIDE_SYNC;
							pDCB->tinfo.current.width 
							  = MSG_EXT_WDTR_BUS_16_BIT;
							pDCB->tinfo.goal.width
							  = MSG_EXT_WDTR_BUS_16_BIT;
						}
					}
				}
			} else
				pSRB->MsgInBuf[3] = 0;
			pSRB->SRBState |= SRB_MSGOUT;
			trm_reg_write16(DO_SETATN,TRMREG_SCSI_CONTROL);
			*pscsi_status = PH_BUS_FREE; /* .. initial phase */
			/* it's important for atn stop */
			trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
			/*
			 * SCSI command
			 */
			trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
			return;
		} else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED) &&
		    (pSRB->MsgInBuf[2] == 1) && (pSRB->MsgCnt == 5)) {
			/*
			 * is 8bit transfer Extended message :
			 * =================================
			 * SYNCHRONOUS DATA TRANSFER REQUEST
			 * =================================
			 * byte 0 :  Extended message (01h)
			 * byte 1 :  Extended message length (03)
			 * byte 2 :  SYNCHRONOUS DATA TRANSFER code (01h)
			 * byte 3 :  Transfer period factor 
			 * byte 4 :  REQ/ACK offset  
			 */
			pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_SYNC_NEGO);
			if ((pSRB->MsgInBuf[1] != 3) ||
			    (pSRB->MsgInBuf[2] != 1)) {
			  /* reject_msg: */
				pSRB->MsgCnt = 1;
				pSRB->MsgInBuf[0] = MSG_REJECT_;
				trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL);
				*pscsi_status = PH_BUS_FREE;
				/* .. initial phase */
				trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
				/* it's important for atn stop */
				/*
				 * SCSI cammand 
				 */
				trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
				return;
			} else if (!(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4])) {
				/* set async */
				pDCB = pSRB->pSRBDCB;
				/* disable sync & sync nego */
				pDCB->SyncMode &= 
				  ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE);
				pDCB->SyncPeriod = 0;
				pDCB->SyncOffset = 0;
				pDCB->tinfo.goal.period = 0;
				pDCB->tinfo.goal.offset = 0;
				pDCB->tinfo.current.period = 0;
				pDCB->tinfo.current.offset = 0;
				pDCB->tinfo.current.width = 
				  MSG_EXT_WDTR_BUS_8_BIT;
				/*               
				 *
				 *   program SCSI control register
				 *
				 */
				trm_reg_write8(pDCB->SyncPeriod,TRMREG_SCSI_SYNC);
				trm_reg_write8(pDCB->SyncOffset,TRMREG_SCSI_OFFSET);
				trm_SetXferRate(pACB,pSRB,pDCB);
				*pscsi_status = PH_BUS_FREE;
				/* .. initial phase */
				trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
				/* it's important for atn stop */
				/*
				 * SCSI cammand 
				 */
				trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
				return;
			} else {
				/* set sync */
				pDCB = pSRB->pSRBDCB;
				pDCB->SyncMode |= 
				  SYNC_NEGO_ENABLE+SYNC_NEGO_DONE;
				pDCB->MaxNegoPeriod = pSRB->MsgInBuf[3];
				/* Transfer period factor */
				pDCB->SyncOffset = pSRB->MsgInBuf[4]; 
				/* REQ/ACK offset */
				if (pACB->AdaptType == 1) {
					for(bIndex = 0; bIndex < 7; bIndex++) {
						if (pSRB->MsgInBuf[3] <=
					   dc395u2x_clock_period[bIndex]) {
				            pDCB->tinfo.goal.period =
						dc395u2x_tinfo_period[bIndex];
				            pDCB->tinfo.current.period =
						dc395u2x_tinfo_period[bIndex];
			                pDCB->tinfo.goal.offset = 
					    pDCB->SyncOffset;
					pDCB->tinfo.current.offset = 
					    pDCB->SyncOffset;
					pDCB->SyncPeriod |= (bIndex|LVDS_SYNC);
					break;
						}
					}
				} else {
					for(bIndex = 0; bIndex < 7; bIndex++) {
						if (pSRB->MsgInBuf[3] <=
						 dc395x_clock_period[bIndex]) {
						   pDCB->tinfo.goal.period =
						dc395x_tinfo_period[bIndex];
						   pDCB->tinfo.current.period =
						dc395x_tinfo_period[bIndex];
						   pDCB->tinfo.goal.offset =
						pDCB->SyncOffset;
						   pDCB->tinfo.current.offset =
					     	       pDCB->SyncOffset;
					     	   pDCB->SyncPeriod |=
				     		       (bIndex|ALT_SYNC);
			     			   break;
						}
					}
				}
				/*               
				 *
	 			 *   program SCSI control register
	 			 *
	 			 */
				trm_reg_write8(pDCB->SyncPeriod,
				    TRMREG_SCSI_SYNC);
				trm_reg_write8(pDCB->SyncOffset,
				    TRMREG_SCSI_OFFSET);
				trm_SetXferRate(pACB,pSRB,pDCB);
				*pscsi_status=PH_BUS_FREE;/*.. initial phase*/
				trm_reg_write16(DO_DATALATCH,TRMREG_SCSI_CONTROL);/* it's important for atn stop*/
	            /*
	            ** SCSI command 
	            */
				trm_reg_write8(SCMD_MSGACCEPT,TRMREG_SCSI_COMMAND);
				return;
			}
		}
	*pscsi_status = PH_BUS_FREE;
	/* .. initial phase */
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop */
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
	}
}

static void
trm_MsgInPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

	trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL);
	trm_reg_write32(1,TRMREG_SCSI_COUNTER);
	if (!(pSRB->SRBState & SRB_MSGIN)) {
		pSRB->SRBState &= SRB_DISCONNECT;
		pSRB->SRBState |= SRB_MSGIN;
	}
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop*/
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_FIFO_IN, TRMREG_SCSI_COMMAND);
}

static void
trm_Nop0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

}

static void
trm_Nop1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{

}

static void
trm_SetXferRate(PACB pACB,PSRB pSRB, PDCB pDCB)
{
	union ccb	*pccb;
	struct ccb_trans_settings neg;
	u_int16_t	cnt, i;
	u_int8_t	bval;
	PDCB		pDCBTemp;

	/*
	 * set all lun device's  period , offset
	 */
	TRM_DPRINTF("trm_SetXferRate\n");
	pccb = pSRB->pccb;
	memset(&neg, 0, sizeof (neg));
	neg.xport_specific.spi.sync_period = pDCB->tinfo.goal.period;
	neg.xport_specific.spi.sync_offset = pDCB->tinfo.goal.offset;
	neg.xport_specific.spi.valid =
	    CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
	xpt_setup_ccb(&neg.ccb_h, pccb->ccb_h.path, /* priority */1);
	xpt_async(AC_TRANSFER_NEG, pccb->ccb_h.path, &neg);
	if (!(pDCB->IdentifyMsg & 0x07)) {
		pDCBTemp = pACB->pLinkDCB;
		cnt = pACB->DeviceCnt;
		bval = pDCB->TargetID;
		for (i = 0; i < cnt; i++) {
			if (pDCBTemp->TargetID == bval) {
				pDCBTemp->SyncPeriod = pDCB->SyncPeriod;
				pDCBTemp->SyncOffset = pDCB->SyncOffset;
				pDCBTemp->SyncMode = pDCB->SyncMode;
			}
			pDCBTemp = pDCBTemp->pNextDCB;
		}
	}
	return;
}

/*
 * scsiiom		
 *            trm_Interrupt       
 *		        
 *
 *    ---SCSI bus phase
 *
 * 	PH_DATA_OUT	        0x00	 Data out phase	              
 * 	PH_DATA_IN	        0x01	 Data in phase	            
 * 	PH_COMMAND	        0x02	 Command phase	 
 * 	PH_STATUS	        0x03	 Status phase
 *	PH_BUS_FREE	        0x04	 Invalid phase used as bus free	
 * 	PH_BUS_FREE	        0x05	 Invalid phase used as bus free	
 * 	PH_MSG_OUT	        0x06	 Message out phase
 * 	PH_MSG_IN	        0x07	 Message in phase
 *
 */
static void 
trm_Disconnect(PACB pACB)
{
	PDCB		pDCB;
	PSRB		pSRB, psrb;
	u_int16_t	i,j, cnt;
	u_int		target_id,target_lun;
	
	TRM_DPRINTF("trm_Disconnect...............\n ");
	
       	pDCB = pACB->pActiveDCB;
	if (!pDCB) {
		TRM_DPRINTF(" Exception Disconnect DCB=NULL..............\n ");
		j = 400;
    		while (--j) 
			DELAY(1);
		/* 1 msec */
		trm_reg_write16((DO_CLRFIFO | DO_HWRESELECT),
		    TRMREG_SCSI_CONTROL);
		return;
	}
	pSRB = pDCB->pActiveSRB; 
	/* bug pSRB=0 */
	target_id  = pSRB->pccb->ccb_h.target_id;
	target_lun = pSRB->pccb->ccb_h.target_lun;
	TRM_DPRINTF(":pDCB->pActiveSRB= %8x \n ",(u_int) pDCB->pActiveSRB);
	pACB->pActiveDCB = 0;
	pSRB->ScsiPhase = PH_BUS_FREE; 
	/* SCSI bus free Phase */
	trm_reg_write16((DO_CLRFIFO | DO_HWRESELECT), TRMREG_SCSI_CONTROL);
	if (pSRB->SRBState & SRB_UNEXPECT_RESEL) {
		pSRB->SRBState = 0;
		trm_DoWaitingSRB(pACB);
	} else if (pSRB->SRBState & SRB_ABORT_SENT) {
		pDCB->DCBFlag = 0;
		cnt = pDCB->GoingSRBCnt;
		pDCB->GoingSRBCnt = 0;
		pSRB = pDCB->pGoingSRB;
		for (i = 0; i < cnt; i++) {
			psrb = pSRB->pNextSRB;
			pSRB->pNextSRB = pACB->pFreeSRB;
			pACB->pFreeSRB = pSRB;
			pSRB = psrb;
		}
		pDCB->pGoingSRB = 0;
		trm_DoWaitingSRB(pACB);
	} else {
		if ((pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || 
		    !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED))) {
		  /* Selection time out */
			if (!(pACB->scan_devices[target_id][target_lun]) &&
			    pSRB->CmdBlock[0] != 0x00 && /* TEST UNIT READY */
			    pSRB->CmdBlock[0] != INQUIRY) {
				pSRB->SRBState = SRB_READY;
				trm_RewaitSRB(pDCB, pSRB);
			} else {
				pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
				goto  disc1;
			}
		} else if (pSRB->SRBState & SRB_DISCONNECT) {
			/*
			 * SRB_DISCONNECT
			 */
			trm_DoWaitingSRB(pACB);
		} else if (pSRB->SRBState & SRB_COMPLETED) {
disc1:
		  /*
		   * SRB_COMPLETED
		   */
			pDCB->pActiveSRB = 0;
			pSRB->SRBState = SRB_FREE;
			trm_SRBdone(pACB, pDCB, pSRB);
		}
	}
	return;
}

static void
trm_Reselect(PACB pACB)
{
	PDCB		pDCB;
	PSRB		pSRB;
	u_int16_t	RselTarLunId;

	TRM_DPRINTF("trm_Reselect................. \n");
	pDCB = pACB->pActiveDCB;
	if (pDCB) {
	  /* Arbitration lost but Reselection win */
		pSRB = pDCB->pActiveSRB;
		pSRB->SRBState = SRB_READY;
		trm_RewaitSRB(pDCB, pSRB);
	}
	/* Read Reselected Target Id and LUN */
	RselTarLunId = trm_reg_read16(TRMREG_SCSI_TARGETID) & 0x1FFF;
	pDCB = pACB->pLinkDCB;
	while (RselTarLunId != *((u_int16_t *) &pDCB->TargetID)) {
	  /* get pDCB of the reselect id */
		pDCB = pDCB->pNextDCB;
	}

	pACB->pActiveDCB = pDCB;
	if (pDCB->SyncMode & EN_TAG_QUEUING) {
		pSRB = &pACB->TmpSRB;
		pDCB->pActiveSRB = pSRB;
	} else {
		pSRB = pDCB->pActiveSRB;
		if (!pSRB || !(pSRB->SRBState & SRB_DISCONNECT)) {
		  /*
	   	   * abort command
   		   */
			pSRB = &pACB->TmpSRB;
			pSRB->SRBState = SRB_UNEXPECT_RESEL;
			pDCB->pActiveSRB = pSRB;
			trm_EnableMsgOutAbort1(pACB, pSRB);
		} else {
			if (pDCB->DCBFlag & ABORT_DEV_) {
				pSRB->SRBState = SRB_ABORT_SENT;
				trm_EnableMsgOutAbort1(pACB, pSRB);
			} else 
				pSRB->SRBState = SRB_DATA_XFER;
		}
	}
	pSRB->ScsiPhase = PH_BUS_FREE;
	/* SCSI bus free Phase */
	/* 
	 * Program HA ID, target ID, period and offset
	 */
	trm_reg_write8((u_int8_t) RselTarLunId,TRMREG_SCSI_TARGETID);
	/* target ID */
	trm_reg_write8(pACB->AdaptSCSIID,TRMREG_SCSI_HOSTID);
	/* host   ID */
	trm_reg_write8(pDCB->SyncPeriod,TRMREG_SCSI_SYNC);
	/* period    */
	trm_reg_write8(pDCB->SyncOffset,TRMREG_SCSI_OFFSET); 
	/* offset    */
	trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
	/* it's important for atn stop*/
	/*
	 * SCSI cammand 
	 */
	trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
	/* to rls the /ACK signal */
}

static void
trm_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB)
{
	PSRB			psrb;
	u_int8_t		bval, bval1,status;
	union ccb		*pccb;
	struct ccb_scsiio	*pcsio;
	PSCSI_INQDATA		ptr;
	int			intflag;
	u_int			target_id,target_lun;
	PDCB			pTempDCB;

	pccb  = pSRB->pccb;
	if (pccb == NULL)
		return;
	pcsio = &pccb->csio;
	target_id  = pSRB->pccb->ccb_h.target_id;
	target_lun = pSRB->pccb->ccb_h.target_lun;
	if ((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		bus_dmasync_op_t op;
		if ((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
			op = BUS_DMASYNC_POSTREAD;
		else
			op = BUS_DMASYNC_POSTWRITE;
		bus_dmamap_sync(pACB->buffer_dmat, pSRB->dmamap, op);
		bus_dmamap_unload(pACB->buffer_dmat, pSRB->dmamap);
	}
    	/*
	 *
	 * target status
	 *
	 */
	status = pSRB->TargetStatus;
	pcsio->scsi_status=SCSI_STAT_GOOD;
	pccb->ccb_h.status = CAM_REQ_CMP;
	if (pSRB->SRBFlag & AUTO_REQSENSE) {
	  /* 
   	   * status of auto request sense 
	   */
		pSRB->SRBFlag &= ~AUTO_REQSENSE;
		pSRB->AdaptStatus = 0;
		pSRB->TargetStatus = SCSI_STATUS_CHECK_COND;
		
		if (status == SCSI_STATUS_CHECK_COND) {
			pccb->ccb_h.status = CAM_SEL_TIMEOUT;
			goto ckc_e;
		}
		*((u_long *) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
		*((u_long *) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
		pSRB->SRBTotalXferLength = pSRB->Segment1[1];
		pSRB->pSRBSGL->address = pSRB->SgSenseTemp.address;
		pSRB->pSRBSGL->length = pSRB->SgSenseTemp.length;
		pcsio->scsi_status = SCSI_STATUS_CHECK_COND;
		bcopy(trm_get_sense_buf(pACB, pSRB), &pcsio->sense_data,
		    pcsio->sense_len);
		pcsio->ccb_h.status = CAM_SCSI_STATUS_ERROR 
		    | CAM_AUTOSNS_VALID;
		goto ckc_e;
	}
	/*
	 * target status
	 */
	if (status) {
		if (status == SCSI_STATUS_CHECK_COND) {
			if ((pcsio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
			  TRM_DPRINTF("trm_RequestSense..................\n");
			  trm_RequestSense(pACB, pDCB, pSRB);
			  return;
			}
			pcsio->scsi_status = SCSI_STATUS_CHECK_COND;
			pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
			goto ckc_e;
		} else if (status == SCSI_STAT_QUEUEFULL) {
			bval = (u_int8_t) pDCB->GoingSRBCnt;
			bval--;
			pDCB->MaxActiveCommandCnt = bval;
			trm_RewaitSRB(pDCB, pSRB);
			pSRB->AdaptStatus = 0;
			pSRB->TargetStatus = 0;
			return;
		} else if (status == SCSI_STAT_SEL_TIMEOUT) {
			pSRB->AdaptStatus  = H_SEL_TIMEOUT;
			pSRB->TargetStatus = 0;
			pcsio->scsi_status = SCSI_STAT_SEL_TIMEOUT;
			pccb->ccb_h.status = CAM_SEL_TIMEOUT;
		} else if (status == SCSI_STAT_BUSY) {
			TRM_DPRINTF("trm: target busy at %s %d\n",
				__FILE__, __LINE__);
			pcsio->scsi_status = SCSI_STAT_BUSY;
			pccb->ccb_h.status = CAM_SCSI_BUSY;
			return;
		  /* The device busy, try again later?	  */
		} else if (status == SCSI_STAT_RESCONFLICT) {
			TRM_DPRINTF("trm: target reserved at %s %d\n",
				__FILE__, __LINE__);
			pcsio->scsi_status = SCSI_STAT_RESCONFLICT;
			pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;	/*XXX*/
			return;
		} else {
			pSRB->AdaptStatus = 0;
			if (pSRB->RetryCnt) {
				pSRB->RetryCnt--;
				pSRB->TargetStatus = 0;
				pSRB->SRBSGIndex = 0;
				if (trm_StartSCSI(pACB, pDCB, pSRB)) {
				  /* 
				   * If trm_StartSCSI return 1 :
				   * current interrupt status is interrupt 
				   * disreenable 
				   * It's said that SCSI processor has more 
				   * one SRB need to do
				   */
					trm_RewaitSRB(pDCB, pSRB);
				}
				return;
			} else {
        			TRM_DPRINTF("trm: driver stuffup at %s %d\n",
					__FILE__, __LINE__);
		      		pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
			}
		}
	} else {
        /* 
 	 * process initiator status..........................
	 * Adapter (initiator) status
	 */
		status = pSRB->AdaptStatus;
		if (status & H_OVER_UNDER_RUN) {
			pSRB->TargetStatus = 0;
			pccb->ccb_h.status = CAM_DATA_RUN_ERR;
			/* Illegal length (over/under run) */
		} else if (pSRB->SRBStatus & PARITY_ERROR) {
			TRM_DPRINTF("trm: driver stuffup %s %d\n",
				__FILE__, __LINE__);
			pDCB->tinfo.goal.period = 0;
			pDCB->tinfo.goal.offset = 0;
			/* Driver failed to perform operation */
			pccb->ccb_h.status = CAM_UNCOR_PARITY;
		} else {
		  /* no error */
			pSRB->AdaptStatus = 0;
			pSRB->TargetStatus = 0;
			pccb->ccb_h.status = CAM_REQ_CMP;
			/* there is no error, (sense is invalid) */
		}
	}
ckc_e:
	if (pACB->scan_devices[target_id][target_lun]) {
	  /*
	   *   if SCSI command in "scan devices" duty
	   */
		if (pSRB->CmdBlock[0] == TEST_UNIT_READY) 
			pACB->scan_devices[target_id][target_lun] = 0;
		/* SCSI command phase :test unit ready */
		else if (pSRB->CmdBlock[0] == INQUIRY) {
		  /* 
		   * SCSI command phase :inquiry scsi device data 
		   * (type,capacity,manufacture.... 
		   */
			if (pccb->ccb_h.status == CAM_SEL_TIMEOUT)
				goto NO_DEV;
			ptr = (PSCSI_INQDATA) pcsio->data_ptr;
			/* page fault */
			TRM_DPRINTF("trm_SRBdone..PSCSI_INQDATA:%2x \n",
			    ptr->DevType);
		  	bval1 = ptr->DevType & SCSI_DEVTYPE; 
			if (bval1 == SCSI_NODEV) {
NO_DEV:
	  			TRM_DPRINTF("trm_SRBdone NO Device:target_id= %d ,target_lun= %d \n",
				    target_id,
				    target_lun);
		      		intflag = splcam();
				pACB->scan_devices[target_id][target_lun] = 0;
				/* no device set scan device flag =0*/
				/* pDCB Q link */
				/* move the head of DCB to tempDCB*/
				pTempDCB=pACB->pLinkDCB;  
				/* search current DCB for pass link */
				while (pTempDCB->pNextDCB != pDCB) {
					pTempDCB = pTempDCB->pNextDCB;
				}
				/*
				 * when the current DCB found than connect 
				 * current DCB tail 
				 */
				/* to the DCB tail that before current DCB */
				pTempDCB->pNextDCB = pDCB->pNextDCB;
				/*
				 * if there was only one DCB ,connect his tail
				 * to his head 
				 */
				if (pACB->pLinkDCB == pDCB)
					pACB->pLinkDCB = pTempDCB->pNextDCB;
				if (pACB->pDCBRunRobin == pDCB)
					pACB->pDCBRunRobin = pTempDCB->pNextDCB;
				pDCB->DCBstatus &= ~DS_IN_QUEUE;
				pACB->DeviceCnt--;
				if (pACB->DeviceCnt == 0) {
					pACB->pLinkDCB = NULL;
					pACB->pDCBRunRobin = NULL;
				}
				splx(intflag);
			} else { 
#ifdef trm_DEBUG1
				int j;
				for (j = 0; j < 28; j++) {
					TRM_DPRINTF("ptr=%2x ", 
						((u_int8_t *)ptr)[j]);
				}
#endif
	      			pDCB->DevType = bval1;
				if (bval1 == SCSI_DASD ||
				    bval1 == SCSI_OPTICAL) {
					if ((((ptr->Vers & 0x07) >= 2) ||
					      ((ptr->RDF & 0x0F) == 2)) && 
					    (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
					    (pDCB->DevMode & TAG_QUEUING_) &&
					    (pDCB->DevMode & EN_DISCONNECT_)) {
						if (pDCB->DevMode &
						    TAG_QUEUING_) {
							pDCB->
							    MaxActiveCommandCnt = 
							  pACB->TagMaxNum;
							pDCB->SyncMode |= 
							  EN_TAG_QUEUING;
							pDCB->tinfo.disc_tag |=
							  TRM_CUR_TAGENB;
						} else {
							pDCB->SyncMode |= 
							  EN_ATN_STOP;
							pDCB->tinfo.disc_tag &=
							  ~TRM_CUR_TAGENB;
						}
					}
				}
			}
			/* pSRB->CmdBlock[0] == INQUIRY */
		}
		/* pACB->scan_devices[target_id][target_lun] */
	}
    	intflag = splcam();
	/*  ReleaseSRB(pDCB, pSRB); */
	if (pSRB == pDCB->pGoingSRB)
		pDCB->pGoingSRB = pSRB->pNextSRB;
	else {
		psrb = pDCB->pGoingSRB;
		while (psrb->pNextSRB != pSRB) {
			psrb = psrb->pNextSRB;
		}
		psrb->pNextSRB = pSRB->pNextSRB;
		if (pSRB == pDCB->pGoingLastSRB) {
			pDCB->pGoingLastSRB = psrb;
		}
	}
	pSRB->pNextSRB = pACB->pFreeSRB;
	pACB->pFreeSRB = pSRB;
	pDCB->GoingSRBCnt--;
	trm_DoWaitingSRB(pACB);

	splx(intflag);
	/*  Notify cmd done */
	xpt_done (pccb);
}

static void
trm_DoingSRB_Done(PACB pACB)
{
	PDCB		pDCB, pdcb;
	PSRB		psrb, psrb2;
	u_int16_t	cnt, i;
	union ccb 	*pccb;

	pDCB = pACB->pLinkDCB;
	if (pDCB == NULL) 
  		return;
	pdcb = pDCB;
    	do {
		cnt = pdcb->GoingSRBCnt;
		psrb = pdcb->pGoingSRB;
		for (i = 0; i < cnt; i++) {
			psrb2 = psrb->pNextSRB;
		    	pccb = psrb->pccb;
			pccb->ccb_h.status = CAM_SEL_TIMEOUT;
			/*  ReleaseSRB(pDCB, pSRB); */
			psrb->pNextSRB = pACB->pFreeSRB;
			pACB->pFreeSRB = psrb;
			xpt_done(pccb);
			psrb  = psrb2;
		}
		pdcb->GoingSRBCnt = 0;
		pdcb->pGoingSRB = NULL;
		pdcb = pdcb->pNextDCB;
	}
	while (pdcb != pDCB);
}

static void 
trm_ResetSCSIBus(PACB pACB)
{
	int	intflag;

	intflag = splcam();
    	pACB->ACBFlag |= RESET_DEV;

	trm_reg_write16(DO_RSTSCSI,TRMREG_SCSI_CONTROL);
	while (!(trm_reg_read16(TRMREG_SCSI_INTSTATUS) & INT_SCSIRESET));
	splx(intflag);
	return;
}

static void 
trm_ScsiRstDetect(PACB pACB)
{
	int	intflag;
	u_long	wlval;

	TRM_DPRINTF("trm_ScsiRstDetect \n");
	wlval = 1000;
	while (--wlval)
		DELAY(1000);
	intflag = splcam();
    	trm_reg_write8(STOPDMAXFER,TRMREG_DMA_CONTROL);

	trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL);

	if (pACB->ACBFlag & RESET_DEV)
		pACB->ACBFlag |= RESET_DONE;
	else {
		pACB->ACBFlag |= RESET_DETECT;
		trm_ResetDevParam(pACB);
		/*	trm_DoingSRB_Done(pACB); ???? */
		trm_RecoverSRB(pACB);
		pACB->pActiveDCB = NULL;
		pACB->ACBFlag = 0;
		trm_DoWaitingSRB(pACB);
	}
	splx(intflag);
    	return;
}

static void
trm_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB)	
{
	union ccb		*pccb;
	struct ccb_scsiio	*pcsio;

	pccb  = pSRB->pccb;
	pcsio = &pccb->csio;

	pSRB->SRBFlag |= AUTO_REQSENSE;
	pSRB->Segment0[0] = *((u_long *) &(pSRB->CmdBlock[0]));
	pSRB->Segment0[1] = *((u_long *) &(pSRB->CmdBlock[4]));
	pSRB->Segment1[0] = (u_long) ((pSRB->ScsiCmdLen << 8) + 
	    pSRB->SRBSGCount);
	pSRB->Segment1[1] = pSRB->SRBTotalXferLength; /* ?????????? */

	/* $$$$$$ Status of initiator/target $$$$$$$$ */
	pSRB->AdaptStatus = 0;
	pSRB->TargetStatus = 0;
	/* $$$$$$ Status of initiator/target $$$$$$$$ */
	
	pSRB->SRBTotalXferLength = sizeof(pcsio->sense_data);
	pSRB->SgSenseTemp.address = pSRB->pSRBSGL->address;
	pSRB->SgSenseTemp.length  = pSRB->pSRBSGL->length;
	pSRB->pSRBSGL->address = trm_get_sense_bufaddr(pACB, pSRB);
	pSRB->pSRBSGL->length = (u_long) sizeof(struct scsi_sense_data);
	pSRB->SRBSGCount = 1;
	pSRB->SRBSGIndex = 0;
	
	*((u_long *) &(pSRB->CmdBlock[0])) = 0x00000003;
	pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
	*((u_int16_t *) &(pSRB->CmdBlock[4])) = pcsio->sense_len;
	pSRB->ScsiCmdLen = 6;
	
	if (trm_StartSCSI(pACB, pDCB, pSRB))
	   /* 
	    * If trm_StartSCSI return 1 :
	    * current interrupt status is interrupt disreenable 
	    * It's said that SCSI processor has more one SRB need to do
	    */
		trm_RewaitSRB(pDCB, pSRB);
}

static void 
trm_EnableMsgOutAbort2(PACB pACB, PSRB pSRB)
{

	pSRB->MsgCnt = 1;
	trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL);
}

static void
trm_EnableMsgOutAbort1(PACB pACB, PSRB pSRB)
{
  
	pSRB->MsgOutBuf[0] = MSG_ABORT;
	trm_EnableMsgOutAbort2(pACB, pSRB);
}

static void
trm_initDCB(PACB pACB, PDCB pDCB, u_int16_t unit,u_int32_t i,u_int32_t j)
{
	PNVRAMTYPE 	pEEpromBuf;
	u_int8_t	bval,PeriodIndex;
	u_int		target_id,target_lun;
	PDCB		pTempDCB;
	int		intflag;
    
    	target_id  = i;
	target_lun = j;

	/*
	 *  Using the lun 0 device to init other DCB first, if the device 
	 *  has been initialized.
	 *  I don't want init sync arguments one by one, it is the same.
	 */
	if (target_lun != 0 && 
	    (pACB->DCBarray[target_id][0].DCBstatus & DS_IN_QUEUE))
		bcopy(&pACB->DCBarray[target_id][0], pDCB, 
		    sizeof(TRM_DCB));
	intflag = splcam();
	if (pACB->pLinkDCB == 0) {
		pACB->pLinkDCB = pDCB;
		/* 
		 * RunRobin impersonate the role 
		 * that let each device had good proportion 
		 * about SCSI command proceeding 
		 */
		pACB->pDCBRunRobin = pDCB;
		pDCB->pNextDCB = pDCB;
	} else {
		pTempDCB=pACB->pLinkDCB;
		/* search the last nod of DCB link */
		while (pTempDCB->pNextDCB != pACB->pLinkDCB)
			pTempDCB = pTempDCB->pNextDCB;
		/* connect current DCB with last DCB tail */
		pTempDCB->pNextDCB = pDCB;
		/* connect current DCB tail to this DCB Q head */
		pDCB->pNextDCB=pACB->pLinkDCB;
	}
	splx(intflag);

	pACB->DeviceCnt++;
	pDCB->TargetID = target_id;
	pDCB->TargetLUN =  target_lun;
	pDCB->pWaitingSRB = NULL;
	pDCB->pGoingSRB = NULL;
	pDCB->GoingSRBCnt = 0;
	pDCB->pActiveSRB = NULL;
	pDCB->MaxActiveCommandCnt = 1;
	pDCB->DCBFlag = 0;
	pDCB->DCBstatus |= DS_IN_QUEUE;
	/* $$$$$$$ */
	pEEpromBuf = &trm_eepromBuf[unit];
	pDCB->DevMode = pEEpromBuf->NvramTarget[target_id].NvmTarCfg0;
	pDCB->AdpMode = pEEpromBuf->NvramChannelCfg;
	/* $$$$$$$ */
	/* 
	 * disconnect enable ?
	 */
	if (pDCB->DevMode & NTC_DO_DISCONNECT) {
		bval = 0xC0;
		pDCB->tinfo.disc_tag |= TRM_USR_DISCENB ;
	} else {
		bval = 0x80;
		pDCB->tinfo.disc_tag &= ~(TRM_USR_DISCENB);
	}
	bval |= target_lun;
	pDCB->IdentifyMsg = bval;
	if (target_lun != 0 && 
	    (pACB->DCBarray[target_id][0].DCBstatus & DS_IN_QUEUE))
		return;
	/* $$$$$$$ */
	/*
	 * tag Qing enable ?
	 */
	if (pDCB->DevMode & TAG_QUEUING_) {
		pDCB->tinfo.disc_tag |= TRM_USR_TAGENB ;
	} else
		pDCB->tinfo.disc_tag &= ~(TRM_USR_TAGENB);
	/* $$$$$$$ */
	/*
	 * wide nego ,sync nego enable ?
	 */
	pDCB->SyncPeriod = 0;
	pDCB->SyncOffset = 0;
	PeriodIndex = pEEpromBuf->NvramTarget[target_id].NvmTarPeriod & 0x07;
	if (pACB->AdaptType==1) {/* is U2? */
	    pDCB->MaxNegoPeriod=dc395u2x_clock_period[ PeriodIndex ];
	    pDCB->tinfo.user.period=pDCB->MaxNegoPeriod;
	    pDCB->tinfo.user.offset=(pDCB->SyncMode & SYNC_NEGO_ENABLE) ? 31 : 0;
	} else {
        pDCB->MaxNegoPeriod=dc395x_clock_period[ PeriodIndex ];
	    pDCB->tinfo.user.period=pDCB->MaxNegoPeriod;
	    pDCB->tinfo.user.offset=(pDCB->SyncMode & SYNC_NEGO_ENABLE) ? 15 : 0;
	}
	pDCB->SyncMode = 0;
	if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && 
	    (pACB->Config & HCC_WIDE_CARD))
		pDCB->SyncMode |= WIDE_NEGO_ENABLE;
	/* enable wide nego */
   	if (pDCB->DevMode & NTC_DO_SYNC_NEGO)
		pDCB->SyncMode |= SYNC_NEGO_ENABLE;
	/* enable sync nego */
	/* $$$$$$$ */
	/*
	 *	Fill in tinfo structure.
	 */
	pDCB->tinfo.user.width  = (pDCB->SyncMode & WIDE_NEGO_ENABLE) ? 
	  MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT;

	pDCB->tinfo.current.period = 0;
	pDCB->tinfo.current.offset = 0;
	pDCB->tinfo.current.width = MSG_EXT_WDTR_BUS_8_BIT;
}

static void
trm_srbmapSG(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
	PSRB pSRB;

	pSRB=(PSRB) arg;
	pSRB->SRBSGPhyAddr=segs->ds_addr;
	return;
}

static void
trm_destroySRB(PACB pACB)
{
	PSRB pSRB;

	pSRB = pACB->pFreeSRB;
	while (pSRB) {
		if (pSRB->sg_dmamap) {
			bus_dmamap_unload(pACB->sg_dmat, pSRB->sg_dmamap);
			bus_dmamem_free(pACB->sg_dmat, pSRB->pSRBSGL,
			    pSRB->sg_dmamap);
			bus_dmamap_destroy(pACB->sg_dmat, pSRB->sg_dmamap);
		}
		if (pSRB->dmamap)
			bus_dmamap_destroy(pACB->buffer_dmat, pSRB->dmamap);
		pSRB = pSRB->pNextSRB;
	}
}

static int
trm_initSRB(PACB pACB)
{
    	u_int16_t    i;
	PSRB    pSRB;
	int error;

	for (i = 0; i < TRM_MAX_SRB_CNT; i++) {
	       	pSRB = (PSRB)&pACB->pFreeSRB[i];

		if (bus_dmamem_alloc(pACB->sg_dmat, (void **)&pSRB->pSRBSGL,
		    BUS_DMA_NOWAIT, &pSRB->sg_dmamap) !=0 ) {
			return ENXIO;
		}
		bus_dmamap_load(pACB->sg_dmat, pSRB->sg_dmamap, pSRB->pSRBSGL,
		    TRM_MAX_SG_LISTENTRY * sizeof(SGentry),
		    trm_srbmapSG, pSRB, /*flags*/0);
		if (i != TRM_MAX_SRB_CNT - 1) {
			/*
			 * link all SRB 
			 */
			pSRB->pNextSRB = &pACB->pFreeSRB[i+1];
		} else {
			/*
			 * load NULL to NextSRB of the last SRB
			 */
			pSRB->pNextSRB = NULL;
		}
		pSRB->TagNumber = i;

		/*
		 * Create the dmamap.  This is no longer optional!
		 */
		if ((error = bus_dmamap_create(pACB->buffer_dmat, 0,
					       &pSRB->dmamap)) != 0)
			return (error);

	}
	return (0);
}




static void
trm_initACB(PACB pACB, u_int8_t adaptType, u_int16_t unit)
{
	PNVRAMTYPE	pEEpromBuf;
    
	pEEpromBuf = &trm_eepromBuf[unit];
	pACB->max_id = 15;
	
	if (pEEpromBuf->NvramChannelCfg & NAC_SCANLUN)
  		pACB->max_lun = 7;
	else
		pACB->max_lun = 0;

	TRM_DPRINTF("trm: pACB->max_id= %d pACB->max_lun= %d \n",
	    pACB->max_id, pACB->max_lun);
	pACB->pLinkDCB = NULL;
	pACB->pDCBRunRobin = NULL;
	pACB->pActiveDCB = NULL;
	pACB->AdapterUnit = (u_int8_t)unit;
	pACB->AdaptSCSIID = pEEpromBuf->NvramScsiId;
	pACB->AdaptSCSILUN = 0;
	pACB->DeviceCnt = 0;
	pACB->AdaptType = adaptType; 
	pACB->TagMaxNum = 2 << pEEpromBuf->NvramMaxTag;
	pACB->ACBFlag = 0;
	return;
}

static void
NVRAM_trm_write_all(PNVRAMTYPE pEEpromBuf,PACB pACB)
{
	u_int8_t	*bpEeprom = (u_int8_t *) pEEpromBuf;
	u_int8_t	bAddr;

	/* Enable SEEPROM */
	trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) | EN_EEPROM),
	    TRMREG_GEN_CONTROL);
	/*
	 * Write enable
	 */
	NVRAM_trm_write_cmd(pACB, 0x04, 0xFF);
	trm_reg_write8(0, TRMREG_GEN_NVRAM);
	NVRAM_trm_wait_30us(pACB);
	for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++) { 
		NVRAM_trm_set_data(pACB, bAddr, *bpEeprom);
	}
	/* 
	 * Write disable
	 */
	NVRAM_trm_write_cmd(pACB, 0x04, 0x00);
	trm_reg_write8(0 , TRMREG_GEN_NVRAM);
	NVRAM_trm_wait_30us(pACB);
	/* Disable SEEPROM */
	trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) & ~EN_EEPROM),
	    TRMREG_GEN_CONTROL);
	return;
}

static void
NVRAM_trm_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData)
{
	int		i;
	u_int8_t	bSendData;
	/* 
	 * Send write command & address	
	 */
	
	NVRAM_trm_write_cmd(pACB, 0x05, bAddr);
	/* 
	 * Write data 
	 */
	for (i = 0; i < 8; i++, bData <<= 1) {
		bSendData = NVR_SELECT;
		if (bData & 0x80)
		  /* Start from bit 7	*/
			bSendData |= NVR_BITOUT;
		trm_reg_write8(bSendData , TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
		trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
	}
	trm_reg_write8(NVR_SELECT , TRMREG_GEN_NVRAM);
	NVRAM_trm_wait_30us(pACB);
	/*
	 * Disable chip select 
	 */
	trm_reg_write8(0 , TRMREG_GEN_NVRAM);
	NVRAM_trm_wait_30us(pACB);
	trm_reg_write8(NVR_SELECT ,TRMREG_GEN_NVRAM);
	NVRAM_trm_wait_30us(pACB);
	/* 
	 * Wait for write ready	
	 */
	while (1) {
		trm_reg_write8((NVR_SELECT | NVR_CLOCK), TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
		trm_reg_write8(NVR_SELECT, TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
		if (trm_reg_read8(TRMREG_GEN_NVRAM) & NVR_BITIN) {
			break;
		}
	}
	/* 
	 * Disable chip select 
	 */
	trm_reg_write8(0, TRMREG_GEN_NVRAM);
	return;
}

static void 
NVRAM_trm_read_all(PNVRAMTYPE pEEpromBuf, PACB pACB)
{
	u_int8_t	*bpEeprom = (u_int8_t*) pEEpromBuf;
	u_int8_t	bAddr;
    
	/*
	 * Enable SEEPROM 
	 */
	trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) | EN_EEPROM),
	    TRMREG_GEN_CONTROL);
	for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
		*bpEeprom = NVRAM_trm_get_data(pACB, bAddr);
	/* 
	 * Disable SEEPROM 
	 */
	trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) & ~EN_EEPROM),
	    TRMREG_GEN_CONTROL);
	return;
}

static u_int8_t
NVRAM_trm_get_data(PACB pACB, u_int8_t bAddr)
{
	int		i;
	u_int8_t	bReadData, bData = 0;
	/* 
	* Send read command & address
	*/
	
	NVRAM_trm_write_cmd(pACB, 0x06, bAddr);
				
	for (i = 0; i < 8; i++) {
	  /* 
	   * Read data
	   */
		trm_reg_write8((NVR_SELECT | NVR_CLOCK) , TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
		trm_reg_write8(NVR_SELECT , TRMREG_GEN_NVRAM);
		/* 
		 * Get data bit while falling edge 
		 */
		bReadData = trm_reg_read8(TRMREG_GEN_NVRAM);
		bData <<= 1;
		if (bReadData & NVR_BITIN) {
			bData |= 1;
		}
		NVRAM_trm_wait_30us(pACB);
	}
	/* 
	 * Disable chip select 
	 */
	trm_reg_write8(0, TRMREG_GEN_NVRAM);
	return (bData);
}

static void
NVRAM_trm_wait_30us(PACB pACB)
{
  
	/*    ScsiPortStallExecution(30);	 wait 30 us	*/
	trm_reg_write8(5, TRMREG_GEN_TIMER);
	while (!(trm_reg_read8(TRMREG_GEN_STATUS) & GTIMEOUT));
	return;
}

static void
NVRAM_trm_write_cmd(PACB pACB, u_int8_t bCmd, u_int8_t bAddr)
{
	int		i;
	u_int8_t	bSendData;
					
    	for (i = 0; i < 3; i++, bCmd <<= 1) {
	  /* 
   	   * Program SB+OP code		
   	   */
     		bSendData = NVR_SELECT;
		if (bCmd & 0x04)	
			bSendData |= NVR_BITOUT;
		/* start from bit 2 */
		trm_reg_write8(bSendData, TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
		trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
	}	
	for (i = 0; i < 7; i++, bAddr <<= 1) {
	  /* 
	   * Program address		
	   */
		bSendData = NVR_SELECT;
		if (bAddr & 0x40)	
		  /* Start from bit 6	*/
			bSendData |= NVR_BITOUT;
		trm_reg_write8(bSendData , TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
		trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM);
		NVRAM_trm_wait_30us(pACB);
	}
	trm_reg_write8(NVR_SELECT, TRMREG_GEN_NVRAM);
	NVRAM_trm_wait_30us(pACB);
}

static void
trm_check_eeprom(PNVRAMTYPE pEEpromBuf, PACB pACB)
{
	u_int16_t	*wpEeprom = (u_int16_t *) pEEpromBuf;
	u_int16_t	wAddr, wCheckSum;
	u_long	dAddr, *dpEeprom;

	NVRAM_trm_read_all(pEEpromBuf,pACB);
	wCheckSum = 0;
	for (wAddr = 0, wpEeprom = (u_int16_t *) pEEpromBuf;
	    wAddr < 64; wAddr++, wpEeprom++) {
		wCheckSum += *wpEeprom;
	}
	if (wCheckSum != 0x1234) {
	  /* 
   	   * Checksum error, load default	
	   */
		pEEpromBuf->NvramSubVendorID[0]	= (u_int8_t) PCI_Vendor_ID_TEKRAM;
		pEEpromBuf->NvramSubVendorID[1]	=
		  (u_int8_t) (PCI_Vendor_ID_TEKRAM >> 8);
		pEEpromBuf->NvramSubSysID[0] = (u_int8_t) PCI_Device_ID_TRM_S1040;
		pEEpromBuf->NvramSubSysID[1] = 
		  (u_int8_t) (PCI_Device_ID_TRM_S1040 >> 8);
		pEEpromBuf->NvramSubClass = 0x00;
		pEEpromBuf->NvramVendorID[0] = (u_int8_t) PCI_Vendor_ID_TEKRAM;
		pEEpromBuf->NvramVendorID[1] =
		  (u_int8_t) (PCI_Vendor_ID_TEKRAM >> 8);
		pEEpromBuf->NvramDeviceID[0] = (u_int8_t) PCI_Device_ID_TRM_S1040;
		pEEpromBuf->NvramDeviceID[1] = 
		  (u_int8_t) (PCI_Device_ID_TRM_S1040 >> 8);
		pEEpromBuf->NvramReserved = 0x00;

		for (dAddr = 0, dpEeprom = (u_long *) pEEpromBuf->NvramTarget;
		    dAddr < 16; dAddr++, dpEeprom++) {
			*dpEeprom = 0x00000077;
			/* NvmTarCfg3,NvmTarCfg2,NvmTarPeriod,NvmTarCfg0 */
		}

		*dpEeprom++ = 0x04000F07;
		/* NvramMaxTag,NvramDelayTime,NvramChannelCfg,NvramScsiId */
		*dpEeprom++ = 0x00000015;
		/* NvramReserved1,NvramBootLun,NvramBootTarget,NvramReserved0 */
		for (dAddr = 0; dAddr < 12; dAddr++, dpEeprom++)
			*dpEeprom = 0x00;
		pEEpromBuf->NvramCheckSum = 0x00;
		for (wAddr = 0, wCheckSum = 0, wpEeprom = (u_int16_t *) pEEpromBuf;
		    wAddr < 63; wAddr++, wpEeprom++)
	      		wCheckSum += *wpEeprom;
		*wpEeprom = 0x1234 - wCheckSum;
		NVRAM_trm_write_all(pEEpromBuf,pACB);
	}
	return;
}
static int
trm_initAdapter(PACB pACB, u_int16_t unit)
{
	PNVRAMTYPE	pEEpromBuf;
	u_int16_t	wval;
	u_int8_t	bval;

	pEEpromBuf = &trm_eepromBuf[unit];

	/* 250ms selection timeout */
	trm_reg_write8(SEL_TIMEOUT, TRMREG_SCSI_TIMEOUT);
	/* Mask all the interrupt */
	trm_reg_write8(0x00, TRMREG_DMA_INTEN);    
	trm_reg_write8(0x00, TRMREG_SCSI_INTEN);     
	/* Reset SCSI module */
	trm_reg_write16(DO_RSTMODULE, TRMREG_SCSI_CONTROL); 
	/* program configuration 0 */
	pACB->Config = HCC_AUTOTERM | HCC_PARITY;
	if (trm_reg_read8(TRMREG_GEN_STATUS) & WIDESCSI)
		pACB->Config |= HCC_WIDE_CARD;
	if (pEEpromBuf->NvramChannelCfg & NAC_POWERON_SCSI_RESET)
		pACB->Config |= HCC_SCSI_RESET;
	if (pACB->Config & HCC_PARITY)
		bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
	else
		bval = PHASELATCH | INITIATOR | BLOCKRST ;
	trm_reg_write8(bval,TRMREG_SCSI_CONFIG0); 
	/* program configuration 1 */
	trm_reg_write8(0x13, TRMREG_SCSI_CONFIG1); 
	/* program Host ID */
	bval = pEEpromBuf->NvramScsiId;
	trm_reg_write8(bval, TRMREG_SCSI_HOSTID); 
	/* set ansynchronous transfer */
	trm_reg_write8(0x00, TRMREG_SCSI_OFFSET); 
	/* Trun LED control off*/
	wval = trm_reg_read16(TRMREG_GEN_CONTROL) & 0x7F;
	trm_reg_write16(wval, TRMREG_GEN_CONTROL); 
	/* DMA config */
	wval = trm_reg_read16(TRMREG_DMA_CONFIG) | DMA_ENHANCE;
	trm_reg_write16(wval, TRMREG_DMA_CONFIG); 
	/* Clear pending interrupt status */
	trm_reg_read8(TRMREG_SCSI_INTSTATUS);
	/* Enable SCSI interrupt */
	trm_reg_write8(0x7F, TRMREG_SCSI_INTEN); 
	trm_reg_write8(EN_SCSIINTR, TRMREG_DMA_INTEN); 
	return (0);
}

static void
trm_mapSRB(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
	PACB pACB;

	pACB = (PACB)arg;
	pACB->srb_physbase = segs->ds_addr;
}

static void
trm_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
	bus_addr_t *baddr;

	baddr = (bus_addr_t *)arg;
	*baddr = segs->ds_addr;
}

static PACB
trm_init(u_int16_t unit, device_t dev)
{
	PACB		pACB;
	int		rid = PCIR_BAR(0), i = 0, j = 0;
	u_int16_t	adaptType = 0;
    
 	pACB = (PACB) device_get_softc(dev);
   	if (!pACB) {
		printf("trm%d: cannot allocate ACB !\n", unit);
		return (NULL);
	}
	pACB->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 
	    &rid, RF_ACTIVE);
    	if (pACB->iores == NULL) {
		printf("trm_init: bus_alloc_resource failed!\n");
		return (NULL);
	}
	switch (pci_get_devid(dev)) {
	case PCI_DEVICEID_TRMS1040:
		adaptType = 0;
		break;
	case PCI_DEVICEID_TRMS2080:
		adaptType = 1;
		break;
	default:
		printf("trm_init %d: unknown adapter type!\n", unit);
		goto bad;
	}
	pACB->dev = dev;
	pACB->tag = rman_get_bustag(pACB->iores);
	pACB->bsh = rman_get_bushandle(pACB->iores);
	if (bus_dma_tag_create(
	/*parent_dmat*/	bus_get_dma_tag(dev),
	/*alignment*/	1,
	/*boundary*/	0,
	/*lowaddr*/	BUS_SPACE_MAXADDR,
	/*highaddr*/	BUS_SPACE_MAXADDR,
	/*filter*/	NULL, 
	/*filterarg*/	NULL,
	/*maxsize*/	BUS_SPACE_MAXSIZE_32BIT,
	/*nsegments*/	BUS_SPACE_UNRESTRICTED,
	/*maxsegsz*/	BUS_SPACE_MAXSIZE_32BIT,
	/*flags*/	0,
	/*lockfunc*/	NULL,
	/*lockarg*/	NULL,
	/* dmat */	&pACB->parent_dmat) != 0) 
		goto bad;
	if (bus_dma_tag_create(
	/*parent_dmat*/	pACB->parent_dmat,
	/*alignment*/	1,
	/*boundary*/	0,
	/*lowaddr*/	BUS_SPACE_MAXADDR,
	/*highaddr*/	BUS_SPACE_MAXADDR,
	/*filter*/	NULL, 
	/*filterarg*/	NULL,
	/*maxsize*/	MAXBSIZE,
	/*nsegments*/	TRM_NSEG,
	/*maxsegsz*/	TRM_MAXTRANSFER_SIZE,
	/*flags*/	BUS_DMA_ALLOCNOW,
	/*lockfunc*/	busdma_lock_mutex,
	/*lockarg*/	&Giant,
	/* dmat */	&pACB->buffer_dmat) != 0) 
		goto bad;
	/* DMA tag for our ccb structures */
	if (bus_dma_tag_create(                                 
	/*parent_dmat*/pACB->parent_dmat, 
	/*alignment*/  1, 
	/*boundary*/   0,
	/*lowaddr*/    BUS_SPACE_MAXADDR,
	/*highaddr*/   BUS_SPACE_MAXADDR,
	/*filter*/     NULL, 
	/*filterarg*/  NULL,
	/*maxsize*/    TRM_MAX_SRB_CNT * sizeof(TRM_SRB),
	/*nsegments*/  1,
	/*maxsegsz*/   TRM_MAXTRANSFER_SIZE,
	/*flags*/      0,
	/*lockfunc*/   busdma_lock_mutex,
	/*lockarg*/    &Giant,
	/*dmat*/       &pACB->srb_dmat) != 0) {
		printf("trm_init %d: bus_dma_tag_create SRB failure\n", unit);
		goto bad;
	}
	if (bus_dmamem_alloc(pACB->srb_dmat, (void **)&pACB->pFreeSRB, 
	    BUS_DMA_NOWAIT, &pACB->srb_dmamap) != 0) {
		printf("trm_init %d: bus_dmamem_alloc SRB failure\n", unit);
		goto bad;
	}
	bus_dmamap_load(pACB->srb_dmat, pACB->srb_dmamap, pACB->pFreeSRB,
	    TRM_MAX_SRB_CNT * sizeof(TRM_SRB), trm_mapSRB, pACB, 
	    /* flags */0);
	/* Create, allocate, and map DMA buffers for autosense data */
	if (bus_dma_tag_create(
	    /*parent_dmat*/pACB->parent_dmat,
	    /*alignment*/1,
	    /*boundary*/0,
	    /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
	    /*highaddr*/BUS_SPACE_MAXADDR,
	    /*filter*/NULL, /*filterarg*/NULL,
	    sizeof(struct scsi_sense_data) * TRM_MAX_SRB_CNT,
	    /*nsegments*/1,
	    /*maxsegsz*/TRM_MAXTRANSFER_SIZE,
	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
	    /*lockarg*/&Giant, &pACB->sense_dmat) != 0) {
	  if (bootverbose)
	    device_printf(dev, "cannot create sense buffer dmat\n");
	  goto bad;
	}

	if (bus_dmamem_alloc(pACB->sense_dmat, (void **)&pACB->sense_buffers,
			     BUS_DMA_NOWAIT, &pACB->sense_dmamap) != 0)
		goto bad;

	bus_dmamap_load(pACB->sense_dmat, pACB->sense_dmamap,
		       pACB->sense_buffers,
		       sizeof(struct scsi_sense_data) * TRM_MAX_SRB_CNT,
		       trm_dmamap_cb, &pACB->sense_busaddr, /*flags*/0);

	trm_check_eeprom(&trm_eepromBuf[unit],pACB);
	trm_initACB(pACB, adaptType, unit);
	for (i = 0; i < (pACB->max_id + 1); i++) {   
		if (pACB->AdaptSCSIID == i)
			continue;
		for(j = 0; j < (pACB->max_lun + 1); j++) {
			pACB->scan_devices[i][j] = 1;
			/* we assume we need to scan all devices */ 
			trm_initDCB(pACB, &pACB->DCBarray[i][j], unit, i, j);
		}
	}
	bzero(pACB->pFreeSRB, TRM_MAX_SRB_CNT * sizeof(TRM_SRB));
	if (bus_dma_tag_create(                    
		    /*parent_dmat*/pACB->parent_dmat,
		    /*alignment*/  1,
		    /*boundary*/   0,
		    /*lowaddr*/    BUS_SPACE_MAXADDR,
		    /*highaddr*/   BUS_SPACE_MAXADDR,
		    /*filter*/     NULL, 
		    /*filterarg*/  NULL,
		    /*maxsize*/    TRM_MAX_SG_LISTENTRY * sizeof(SGentry), 
		    /*nsegments*/  1,
		    /*maxsegsz*/   TRM_MAXTRANSFER_SIZE,
		    /*flags*/      0, 
		    /*lockfunc*/   busdma_lock_mutex,
		    /*lockarg*/    &Giant,
		    /*dmat*/       &pACB->sg_dmat) != 0)
		goto bad;

	if (trm_initSRB(pACB)) {
		printf("trm_initSRB: error\n");
		goto bad;
	}
   	if (trm_initAdapter(pACB, unit)) {
		printf("trm_initAdapter: initial ERROR\n");
		goto bad;
	}
	return (pACB);
bad:
	if (pACB->iores)
		bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0),
		    pACB->iores);
	if (pACB->sense_dmamap) {
		bus_dmamap_unload(pACB->sense_dmat, pACB->sense_dmamap);
		bus_dmamem_free(pACB->sense_dmat, pACB->sense_buffers,
		    pACB->sense_dmamap);
		bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap);
	}
	if (pACB->sense_dmat)
		bus_dma_tag_destroy(pACB->sense_dmat);
	if (pACB->sg_dmat) {
		trm_destroySRB(pACB);
		bus_dma_tag_destroy(pACB->sg_dmat);
	}
	if (pACB->srb_dmamap) {
		bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap);
		bus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB, 
		    pACB->srb_dmamap);
		bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap);
	}
	if (pACB->srb_dmat)
		bus_dma_tag_destroy(pACB->srb_dmat);
	if (pACB->buffer_dmat)
		bus_dma_tag_destroy(pACB->buffer_dmat);
	if (pACB->parent_dmat)
		bus_dma_tag_destroy(pACB->parent_dmat);
	return (NULL);
}

static int
trm_attach(device_t dev)
{
	struct	cam_devq *device_Q;
	u_long	device_id;
	PACB	pACB = 0;
	int	rid = 0;
	int unit = device_get_unit(dev);
	
	device_id = pci_get_devid(dev);
	/*
	 * These cards do not allow memory mapped accesses
	 */
	if ((pACB = trm_init((u_int16_t) unit,
    	    dev)) == NULL) {
		printf("trm%d: trm_init error!\n",unit);
		return (ENXIO);
	}
	/* After setting up the adapter, map our interrupt */
	/*  
	 * Now let the CAM generic SCSI layer find the SCSI devices on the bus
	 * start queue to reset to the idle loop.
	 * Create device queue of SIM(s)
	 * (MAX_START_JOB - 1) : max_sim_transactions
	 */
	pACB->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	    RF_SHAREABLE | RF_ACTIVE);
    	if (pACB->irq == NULL ||
	    bus_setup_intr(dev, pACB->irq, 
	    INTR_TYPE_CAM, NULL, trm_Interrupt, pACB, &pACB->ih)) {
		printf("trm%d: register Interrupt handler error!\n", unit);
		goto bad;
	}
	device_Q = cam_simq_alloc(TRM_MAX_START_JOB);
	if (device_Q == NULL){ 
		printf("trm%d: device_Q == NULL !\n",unit);
		goto bad;
	}
	/*
	 * Now tell the generic SCSI layer
	 * about our bus.
	 * If this is the xpt layer creating a sim, then it's OK
	 * to wait for an allocation.
	 * XXX Should we pass in a flag to indicate that wait is OK?
	 *
	 *                    SIM allocation
	 *
	 *                 SCSI Interface Modules
	 * The sim driver creates a sim for each controller.  The sim device
	 * queue is separately created in order to allow resource sharing betwee
	 * sims.  For instance, a driver may create one sim for each channel of
	 * a multi-channel controller and use the same queue for each channel.
	 * In this way, the queue resources are shared across all the channels
	 * of the multi-channel controller.
	 * trm_action     : sim_action_func
	 * trm_poll       : sim_poll_func
	 * "trm"        : sim_name ,if sim_name =  "xpt" ..M_DEVBUF,M_WAITOK
	 * pACB         : *softc    if sim_name <> "xpt" ..M_DEVBUF,M_NOWAIT
	 * pACB->unit   : unit
	 * 1            : max_dev_transactions
	 * MAX_TAGS     : max_tagged_dev_transactions
	 *
	 *  *******Construct our first channel SIM entry
	 */
	pACB->psim = cam_sim_alloc(trm_action,
	    trm_poll,
	    "trm",
	    pACB,
	    unit,
	    &Giant,
	    1,
	    TRM_MAX_TAGS_CMD_QUEUE,
	    device_Q);
	if (pACB->psim == NULL) {
		printf("trm%d: SIM allocate fault !\n",unit);
		cam_simq_free(device_Q);  /* SIM allocate fault*/
		goto bad;
	}
	if (xpt_bus_register(pACB->psim, dev, 0) != CAM_SUCCESS)  {
		printf("trm%d: xpt_bus_register fault !\n",unit);
		goto bad;
	}
	if (xpt_create_path(&pACB->ppath,
	      NULL,
	      cam_sim_path(pACB->psim),
	      CAM_TARGET_WILDCARD,
	      CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
		printf("trm%d: xpt_create_path fault !\n",unit);
		xpt_bus_deregister(cam_sim_path(pACB->psim));
		goto bad;
	}
	return (0);
bad:
	if (pACB->iores)
		bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0),
		    pACB->iores);
	if (pACB->sg_dmat) {		
		trm_destroySRB(pACB);
		bus_dma_tag_destroy(pACB->sg_dmat);
	}
	
	if (pACB->srb_dmamap) {
		bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap);
		bus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB, 
		    pACB->srb_dmamap);
		bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap);
	}
	if (pACB->srb_dmat)
		bus_dma_tag_destroy(pACB->srb_dmat);
	if (pACB->sense_dmamap) {
	  	  bus_dmamap_unload(pACB->sense_dmat, pACB->sense_dmamap);
		  bus_dmamem_free(pACB->sense_dmat, pACB->sense_buffers,
		      pACB->sense_dmamap);
		  bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap);
	}
	if (pACB->sense_dmat)
		bus_dma_tag_destroy(pACB->sense_dmat);		
	if (pACB->buffer_dmat)
		bus_dma_tag_destroy(pACB->buffer_dmat);
	if (pACB->ih)
		bus_teardown_intr(dev, pACB->irq, pACB->ih);
	if (pACB->irq)
		bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irq);
	if (pACB->psim)
		cam_sim_free(pACB->psim, TRUE);
	
	return (ENXIO);
	
}

/*
*                  pci_device
*         trm_probe (device_t tag, pcidi_t type)
*
*/
static int
trm_probe(device_t dev)
{
  	switch (pci_get_devid(dev)) {
	case PCI_DEVICEID_TRMS1040: 
		device_set_desc(dev,
		    "Tekram DC395U/UW/F DC315/U Fast20 Wide SCSI Adapter");
		return (BUS_PROBE_DEFAULT);
	case PCI_DEVICEID_TRMS2080:
		device_set_desc(dev,
		    "Tekram DC395U2D/U2W Fast40 Wide SCSI Adapter");
		return (BUS_PROBE_DEFAULT);
	default:
		return (ENXIO);
	}
}

static int
trm_detach(device_t dev)
{
	PACB pACB = device_get_softc(dev);

	bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), pACB->iores);
	trm_destroySRB(pACB);
	bus_dma_tag_destroy(pACB->sg_dmat);
	bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap);
	bus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB,
	    pACB->srb_dmamap);
	bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap);
	bus_dma_tag_destroy(pACB->srb_dmat);	
	bus_dmamap_unload(pACB->sense_dmat, pACB->sense_dmamap);
	bus_dmamem_free(pACB->sense_dmat, pACB->sense_buffers,
	    pACB->sense_dmamap);
	bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap);
	bus_dma_tag_destroy(pACB->sense_dmat);				      
	bus_dma_tag_destroy(pACB->buffer_dmat);
	bus_teardown_intr(dev, pACB->irq, pACB->ih);
	bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irq);
	xpt_async(AC_LOST_DEVICE, pACB->ppath, NULL);
	xpt_free_path(pACB->ppath);
	xpt_bus_deregister(cam_sim_path(pACB->psim));
	cam_sim_free(pACB->psim, TRUE);
	return (0);
}
static device_method_t trm_methods[] = {
	/* Device interface */
	DEVMETHOD(device_probe,		trm_probe),
	DEVMETHOD(device_attach,	trm_attach),
	DEVMETHOD(device_detach,	trm_detach),
	{ 0, 0 }
};

static driver_t trm_driver = {
	"trm", trm_methods, sizeof(struct _ACB)
};

static devclass_t trm_devclass;
DRIVER_MODULE(trm, pci, trm_driver, trm_devclass, 0, 0);
MODULE_DEPEND(trm, pci, 1, 1, 1);
MODULE_DEPEND(trm, cam, 1, 1, 1);
