#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#if defined(__FreeBSD__) && __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 <sys/thread2.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <bus/pci/pcivar.h>
#include <bus/pci/pcireg.h>
#include <sys/rman.h>
#include <bus/cam/cam.h>
#include <bus/cam/cam_ccb.h>
#include <bus/cam/cam_sim.h>
#include <bus/cam/cam_xpt.h>
#include <bus/cam/cam_xpt_sim.h>
#include <bus/cam/cam_xpt_periph.h>
#include <bus/cam/cam_debug.h>
#include <bus/cam/scsi/scsi_all.h>
#include <bus/cam/scsi/scsi_message.h>
#include "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...) kprintf("trm: " fmt, ##arg)
#else
#define TRM_DPRINTF(fmt, arg...) {}
#endif
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);
#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,
trm_DataInPhase0,
trm_CommandPhase0,
trm_StatusPhase0,
trm_Nop0,
trm_Nop1,
trm_MsgOutPhase0,
trm_MsgInPhase0,
};
static void * trm_SCSI_phase1[] = {
trm_DataOutPhase1,
trm_DataInPhase1,
trm_CommandPhase1,
trm_StatusPhase1,
trm_Nop0,
trm_Nop1,
trm_MsgOutPhase1,
trm_MsgInPhase1,
};
NVRAMTYPE trm_eepromBuf[TRM_MAX_ADAPTER_NUM];
u_int8_t dc395x_clock_period[] = {
12,
18,
25,
31,
37,
43,
50,
62
};
u_int8_t dc395u2x_clock_period[]={
10,
12,
18,
25,
31,
37,
43,
50,
};
#define dc395x_tinfo_period dc395x_clock_period
#define dc395u2x_tinfo_period dc395u2x_clock_period
static PSRB
trm_GetSRB(PACB pACB)
{
PSRB pSRB;
crit_enter();
pSRB = pACB->pFreeSRB;
if (pSRB) {
pACB->pFreeSRB = pSRB->pNextSRB;
pSRB->pNextSRB = NULL;
}
crit_exit();
return (pSRB);
}
static void
trm_RewaitSRB0(PDCB pDCB, PSRB pSRB)
{
PSRB psrb1;
crit_enter();
if ((psrb1 = pDCB->pWaitingSRB)) {
pSRB->pNextSRB = psrb1;
pDCB->pWaitingSRB = pSRB;
} else {
pSRB->pNextSRB = NULL;
pDCB->pWaitingSRB = pSRB;
pDCB->pWaitingLastSRB = pSRB;
}
crit_exit();
}
static void
trm_RewaitSRB(PDCB pDCB, PSRB pSRB)
{
PSRB psrb1;
crit_enter();
pDCB->GoingSRBCnt--;
psrb1 = pDCB->pGoingSRB;
if (pSRB == psrb1)
pDCB->pGoingSRB = psrb1->pNextSRB;
else {
while (pSRB != psrb1->pNextSRB)
psrb1 = psrb1->pNextSRB;
psrb1->pNextSRB = pSRB->pNextSRB;
if (pSRB == pDCB->pGoingLastSRB)
pDCB->pGoingLastSRB = psrb1;
}
if ((psrb1 = pDCB->pWaitingSRB)) {
pSRB->pNextSRB = psrb1;
pDCB->pWaitingSRB = pSRB;
} else {
pSRB->pNextSRB = NULL;
pDCB->pWaitingSRB = pSRB;
pDCB->pWaitingLastSRB = pSRB;
}
crit_exit();
}
static void
trm_DoWaitingSRB(PACB pACB)
{
PDCB ptr, ptr1;
PSRB pSRB;
crit_enter();
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)) {
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;
}
}
}
crit_exit();
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)
{
PACB pACB;
PSRB pSRB;
union ccb *ccb;
u_long totalxferlen=0;
crit_enter();
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;
bus_dmasync_op_t op;
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;
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);
crit_exit();
return;
}
ccb->ccb_h.status |= CAM_SIM_QUEUED;
#if 0
callout_reset(&ccb->ccb_h.timeout_ch, (ccb->ccb_h.timeout * hz) / 1000,
trmtimeout, srb);
#endif
trm_SendSRB(pACB, pSRB);
crit_exit();
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)) {
pDCB->GoingSRBCnt++;
if (pDCB->pGoingSRB) {
pDCB->pGoingLastSRB->pNextSRB = pSRB;
pDCB->pGoingLastSRB = pSRB;
} else {
pDCB->pGoingSRB = pSRB;
pDCB->pGoingLastSRB = pSRB;
}
} else {
trm_RewaitSRB0(pDCB, pSRB);
}
SND_EXIT:
return;
}
static void
trm_action(struct cam_sim *psim, union ccb *pccb)
{
PACB pACB;
u_int target_id,target_lun;
CAM_DEBUG(pccb->ccb_h.path, CAM_DEBUG_TRACE, ("trm_action\n"));
crit_enter();
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;
case XPT_SCSI_IO: {
PDCB pDCB = NULL;
PSRB pSRB;
struct ccb_scsiio *pcsio;
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);
crit_exit();
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);
}
pSRB = trm_GetSRB(pACB);
if (!pSRB) {
pccb->ccb_h.status = CAM_RESRC_UNAVAIL;
xpt_done(pccb);
crit_exit();
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;
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);
crit_exit();
return;
}
} else
bcopy(pcsio->cdb_io.cdb_bytes,
pSRB->CmdBlock, pcsio->cdb_len);
if ((pccb->ccb_h.flags & CAM_DIR_MASK)
!= CAM_DIR_NONE) {
if ((pccb->ccb_h.flags &
CAM_SCATTER_VALID) == 0) {
if ((pccb->ccb_h.flags
& CAM_DATA_PHYS) == 0) {
int error;
crit_enter();
error = bus_dmamap_load(
pACB->buffer_dmat,
pSRB->dmamap,
pcsio->data_ptr,
pcsio->dxfer_len,
trm_ExecuteSRB,
pSRB,
0);
if (error == EINPROGRESS) {
xpt_freeze_simq(
pACB->psim,
1);
pccb->ccb_h.status |=
CAM_RELEASE_SIMQ;
}
crit_exit();
} else {
struct bus_dma_segment seg;
seg.ds_addr =
(bus_addr_t)pcsio->data_ptr;
seg.ds_len = pcsio->dxfer_len;
trm_ExecuteSRB(pSRB, &seg, 1,
0);
}
} else {
struct bus_dma_segment *segs;
if ((pccb->ccb_h.flags &
CAM_SG_LIST_PHYS) == 0 ||
(pccb->ccb_h.flags
& CAM_DATA_PHYS) != 0) {
pSRB->pNextSRB = pACB->pFreeSRB;
pACB->pFreeSRB = pSRB;
pccb->ccb_h.status =
CAM_PROVIDE_FAIL;
xpt_done(pccb);
crit_exit();
return;
}
segs = (struct bus_dma_segment *)
pcsio->data_ptr;
trm_ExecuteSRB(pSRB, segs,
pcsio->sglist_cnt, 1);
}
} else
trm_ExecuteSRB(pSRB, NULL, 0, 0);
}
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;
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;
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;
case XPT_REL_SIMQ:
TRM_DPRINTF(" XPT_REL_SIMQ \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_SASYNC_CB:
TRM_DPRINTF(" XPT_SASYNC_CB \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_SDEV_TYPE:
TRM_DPRINTF(" XPT_SDEV_TYPE \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_SCAN_BUS:
TRM_DPRINTF(" XPT_SCAN_BUS \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_DEV_MATCH:
TRM_DPRINTF(" XPT_DEV_MATCH \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_DEBUG:
TRM_DPRINTF(" XPT_DEBUG \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_ABORT:
TRM_DPRINTF(" XPT_ABORT \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
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;
case XPT_RESET_DEV:
TRM_DPRINTF(" XPT_RESET_DEV \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_TERM_IO:
TRM_DPRINTF(" XPT_TERM_IO \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_SCAN_LUN:
TRM_DPRINTF(" XPT_SCAN_LUN \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_GET_TRAN_SETTINGS: {
struct ccb_trans_settings *cts = &pccb->cts;
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];
crit_enter();
if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
if (pDCB->tinfo.disc_tag & TRM_CUR_DISCENB)
spi->flags = CTS_SPI_FLAGS_DISC_ENB;
else
spi->flags = 0;
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 {
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);
crit_exit();
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;
case XPT_SET_TRAN_SETTINGS: {
struct ccb_trans_settings *cts = &pccb->cts;
u_int update_type;
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;
crit_enter();
pDCB = &pACB->DCBarray[target_id][target_lun];
if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
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 (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;
}
}
if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
if ((spi->sync_period != 0) &&
(spi->sync_period < 125))
spi->sync_period = 125;
if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET)
!= 0) {
if (spi->sync_offset == 0)
spi->sync_period = 0;
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;
}
crit_exit();
pccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(pccb);
break;
}
case XPT_CALC_GEOMETRY:
TRM_DPRINTF(" XPT_CALC_GEOMETRY \n");
cam_calc_geometry(&pccb->ccg, 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;
case XPT_ENG_EXEC:
TRM_DPRINTF(" XPT_ENG_EXEC \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_EN_LUN:
TRM_DPRINTF(" XPT_EN_LUN \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_TARGET_IO:
TRM_DPRINTF(" XPT_TARGET_IO \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_ACCEPT_TARGET_IO:
TRM_DPRINTF(" XPT_ACCEPT_TARGET_IO \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_CONT_TARGET_IO:
TRM_DPRINTF(" XPT_CONT_TARGET_IO \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_IMMED_NOTIFY:
TRM_DPRINTF(" XPT_IMMED_NOTIFY \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
case XPT_NOTIFY_ACK:
TRM_DPRINTF(" XPT_NOTIFY_ACK \n");
pccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(pccb);
break;
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;
}
crit_exit();
}
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)
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)
{
u_int16_t i;
TRM_DPRINTF("trm: RESET");
crit_enter();
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);
trm_reg_write8(EN_SCSIINTR, TRMREG_DMA_INTEN);
trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL);
trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL);
trm_ResetDevParam(pACB);
trm_DoingSRB_Done(pACB);
pACB->pActiveDCB = NULL;
pACB->ACBFlag = 0;
trm_DoWaitingSRB(pACB);
if (pACB->ppath != NULL)
xpt_async(AC_BUS_RESET, pACB->ppath, NULL);
crit_exit();
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;
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;
}
}
trm_reg_write8((identify_message & 0xBF) ,TRMREG_SCSI_FIFO);
scsicommand = SCMD_SEL_ATN;
pSRB->SRBState = SRB_START_;
} else {
trm_reg_write8(identify_message,TRMREG_SCSI_FIFO);
scsicommand = SCMD_SEL_ATN;
pSRB->SRBState = SRB_START_;
if (pDCB->SyncMode & EN_TAG_QUEUING) {
trm_reg_write8(MSG_SIMPLE_QTAG, TRMREG_SCSI_FIFO);
trm_reg_write8(pSRB->TagNumber, TRMREG_SCSI_FIFO);
scsicommand = SCMD_SEL_ATN3;
}
}
polling:
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) {
pSRB->SRBState = SRB_READY;
return_code = 1;
} else {
pSRB->ScsiPhase = SCSI_NOP1;
pACB->pActiveDCB = pDCB;
pDCB->pActiveSRB = pSRB;
return_code = 0;
trm_reg_write16(DO_DATALATCH | DO_HWRESELECT,
TRMREG_SCSI_CONTROL);
trm_reg_write8(scsicommand,TRMREG_SCSI_COMMAND);
}
return (return_code);
}
static void
trm_Interrupt(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;
stateV = trm_SCSI_phase0[phase];
stateV(pACB, pSRB, &scsi_status);
pSRB->ScsiPhase = scsi_status & PHASEMASK;
phase = (u_int16_t) scsi_status & PHASEMASK;
stateV = 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;
}
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:
if (!(pSRB->SRBState & SRB_DO_WIDE_NEGO)
&& (pDCB->SyncMode & WIDE_NEGO_ENABLE)) {
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);
trm_reg_write8(2,TRMREG_SCSI_FIFO);
trm_reg_write8(3,TRMREG_SCSI_FIFO);
trm_reg_write8(1,TRMREG_SCSI_FIFO);
pSRB->SRBState |= SRB_DO_WIDE_NEGO;
} else if (!(pSRB->SRBState & SRB_DO_SYNC_NEGO)
&& (pDCB->SyncMode & SYNC_NEGO_ENABLE)) {
if (!(pDCB->SyncMode & WIDE_NEGO_DONE))
trm_reg_write8((pDCB->IdentifyMsg & 0xBF),
TRMREG_SCSI_FIFO);
trm_reg_write8(MSG_EXTENDED,TRMREG_SCSI_FIFO);
trm_reg_write8(3,TRMREG_SCSI_FIFO);
trm_reg_write8(1,TRMREG_SCSI_FIFO);
trm_reg_write8(pDCB->MaxNegoPeriod,TRMREG_SCSI_FIFO);
trm_reg_write8((pACB->AdaptType == 1) ? 31 : 15,
TRMREG_SCSI_FIFO);
pSRB->SRBState |= SRB_DO_SYNC_NEGO;
}
}
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
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;
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);
}
pSRB->SRBState = SRB_COMMAND;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
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)) {
dLeftCounter = (u_long)
(trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x3F);
if (pDCB->SyncPeriod & WIDE_SYNC) {
dLeftCounter <<= 1;
}
}
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 {
if (pSRB->SRBTotalXferLength != dLeftCounter) {
TempSRBXferredLength =
pSRB->SRBTotalXferLength - dLeftCounter;
pSRB->SRBTotalXferLength = dLeftCounter;
pseg =
pSRB->pSRBSGL + pSRB->SRBSGIndex;
for (SGIndexTemp = pSRB->SRBSGIndex;
SGIndexTemp < pSRB->SRBSGCount;
SGIndexTemp++) {
if (TempSRBXferredLength >=
pseg->length)
TempSRBXferredLength -=
pseg->length;
else {
pseg->length -=
TempSRBXferredLength;
pseg->address +=
TempSRBXferredLength;
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;
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 {
if (pSRB->SRBTotalXferLength != dLeftCounter) {
TempSRBXferredLength =
pSRB->SRBTotalXferLength - dLeftCounter;
pSRB->SRBTotalXferLength = dLeftCounter;
pseg = pSRB->pSRBSGL + pSRB->SRBSGIndex;
for (SGIndexTemp = pSRB->SRBSGIndex;
SGIndexTemp < pSRB->SRBSGCount;
SGIndexTemp++) {
if (TempSRBXferredLength >= pseg->length)
TempSRBXferredLength -= pseg->length;
else {
pseg->length -= TempSRBXferredLength;
pseg->address += TempSRBXferredLength;
pSRB->SRBSGIndex = SGIndexTemp;
break;
}
pseg++;
}
}
}
}
}
static void
trm_DataInPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status)
{
u_int16_t ioDir;
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) {
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);
trm_reg_write32(
((u_long)(pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3),
TRMREG_DMA_XCNT);
trm_reg_write32(pSRB->SRBTotalXferLength,
TRMREG_SCSI_COUNTER);
trm_reg_write16(ioDir, TRMREG_DMA_COMMAND);
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
bval = (ioDir == XFERDATAOUT) ?
SCMD_DMA_OUT : SCMD_DMA_IN;
trm_reg_write8(bval, TRMREG_SCSI_COMMAND);
} else {
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);
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
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);
trm_reg_write8(SCMD_COMP, TRMREG_SCSI_COMMAND);
}
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else if (message_in_code == MSG_SAVE_PTR) {
*pscsi_status = PH_BUS_FREE;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
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;
pSRB->MsgCnt = 1;
pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
*pscsi_status = PH_BUS_FREE;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else if (message_in_code == MSG_REJECT_) {
if (pDCB->SyncMode & WIDE_NEGO_ENABLE) {
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)) {
pSRB->SRBState |= SRB_MSGOUT;
trm_reg_write16(
DO_SETATN,
TRMREG_SCSI_CONTROL);
} else {
trm_reg_write16(
DO_CLRATN,
TRMREG_SCSI_CONTROL);
}
} else if (pDCB->SyncMode & SYNC_NEGO_ENABLE) {
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;
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else {
*pscsi_status = PH_BUS_FREE;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
}
} else {
*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)) {
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED) &&
(pSRB->MsgInBuf[2] == 3) && (pSRB->MsgCnt == 4)) {
pDCB = pSRB->pSRBDCB;
pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_WIDE_NEGO);
if ((pSRB->MsgInBuf[1] != 2)) {
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
}
if (pDCB->SyncMode & WIDE_NEGO_ENABLE) {
if (pSRB->MsgInBuf[3] > 2) {
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
}
if (pSRB->MsgInBuf[3] == 2) {
pSRB->MsgInBuf[3] = 1;
} 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) {
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED) &&
(pSRB->MsgInBuf[2] == 1) && (pSRB->MsgCnt == 5)) {
pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_SYNC_NEGO);
if ((pSRB->MsgInBuf[1] != 3) ||
(pSRB->MsgInBuf[2] != 1)) {
pSRB->MsgCnt = 1;
pSRB->MsgInBuf[0] = MSG_REJECT_;
trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL);
*pscsi_status = PH_BUS_FREE;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else if (!(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4])) {
pDCB = pSRB->pSRBDCB;
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;
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;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
return;
} else {
pDCB = pSRB->pSRBDCB;
pDCB->SyncMode |=
SYNC_NEGO_ENABLE+SYNC_NEGO_DONE;
pDCB->MaxNegoPeriod = pSRB->MsgInBuf[3];
pDCB->SyncOffset = pSRB->MsgInBuf[4];
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;
}
}
}
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;
trm_reg_write16(DO_DATALATCH,TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT,TRMREG_SCSI_COMMAND);
return;
}
}
*pscsi_status = PH_BUS_FREE;
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
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);
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;
TRM_DPRINTF("trm_SetXferRate\n");
pccb = pSRB->pccb;
neg = &xpt_alloc_ccb()->cts;
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, 1);
xpt_async(AC_TRANSFER_NEG, pccb->ccb_h.path, neg);
xpt_free_ccb(&neg->ccb_h);
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;
}
}
}
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);
trm_reg_write16((DO_CLRFIFO | DO_HWRESELECT),
TRMREG_SCSI_CONTROL);
crit_exit();
return;
}
pSRB = pDCB->pActiveSRB;
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 = NULL;
pSRB->ScsiPhase = PH_BUS_FREE;
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 = NULL;
trm_DoWaitingSRB(pACB);
} else {
if ((pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
!(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED))) {
if (!(pACB->scan_devices[target_id][target_lun]) &&
pSRB->CmdBlock[0] != 0x00 &&
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) {
trm_DoWaitingSRB(pACB);
} else if (pSRB->SRBState & SRB_COMPLETED) {
disc1:
pDCB->pActiveSRB = NULL;
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) {
pSRB = pDCB->pActiveSRB;
pSRB->SRBState = SRB_READY;
trm_RewaitSRB(pDCB, pSRB);
}
RselTarLunId = trm_reg_read16(TRMREG_SCSI_TARGETID) & 0x1FFF;
pDCB = pACB->pLinkDCB;
while (RselTarLunId != *((u_int16_t *) &pDCB->TargetID)) {
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)) {
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;
trm_reg_write8((u_int8_t) RselTarLunId,TRMREG_SCSI_TARGETID);
trm_reg_write8(pACB->AdaptSCSIID,TRMREG_SCSI_HOSTID);
trm_reg_write8(pDCB->SyncPeriod,TRMREG_SCSI_SYNC);
trm_reg_write8(pDCB->SyncOffset,TRMREG_SCSI_OFFSET);
trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL);
trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND);
}
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;
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);
}
status = pSRB->TargetStatus;
pcsio->scsi_status=SCSI_STAT_GOOD;
pccb->ccb_h.status = CAM_REQ_CMP;
if (pSRB->SRBFlag & AUTO_REQSENSE) {
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;
}
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;
} 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;
return;
} else {
pSRB->AdaptStatus = 0;
if (pSRB->RetryCnt) {
pSRB->RetryCnt--;
pSRB->TargetStatus = 0;
pSRB->SRBSGIndex = 0;
if (trm_StartSCSI(pACB, pDCB, pSRB)) {
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 {
status = pSRB->AdaptStatus;
if (status & H_OVER_UNDER_RUN) {
pSRB->TargetStatus = 0;
pccb->ccb_h.status = CAM_DATA_RUN_ERR;
} 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;
pccb->ccb_h.status = CAM_UNCOR_PARITY;
} else {
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0;
pccb->ccb_h.status = CAM_REQ_CMP;
}
}
ckc_e:
if (pACB->scan_devices[target_id][target_lun]) {
if (pSRB->CmdBlock[0] == TEST_UNIT_READY)
pACB->scan_devices[target_id][target_lun] = 0;
else if (pSRB->CmdBlock[0] == INQUIRY) {
if (pccb->ccb_h.status == CAM_SEL_TIMEOUT)
goto NO_DEV;
ptr = (PSCSI_INQDATA) pcsio->data_ptr;
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);
crit_enter();
pACB->scan_devices[target_id][target_lun] = 0;
pTempDCB=pACB->pLinkDCB;
while (pTempDCB->pNextDCB != pDCB) {
pTempDCB = pTempDCB->pNextDCB;
}
pTempDCB->pNextDCB = pDCB->pNextDCB;
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;
}
crit_exit();
} 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;
}
}
}
}
}
}
crit_enter();
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);
crit_exit();
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;
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)
{
crit_enter();
pACB->ACBFlag |= RESET_DEV;
trm_reg_write16(DO_RSTSCSI,TRMREG_SCSI_CONTROL);
while (!(trm_reg_read16(TRMREG_SCSI_INTSTATUS) & INT_SCSIRESET));
crit_exit();
return;
}
static void
trm_ScsiRstDetect(PACB pACB)
{
u_long wlval;
TRM_DPRINTF("trm_ScsiRstDetect \n");
wlval = 1000;
while (--wlval)
DELAY(1000);
crit_enter();
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_RecoverSRB(pACB);
pACB->pActiveDCB = NULL;
pACB->ACBFlag = 0;
trm_DoWaitingSRB(pACB);
}
crit_exit();
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;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0;
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))
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;
target_id = i;
target_lun = j;
if (target_lun != 0 &&
(pACB->DCBarray[target_id][0].DCBstatus & DS_IN_QUEUE))
bcopy(&pACB->DCBarray[target_id][0], pDCB,
sizeof(TRM_DCB));
crit_enter();
if (pACB->pLinkDCB == NULL) {
pACB->pLinkDCB = pDCB;
pACB->pDCBRunRobin = pDCB;
pDCB->pNextDCB = pDCB;
} else {
pTempDCB=pACB->pLinkDCB;
while (pTempDCB->pNextDCB != pACB->pLinkDCB)
pTempDCB = pTempDCB->pNextDCB;
pTempDCB->pNextDCB = pDCB;
pDCB->pNextDCB=pACB->pLinkDCB;
}
crit_exit();
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;
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;
if (pDCB->DevMode & TAG_QUEUING_) {
pDCB->tinfo.disc_tag |= TRM_USR_TAGENB ;
} else
pDCB->tinfo.disc_tag &= ~(TRM_USR_TAGENB);
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
PeriodIndex = pEEpromBuf->NvramTarget[target_id].NvmTarPeriod & 0x07;
if (pACB->AdaptType==1) {
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;
if (pDCB->DevMode & NTC_DO_SYNC_NEGO)
pDCB->SyncMode |= SYNC_NEGO_ENABLE;
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, 0);
if (i != TRM_MAX_SRB_CNT - 1) {
pSRB->pNextSRB = &pACB->pFreeSRB[i+1];
} else {
pSRB->pNextSRB = NULL;
}
pSRB->TagNumber = i;
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;
trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) | EN_EEPROM),
TRMREG_GEN_CONTROL);
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);
}
NVRAM_trm_write_cmd(pACB, 0x04, 0x00);
trm_reg_write8(0 , TRMREG_GEN_NVRAM);
NVRAM_trm_wait_30us(pACB);
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;
NVRAM_trm_write_cmd(pACB, 0x05, bAddr);
for (i = 0; i < 8; i++, bData <<= 1) {
bSendData = NVR_SELECT;
if (bData & 0x80)
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);
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);
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;
}
}
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;
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);
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;
NVRAM_trm_write_cmd(pACB, 0x06, bAddr);
for (i = 0; i < 8; i++) {
trm_reg_write8((NVR_SELECT | NVR_CLOCK) , TRMREG_GEN_NVRAM);
NVRAM_trm_wait_30us(pACB);
trm_reg_write8(NVR_SELECT , TRMREG_GEN_NVRAM);
bReadData = trm_reg_read8(TRMREG_GEN_NVRAM);
bData <<= 1;
if (bReadData & NVR_BITIN) {
bData |= 1;
}
NVRAM_trm_wait_30us(pACB);
}
trm_reg_write8(0, TRMREG_GEN_NVRAM);
return (bData);
}
static void
NVRAM_trm_wait_30us(PACB pACB)
{
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) {
bSendData = NVR_SELECT;
if (bCmd & 0x04)
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);
}
for (i = 0; i < 7; i++, bAddr <<= 1) {
bSendData = NVR_SELECT;
if (bAddr & 0x40)
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 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) {
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;
}
*dpEeprom++ = 0x04000F07;
*dpEeprom++ = 0x00000015;
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];
trm_reg_write8(SEL_TIMEOUT, TRMREG_SCSI_TIMEOUT);
trm_reg_write8(0x00, TRMREG_DMA_INTEN);
trm_reg_write8(0x00, TRMREG_SCSI_INTEN);
trm_reg_write16(DO_RSTMODULE, TRMREG_SCSI_CONTROL);
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);
trm_reg_write8(0x13, TRMREG_SCSI_CONFIG1);
bval = pEEpromBuf->NvramScsiId;
trm_reg_write8(bval, TRMREG_SCSI_HOSTID);
trm_reg_write8(0x00, TRMREG_SCSI_OFFSET);
wval = trm_reg_read16(TRMREG_GEN_CONTROL) & 0x7F;
trm_reg_write16(wval, TRMREG_GEN_CONTROL);
wval = trm_reg_read16(TRMREG_DMA_CONFIG) | DMA_ENHANCE;
trm_reg_write16(wval, TRMREG_DMA_CONFIG);
trm_reg_read8(TRMREG_SCSI_INTSTATUS);
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) {
kprintf("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) {
kprintf("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:
kprintf("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( pACB->parent_dmat,
1,
0,
BUS_SPACE_MAXADDR,
BUS_SPACE_MAXADDR,
MAXBSIZE,
TRM_NSEG,
TRM_MAXTRANSFER_SIZE,
BUS_DMA_ALLOCNOW,
&pACB->buffer_dmat) != 0)
goto bad;
if (bus_dma_tag_create(
pACB->parent_dmat,
1,
0,
BUS_SPACE_MAXADDR,
BUS_SPACE_MAXADDR,
TRM_MAX_SRB_CNT * sizeof(TRM_SRB),
1,
TRM_MAXTRANSFER_SIZE,
0,
&pACB->srb_dmat) != 0) {
kprintf("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) {
kprintf("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,
0);
if (bus_dma_tag_create(NULL, 1,
0,
BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR,
sizeof(struct scsi_sense_data) * TRM_MAX_SRB_CNT,
1,
TRM_MAXTRANSFER_SIZE,
0, &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, 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;
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(
NULL,
1,
0,
BUS_SPACE_MAXADDR,
BUS_SPACE_MAXADDR,
TRM_MAX_SG_LISTENTRY * sizeof(SGentry),
1,
TRM_MAXTRANSFER_SIZE,
0,
&pACB->sg_dmat) != 0)
goto bad;
if (trm_initSRB(pACB)) {
kprintf("trm_initSRB: error\n");
goto bad;
}
if (trm_initAdapter(pACB, unit)) {
kprintf("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);
return (NULL);
}
static int
trm_attach(device_t dev)
{
struct cam_devq *device_Q;
PACB pACB = NULL;
int rid = 0;
int unit = device_get_unit(dev);
if ((pACB = trm_init((u_int16_t) unit,
dev)) == NULL) {
kprintf("trm%d: trm_init error!\n",unit);
return (ENXIO);
}
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,
0, trm_Interrupt, pACB,
&pACB->ih, NULL)) {
kprintf("trm%d: register Interrupt handler error!\n", unit);
goto bad;
}
device_Q = cam_simq_alloc(TRM_MAX_START_JOB);
if (device_Q == NULL){
kprintf("trm%d: device_Q == NULL !\n",unit);
goto bad;
}
pACB->psim = cam_sim_alloc(trm_action,
trm_poll,
"trm",
pACB,
unit,
&sim_mplock,
1,
TRM_MAX_TAGS_CMD_QUEUE,
device_Q);
cam_simq_release(device_Q);
if (pACB->psim == NULL) {
kprintf("trm%d: SIM allocate fault !\n",unit);
goto bad;
}
if (xpt_bus_register(pACB->psim, 0) != CAM_SUCCESS) {
kprintf("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) {
kprintf("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);
return (ENXIO);
}
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);
return (0);
}
static device_method_t trm_methods[] = {
DEVMETHOD(device_probe, trm_probe),
DEVMETHOD(device_attach, trm_attach),
DEVMETHOD(device_detach, trm_detach),
DEVMETHOD_END
};
static driver_t trm_driver = {
"trm", trm_methods, sizeof(struct _ACB)
};
static devclass_t trm_devclass;
DRIVER_MODULE(trm, pci, trm_driver, trm_devclass, NULL, NULL);
MODULE_DEPEND(trm, cam, 1, 1, 1);