Index: conf/NOTES =================================================================== RCS file: /home/ncvs/src/sys/conf/NOTES,v retrieving revision 1.1093 diff -u -p -r1.1093 NOTES --- conf/NOTES 13 Oct 2002 16:29:13 -0000 1.1093 +++ conf/NOTES 13 Oct 2002 17:44:04 -0000 @@ -1167,6 +1167,7 @@ options TDFX_LINUX # Enable Linuxulato # 53C810, 53C810A, 53C815, 53C825, 53C825A, 53C860, 53C875, # 53C876, 53C885, 53C895, 53C895A, 53C896, 53C897, 53C1510D, # 53C1010-33, 53C1010-66. +# trm: Tekram DC395U/UW/F DC315U adapters. # wds: WD7000 # @@ -1206,6 +1207,7 @@ hint.isp.0.nodewnn="w50000000aaaa0001" device ispfw device ncr device sym +device trm device wds hint.wds.0.at="isa" hint.wds.0.port="0x350" Index: conf/files =================================================================== RCS file: /home/ncvs/src/sys/conf/files,v retrieving revision 1.717 diff -u -p -r1.717 files --- conf/files 12 Oct 2002 05:32:22 -0000 1.717 +++ conf/files 13 Oct 2002 14:42:30 -0000 @@ -652,6 +652,7 @@ dev/syscons/rain/rain_saver.c optional r dev/syscons/star/star_saver.c optional star_saver dev/syscons/warp/warp_saver.c optional warp_saver dev/tdfx/tdfx_pci.c optional tdfx pci +dev/trm/trm.c optional trm dev/twe/twe.c optional twe dev/twe/twe_freebsd.c optional twe dev/tx/if_tx.c optional tx Index: dev/trm/trm.c =================================================================== RCS file: dev/trm/trm.c diff -N dev/trm/trm.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/trm/trm.c 3 Oct 2002 01:10:44 -0000 @@ -0,0 +1,3392 @@ +/* + * 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 DC395U/UW/F ,DC315/U + * PCI SCSI Bus Master Host Adapter + * (SCSI chip set used Tekram ASIC TRM-S1040) + * (C)Copyright 1995-1999 Tekram Technology Co., Ltd. + */ + +/* + * 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 + */ + +/* + * + * + * 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 , 1996-12-17 + */ + +/* + * Updated to compile under FreeBSD 5.0-CURRENT by Olivier Houchard + * , 2002-03-04 + */ + +/* #define trm_DEBUG0 */ + +#include + +#include +#include +#include +#if __FreeBSD_version >= 500000 +#include +#endif +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#define PCI_BASE_ADDR0 0x10 +#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 + +#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 TRM_read_all(PNVRAMTYPE pEEpromBuf,PACB pACB); +static u_int8_t TRM_get_data(PACB pACB, u_int8_t bAddr); +static void TRM_write_all(PNVRAMTYPE pEEpromBuf,PACB pACB); +static void TRM_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData); +static void TRM_write_cmd(PACB pACB, u_int8_t bCmd, u_int8_t bAddr); +static void TRM_wait_30us(PACB pACB); + +static void trm_Interrupt(void *vpACB); +static void trm_DataOutPhase0(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_DataInPhase0(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_CommandPhase0(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_StatusPhase0(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_MsgOutPhase0(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_MsgInPhase0(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_DataOutPhase1(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_DataInPhase1(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_CommandPhase1(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_StatusPhase1(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_MsgOutPhase1(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_MsgInPhase1(PACB pACB, PSRB pSRB, + u_int8_t * pscsi_status); +static void trm_Nop0(PACB pACB, PSRB pSRB, u_int8_t * pscsi_status); +static void trm_Nop1(PACB pACB, PSRB pSRB, u_int8_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, + device_t pci_config_id); +static void trm_initDCB(PACB pACB, PDCB pDCB, u_int16_t unit, + u_int32_t i, u_int32_t j); +static void trm_initSRB(PSRB psrb); +static void trm_linkSRB(PACB pACB); +static void trm_initACB(PACB pACB, 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[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_trm_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 dc395x_trm_tinfo_sync_period[] = { + 12,/* 20.0 MB/sec */ + 18,/* 13.3 MB/sec */ + 25,/* 10.0 MB/sec */ + 31,/* 8.0 MB/sec */ + 37,/* 6.6 MB/sec */ + 43,/* 5.7 MB/sec */ + 50,/* 5.0 MB/sec */ + 62,/* 4.0 MB/sec */ +}; + +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->pWaitLastSRB = pSRB; + } + splx(intflag); +} + +static void +trm_RewaitSRB(PDCB pDCB, PSRB pSRB) +{ + PSRB psrb1; + int intflag; + u_int8_t bval; + + intflag = splcam(); + 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->pWaitLastSRB = pSRB; + } + bval = pSRB->TagNumber; + pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ + 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->MaxCommand > 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->pWaitLastSRB == pSRB) { + ptr1->pWaitingSRB = NULL; + ptr1->pWaitLastSRB = 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->pWaitLastSRB->pNextSRB = pSRB; + pDCB->pWaitLastSRB = pSRB; + pSRB->pNextSRB = NULL; + } else { + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLastSRB = pSRB; + } +} + +static void +trm_ExecuteSRB(void *arg, bus_dma_segment_t *dm_segs, int nseg, int vp) +{ + int flags; + PACB pACB; + PSRB pSRB; + union ccb *ccb; + u_long totalxferlen=0; + + 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; + + /* Copy the segments into our SG list */ + end_seg = dm_segs + nseg; + psg = (PSEG) &pSRB->SegmentX[0]; + pSRB->SRBSGListPointer= psg; + while (dm_segs < end_seg) { + psg->address = vp?(u_long)vtophys(dm_segs->ds_addr) + :(u_long)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 */ + + flags = splcam(); + 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) +{ + int intflag; + PDCB pDCB; + + intflag = splcam(); + pDCB = pSRB->pSRBDCB; + if (!(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) + || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV))) { + TRM_DPRINTF("pDCB->MaxCommand=%d \n",pDCB->MaxCommand); + 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: + splx(intflag); + /* + * enable interrupt + */ + 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")); + + 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; + + 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]); + pDCB = pACB->pDCB[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); + 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 + */ + 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 flags; + int error; + + flags = splsoftvm(); + 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; + } + splx(flags); + } else { + struct bus_dma_segment seg; + + /* Pointer to physical buffer */ + seg.ds_addr = + (bus_addr_t)pcsio->data_ptr; + seg.ds_len = pcsio->dxfer_len; + trm_ExecuteSRB( + pSRB, + &seg, + 1, + 0); + } + } else { + /* CAM_SCATTER_VALID */ + 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); + return; + } + + /* cam SG list is physical, + * cam data is virtual + */ + segs = (struct bus_dma_segment *) + pcsio->data_ptr; + trm_ExecuteSRB( + pSRB, + segs, + pcsio->sglist_cnt, + 1); + } /* CAM_SCATTER_VALID */ + } 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; + /* + * 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); + 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->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; + /* + * (Re)Scan the SCSI Bus + * Rescan the given bus, or bus/target/lun + */ + case XPT_SCAN_BUS: + TRM_DPRINTF(" XPT_SCAN_BUS \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; + /* + * Scan Logical Unit + */ + case XPT_SCAN_LUN: + TRM_DPRINTF(" XPT_SCAN_LUN \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; + int intflag; + struct trm_transinfo *tinfo; + PDCB pDCB; + + TRM_DPRINTF(" XPT_GET_TRAN_SETTINGS \n"); + cts = &pccb->cts; + pDCB = pACB->pDCB[target_id][target_lun]; + intflag = splcam(); + /* + * disable interrupt + */ + if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { + /* current transfer settings */ + if (pDCB->tinfo.disc_tag & TRM_CUR_DISCENB) + cts->flags = CCB_TRANS_DISC_ENB; + else + cts->flags = 0;/* no tag & disconnect */ + if (pDCB->tinfo.disc_tag & TRM_CUR_TAGENB) + cts->flags |= CCB_TRANS_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) + cts->flags = CCB_TRANS_DISC_ENB; + else + cts->flags = 0; + if (pDCB->tinfo.disc_tag & TRM_USR_TAGENB) + cts->flags |= CCB_TRANS_TAG_ENB; + tinfo = &pDCB->tinfo.user; + TRM_DPRINTF("USER: cts->flags= %2x \n", + cts->flags); + } + cts->sync_period = tinfo->period; + cts->sync_offset = tinfo->offset; + cts->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); + cts->valid = CCB_TRANS_SYNC_RATE_VALID | + CCB_TRANS_SYNC_OFFSET_VALID | + CCB_TRANS_BUS_WIDTH_VALID | + CCB_TRANS_DISC_VALID | + CCB_TRANS_TQ_VALID; + 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; + u_int update_type; + int intflag; + PDCB pDCB; + + TRM_DPRINTF(" XPT_SET_TRAN_SETTINGS \n"); + cts = &pccb->cts; + update_type = 0; + if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) + update_type |= TRM_TRANS_GOAL; + if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) + update_type |= TRM_TRANS_USER; + intflag = splcam(); + pDCB = pACB->pDCB[target_id][target_lun]; + + if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { + /*ccb disc enables */ + if (update_type & TRM_TRANS_GOAL) { + if ((cts->flags & CCB_TRANS_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 ((cts->flags & CCB_TRANS_DISC_ENB) + != 0) + pDCB->tinfo.disc_tag + |= TRM_USR_DISCENB; + else + pDCB->tinfo.disc_tag &= + ~TRM_USR_DISCENB; + } + } + if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { + /* if ccb tag q active */ + if (update_type & TRM_TRANS_GOAL) { + if ((cts->flags & CCB_TRANS_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 ((cts->flags & CCB_TRANS_TAG_ENB) + != 0) + pDCB->tinfo.disc_tag |= + TRM_USR_TAGENB; + else + pDCB->tinfo.disc_tag &= + ~TRM_USR_TAGENB; + } + } + /* Minimum sync period factor */ + + if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { + /* if ccb sync active */ + /* TRM-S1040 MinSyncPeriod = 4 clocks/byte */ + if ((cts->sync_period != 0) && + (cts->sync_period < 125)) + cts->sync_period = 125; + /* 1/(125*4) minsync 2 MByte/sec */ + if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) + != 0) { + if (cts->sync_offset == 0) + cts->sync_period = 0; + /* TRM-S1040 MaxSyncOffset = 15 bytes*/ + if (cts->sync_offset > 15) + cts->sync_offset = 15; + } + } + if ((update_type & TRM_TRANS_USER) != 0) { + pDCB->tinfo.user.period = cts->sync_period; + pDCB->tinfo.user.offset = cts->sync_offset; + pDCB->tinfo.user.width = cts->bus_width; + } + if ((update_type & TRM_TRANS_GOAL) != 0) { + pDCB->tinfo.goal.period = cts->sync_period; + pDCB->tinfo.goal.offset = cts->sync_offset; + pDCB->tinfo.goal.width = cts->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: { + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + int extended; + + TRM_DPRINTF(" XPT_CALC_GEOMETRY \n"); + ccg = &pccb->ccg; + size_mb = ccg->volume_size / + ((1024L * 1024L) / ccg->block_size); + extended = 1; + if (size_mb > 1024 && extended) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + pccb->ccb_h.status = CAM_REQ_CMP; + 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; + } +} + +static void +trm_poll(struct cam_sim *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; + pDCB->MaxNegoPeriod = dc395x_trm_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->pWaitLastSRB = psrb2; + psrb2->pNextSRB = NULL; + } + } + pdcb->GoingSRBCnt = 0; + pdcb->pGoingSRB = NULL; + pdcb->TagMask = 0; + 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 tag_number, scsicommand, i,command,identify_message; + u_int8_t * ptr; + u_long tag_mask; + union ccb *pccb; + struct ccb_scsiio *pcsio; + + pccb = pSRB->pccb; + pcsio = &pccb->csio; + pSRB->TagNumber = 31; + + 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 */ + /* + * Get tag id + */ + tag_mask = 1; + tag_number = 0; + while (tag_mask & pDCB->TagMask) { + tag_mask = tag_mask << 1; + tag_number++; + } + /* + * Send Tag id + */ + trm_reg_write8(MSG_SIMPLE_QTAG, TRMREG_SCSI_FIFO); + trm_reg_write8(tag_number, TRMREG_SCSI_FIFO); + pDCB->TagMask |= tag_mask; + pSRB->TagNumber = tag_number; + scsicommand = SCMD_SEL_ATN3; + pSRB->SRBState = SRB_START_; + } + } +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; + pDCB->TagMask &= ~(1 << pSRB->TagNumber); + 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_int8_t *); + u_int8_t scsi_status=0, scsi_intstatus; + + pACB = vpACB; + + if (pACB == NULL) { + TRM_DPRINTF("trm_Interrupt: pACB NULL return......"); + return; + } + + 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; + pSRB = pDCB->pActiveSRB; + if (pDCB) { + 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_int8_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_int8_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(SYNC_NEGO_OFFSET,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_int8_t *pscsi_status) +{ + +} + +static void +trm_CommandPhase1(PACB pACB, PSRB pSRB, u_int8_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_int8_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) & 0x1F); + 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->SRBSGListPointer + 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_int8_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_int8_t *pscsi_status) +{ + u_int8_t bval,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)) { + bval = trm_reg_read8(TRMREG_DMA_STATUS); + while (!(bval & DMAXFERCOMP)) + bval = 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->SRBSGListPointer + 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_int8_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) { + pSRB->SRBSGPhyAddr = vtophys(pSRB->SRBSGListPointer); + /* + * load what physical address of Scatter/Gather list + table want to be transfer + */ + 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_int8_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_int8_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_int8_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; + goto min6; + } else if (message_in_code == MSG_SAVE_PTR) { + goto min6; + } 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) */ + goto min6; + } 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; + goto re_prog; + } + } + goto min6; + } else if (message_in_code == MSG_IGNOREWIDE) { + trm_reg_write32(1, TRMREG_SCSI_COUNTER); + trm_reg_read8(TRMREG_SCSI_FIFO); + goto min6; + } else { + /* Restore data pointer message */ + /* Save data pointer message */ + /* Completion message */ + /* NOP message */ + goto min6; + } + } 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)) + goto mingx0; + pDCB->pActiveSRB = pSRB; + pSRB->SRBState = SRB_DATA_XFER; + } else { +mingx0: + pSRB = pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + trm_EnableMsgOutAbort2( + pACB, + pSRB); + } + } + } 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); + goto min6; + } + 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); + goto min6; + } + 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); + goto min6; + } 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); + } 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; + goto re_prog; + } 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 */ + for (bIndex = 0; bIndex < 7; bIndex++) { + if (pSRB->MsgInBuf[3] <= + dc395x_trm_clock_period[bIndex]) { + break; + } + } + pDCB->tinfo.goal.period = + dc395x_trm_tinfo_sync_period[bIndex]; + pDCB->tinfo.current.period = + dc395x_trm_tinfo_sync_period[bIndex]; + pDCB->tinfo.goal.offset = pDCB->SyncOffset; + pDCB->tinfo.current.offset = pDCB->SyncOffset; + pDCB->SyncPeriod |= (bIndex | ALT_SYNC); +re_prog: + /* + * + * 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); + } + } + } +min6: + *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_int8_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_int8_t *pscsi_status) +{ + +} + +static void +trm_Nop1(PACB pACB, PSRB pSRB, u_int8_t *pscsi_status) +{ + +} + +static void +trm_SetXferRate(PACB pACB,PSRB pSRB, PDCB pDCB) +{ + u_int16_t cnt, i; + u_int8_t bval; + PDCB pDCBTemp; + u_int target_id,target_lun; + + /* + * set all lun device's period , offset + */ + target_id = pSRB->pccb->ccb_h.target_id; + target_lun = pSRB->pccb->ccb_h.target_lun; + TRM_DPRINTF("trm_SetXferRate:target_id= %d ,target_lun= %d \n" + ,target_id,target_lun); + if (!(pDCB->IdentifyMsg & 0x07)) { + if (!pACB->scan_devices[target_id][target_lun]) { + 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; + int intflag; + u_int16_t i,j, cnt; + u_int8_t bval; + u_int target_id,target_lun; + + TRM_DPRINTF("trm_Disconnect...............\n "); + + intflag = splcam(); + 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->TagMask = 0; + 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->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 + */ + if (pDCB->MaxCommand > 1) { + bval = pSRB->TagNumber; + pDCB->TagMask &= (~(1 << bval)); + /* free tag mask */ + } + pDCB->pActiveSRB = 0; + pSRB->SRBState = SRB_FREE; + trm_SRBdone(pACB, pDCB, pSRB); + } + } + splx(intflag); + 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->pTmpSRB; + pDCB->pActiveSRB = pSRB; + } else { + pSRB = pDCB->pActiveSRB; + if (!pSRB || !(pSRB->SRBState & SRB_DISCONNECT)) { + /* + * abort command + */ + pSRB = pACB->pTmpSRB; + 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->SegmentX[0].address = pSRB->SgSenseTemp.address; + pSRB->SegmentX[0].length = pSRB->SgSenseTemp.length; + pcsio->scsi_status = SCSI_STATUS_CHECK_COND; + pccb->ccb_h.status = 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_AUTOSNS_VALID | + CAM_SCSI_STATUS_ERROR; + goto ckc_e; + } else if (status == SCSI_STAT_QUEUEFULL) { + bval = (u_int8_t) pDCB->GoingSRBCnt; + bval--; + pDCB->MaxCommand = bval; + trm_RewaitSRB(pDCB, pSRB); + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pcsio->scsi_status = SCSI_STAT_QUEUEFULL; + pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + goto ckc_e; + } 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; + /* 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*/ + } else { + pSRB->AdaptStatus = 0; + if (pSRB->RetryCnt) { + pSRB->RetryCnt--; + pSRB->TargetStatus = 0; + pSRB->SRBSGIndex = 0; + pSRB->SRBSGListPointer = (PSEG) + &pSRB->SegmentX[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; + 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->MaxCommand = + pACB->TagMaxNum; + pDCB->SyncMode |= + EN_TAG_QUEUING; + pDCB->TagMask = 0; + 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->TagMask = 0; + 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->SegmentX[0].address; + pSRB->SgSenseTemp.length = pSRB->SegmentX[0].length; + pSRB->SegmentX[0].address = (u_long) vtophys(&pcsio->sense_data); + pSRB->SegmentX[0].length = (u_long) pcsio->sense_len; + pSRB->SRBSGListPointer = &pSRB->SegmentX[0]; + 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; + + 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->pDCBACB = pACB; + pDCB->TargetID = target_id; + pDCB->TargetLUN = target_lun; + pDCB->pWaitingSRB = NULL; + pDCB->pGoingSRB = NULL; + pDCB->GoingSRBCnt = 0; + pDCB->pActiveSRB = NULL; + pDCB->TagMask = 0; + pDCB->MaxCommand = 1; + pDCB->DCBFlag = 0; + /* $$$$$$$ */ + 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; + /* $$$$$$$ */ + /* + * 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; + pDCB->MaxNegoPeriod = dc395x_trm_clock_period[ PeriodIndex ] ; + 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.period = pDCB->MaxNegoPeriod; + pDCB->tinfo.user.offset = (pDCB->SyncMode & SYNC_NEGO_ENABLE) ? 15 : 0; + 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_initSRB(PSRB psrb) +{ + + psrb->PhysSRB = vtophys(psrb); +} + +static void +trm_linkSRB(PACB pACB) +{ + u_int16_t i; + + for (i = 0; i < MAX_SRB_CNT; i++) { + if (i != MAX_SRB_CNT - 1) + /* + * link all SRB + */ + pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; + else + /* + * load NULL to NextSRB of the last SRB + */ + pACB->SRB_array[i].pNextSRB = NULL; + /* + * convert and save physical address of SRB to pSRB->PhysSRB + */ + trm_initSRB((PSRB) &pACB->SRB_array[i]); + } +} + + +static void +trm_initACB(PACB pACB, u_int16_t unit) +{ + PNVRAMTYPE pEEpromBuf; + u_int16_t i,j; + + 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->pFreeSRB = pACB->SRB_array; + pACB->AdapterUnit = unit; + pACB->AdaptSCSIID = pEEpromBuf->NvramScsiId; + pACB->AdaptSCSILUN = 0; + pACB->DeviceCnt = 0; + pACB->TagMaxNum = 2 << pEEpromBuf->NvramMaxTag ; + pACB->ACBFlag = 0; + /* + * link all device's SRB Q of this adapter + */ + trm_linkSRB(pACB); + /* + * temp SRB for Q tag used or abord command used + */ + pACB->pTmpSRB = &pACB->TmpSRB; + /* + * convert and save physical address of SRB to pSRB->PhysSRB + */ + trm_initSRB(pACB->pTmpSRB); + /* allocate DCB array for scan device */ + for (i = 0; i < (pACB->max_id +1); i++) { + if (pACB->AdaptSCSIID != i) { + for (j = 0; j < (pACB->max_lun +1); j++) { + pACB->scan_devices[i][j] = 1; + pACB->pDCB[i][j]= (PDCB) malloc ( + sizeof (struct _DCB), M_DEVBUF, M_WAITOK); + trm_initDCB(pACB, + pACB->pDCB[i][j], unit, i, j); + TRM_DPRINTF("pDCB= %8x \n", + (u_int)pACB->pDCB[i][j]); + } + } + } + TRM_DPRINTF("sizeof(struct _DCB)= %8x \n",sizeof(struct _DCB)); + TRM_DPRINTF("sizeof(struct _ACB)= %8x \n",sizeof(struct _ACB)); + TRM_DPRINTF("sizeof(struct _SRB)= %8x \n",sizeof(struct _SRB)); +} + +static void +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 + */ + TRM_write_cmd(pACB, 0x04, 0xFF); + trm_reg_write8(0, TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++) { + TRM_set_data(pACB, bAddr, *bpEeprom); + } + /* + * Write disable + */ + TRM_write_cmd(pACB, 0x04, 0x00); + trm_reg_write8(0 , TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + /* Disable SEEPROM */ + trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) & ~EN_EEPROM), + TRMREG_GEN_CONTROL); + return; +} + +static void +TRM_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData) +{ + int i; + u_int8_t bSendData; + /* + * Send write command & address + */ + + 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); + TRM_wait_30us(pACB); + trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + } + trm_reg_write8(NVR_SELECT , TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + /* + * Disable chip select + */ + trm_reg_write8(0 , TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + trm_reg_write8(NVR_SELECT ,TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + /* + * Wait for write ready + */ + while (1) { + trm_reg_write8((NVR_SELECT | NVR_CLOCK), TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + trm_reg_write8(NVR_SELECT, TRMREG_GEN_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 +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 = 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 +TRM_get_data(PACB pACB, u_int8_t bAddr) +{ + int i; + u_int8_t bReadData, bData = 0; + /* + * Send read command & address + */ + + TRM_write_cmd(pACB, 0x06, bAddr); + + for (i = 0; i < 8; i++) { + /* + * Read data + */ + trm_reg_write8((NVR_SELECT | NVR_CLOCK) , TRMREG_GEN_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; + } + TRM_wait_30us(pACB); + } + /* + * Disable chip select + */ + trm_reg_write8(0, TRMREG_GEN_NVRAM); + return (bData); +} + +static void +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 +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); + TRM_wait_30us(pACB); + trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_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); + TRM_wait_30us(pACB); + trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM); + TRM_wait_30us(pACB); + } + trm_reg_write8(NVR_SELECT, TRMREG_GEN_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; + + 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; + TRM_write_all(pEEpromBuf,pACB); + } + return; +} +static int +trm_initAdapter(PACB pACB, u_int16_t unit, device_t pci_config_id) +{ + 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 PACB +trm_init(u_int16_t unit, device_t pci_config_id) +{ + PACB pACB; + int rid = PCI_BASE_ADDR0; + struct resource *iores; + + pACB = (PACB) device_get_softc(pci_config_id); + if (!pACB) { + printf("trm%d: cannot allocate ACB !\n", unit); + return (NULL); + } + bzero (pACB, sizeof (struct _ACB)); + iores = bus_alloc_resource(pci_config_id, SYS_RES_IOPORT + , &rid, 0, ~0, 1, RF_ACTIVE); + if (iores == NULL) { + printf("trm_init: bus_alloc_resource failed!\n"); + return (NULL); + } + pACB->tag = rman_get_bustag(iores); + pACB->bsh = rman_get_bushandle(iores); + if (bus_dma_tag_create(/*parent_dmat*/ NULL, + /*alignment*/ 1, + /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/ NULL, + /*filterarg*/ NULL, + /*maxsize*/ MAXBSIZE, + /*nsegments*/ TRM_NSEG, + /*maxsegsz*/ TRM_MAXTRANSFER_SIZE, + /*flags*/ BUS_DMA_ALLOCNOW, + &pACB->buffer_dmat) != 0) + { + free(pACB, M_DEVBUF); + return (NULL); + } + trm_check_eeprom(&trm_eepromBuf[unit],pACB); + trm_initACB(pACB, unit); + if (trm_initAdapter(pACB, unit, pci_config_id)) { + printf("trm_initAdapter: initial ERROR\n"); + free(pACB, M_DEVBUF); + return (NULL); + } + return (pACB); +} + +static int +trm_attach(device_t pci_config_id) +{ + struct cam_devq *device_Q; + u_long device_id; + PACB pACB = 0; + int rid = 0; + void *ih; + struct resource *irqres; + int unit = device_get_unit(pci_config_id); + + device_id = pci_get_devid(pci_config_id); + /* + * These cards do not allow memory mapped accesses + */ + if (device_id == PCI_DEVICEID_TRMS1040) { + if ((pACB=trm_init((u_int16_t) unit, + pci_config_id)) == NULL) { + printf("trm%d: trm_init error!\n",unit); + return (ENXIO); + } + } else + 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 + */ + irqres = bus_alloc_resource(pci_config_id, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + if (irqres == NULL || + bus_setup_intr(pci_config_id, irqres, + INTR_TYPE_CAM, trm_Interrupt, pACB, &ih)) { + printf("trm%d: register Interrupt handler error!\n", unit); + free(pACB, M_DEVBUF); + return (ENXIO); + } + device_Q = cam_simq_alloc(MAX_START_JOB); + if (device_Q == NULL){ + printf("trm%d: device_Q == NULL !\n",unit); + free(pACB, M_DEVBUF); + return (ENXIO); + } + /* + * 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, + 1, + 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*/ + free(pACB, M_DEVBUF); + return (ENXIO); + } + if (xpt_bus_register(pACB->psim, 0) != CAM_SUCCESS) { + printf("trm%d: xpt_bus_register fault !\n",unit); + cam_sim_free(pACB->psim, TRUE); + free(pACB, M_DEVBUF); + /* + * cam_sim_free(pACB->psim, TRUE); free_devq + * pACB->psim = NULL; + */ + return (ENXIO); + } + 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)); + cam_sim_free(pACB->psim, /*free_simq*/TRUE); + free(pACB, M_DEVBUF); + /* + * cam_sim_free(pACB->psim, TRUE); free_devq + * pACB->psim = NULL; + */ + return (ENXIO); + } + return (0); +} + +/* +* pci_device +* trm_probe (device_t tag, pcidi_t type) +* +*/ +static int +trm_probe(device_t tag) +{ + + if (pci_get_devid(tag) == PCI_DEVICEID_TRMS1040) { + device_set_desc(tag, + "Tekram DC395U/UW/F DC315/U Fast20 Wide SCSI Adapter"); + return (0); + } else + return (ENXIO); +} + +static int +trm_detach(PACB pACB) +{ + 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); Index: dev/trm/trm.h =================================================================== RCS file: dev/trm/trm.h diff -N dev/trm/trm.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/trm/trm.h 24 May 2002 15:51:38 -0000 @@ -0,0 +1,963 @@ +/* + * File Name : trm.h + * + * Tekram DC395U/UW/F ,DC315/U + * PCI SCSI Bus Master Host Adapter Device Driver + * (SCSI chip set used Tekram ASIC TRM-S1040) + * + * 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. + */ + +#ifndef trm_H +#define trm_H + +/* SCSI CAM */ + +#define TRM_TRANS_CUR 0x01 /* Modify current neogtiation status */ +#define TRM_TRANS_ACTIVE 0x03 /* Assume this is the active target */ +#define TRM_TRANS_GOAL 0x04 /* Modify negotiation goal */ +#define TRM_TRANS_USER 0x08 /* Modify user negotiation settings */ + +struct trm_transinfo { + u_int8_t width; + u_int8_t period; + u_int8_t offset; +}; + +struct trm_target_info { + u_int8_t disc_tag; /* bits define..... */ +#define TRM_CUR_DISCENB 0x01 /* current setting disconnect enable */ +#define TRM_CUR_TAGENB 0x02 /* current setting tag command Q enable */ +#define TRM_USR_DISCENB 0x04 /* user adapter device setting disconnect enable */ +#define TRM_USR_TAGENB 0x08 /* user adapter device setting tag command Q enable*/ + struct trm_transinfo current; /* info of current */ + struct trm_transinfo goal; /* info of after negotiating */ + struct trm_transinfo user; /* info of user adapter device setting */ +}; +/* + * SCSI CAM ** + */ + +/* + * bus_dma_segment_t + * + * Describes a single contiguous DMA transaction. Values + * are suitable for programming into DMA registers. + * + *typedef struct bus_dma_segment + *{ + * bus_addr_t ds_addr; // DMA address + * bus_size_t ds_len; // length of transfer + *} bus_dma_segment_t; + */ + +/*;----------------------Segment Entry------------------------------------*/ +typedef struct _SGentry { + u_long address; + u_long length; +} SGentry, *PSEG; +/* + *----------------------------------------------------------------------- + * feature of chip set MAX value + *----------------------------------------------------------------------- + */ + +#define MAX_ADAPTER_NUM 4 +#define MAX_DEVICES 16 +#define MAX_SG_LISTENTRY 32 +#define MAX_TARGETS 16 +#define MAX_TAGS_CMD_QUEUE 32 /* MAX_CMD_QUEUE 20*/ +#define MAX_CMD_PER_LUN 32 +#define MAX_SRB_CNT MAX_CMD_PER_LUN*4 +#define MAX_START_JOB MAX_CMD_PER_LUN*4 +#define TRM_NSEG (btoc(MAXPHYS) + 1) +#define TRM_MAXTRANSFER_SIZE 0xFFFFFF /* restricted by 24 bit counter */ +#define PAGELEN 4096 + +#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40MHz) */ + +/* + * CAM ccb + * Union of all CCB types for kernel space allocation. This union should + * never be used for manipulating CCBs - its only use is for the allocation + * and deallocation of raw CCB space and is the return type of xpt_ccb_alloc + * and the argument to xpt_ccb_free. + * + *union ccb { + * struct ccb_hdr ccb_h; // For convenience + * struct ccb_scsiio csio; + * struct ccb_getdev cgd; + * struct ccb_getdevlist cgdl; + * struct ccb_pathinq cpi; + * struct ccb_relsim crs; + * struct ccb_setasync csa; + * struct ccb_setdev csd; + * struct ccb_dev_match cdm; + * struct ccb_trans_settings cts; + * struct ccb_calc_geometry ccg; + * struct ccb_abort cab; + * struct ccb_resetbus crb; + * struct ccb_resetdev crd; + * struct ccb_termio tio; + * struct ccb_accept_tio atio; + * struct ccb_scsiio ctio; + * struct ccb_en_lun cel; + * struct ccb_immed_notify cin; + * struct ccb_notify_ack cna; + * struct ccb_eng_inq cei; + * struct ccb_eng_exec cee; + * struct ccb_rescan crcn; + * struct ccb_debug cdbg; + * }; + */ + +/* + *----------------------------------------------------------------------- + * SCSI Request Block + *----------------------------------------------------------------------- + */ +struct _SRB { + u_int8_t CmdBlock[12]; + u_long Segment0[2]; + u_long Segment1[2]; + u_long PhysSRB; + struct _SRB *pNextSRB; + struct _DCB *pSRBDCB; + SGentry SegmentX[MAX_SG_LISTENTRY]; + SGentry SgSenseTemp; + /* + * CAM ccb + */ + union ccb *pccb; + bus_dmamap_t dmamap; + PSEG SRBSGListPointer; /* scatter gather list */ + u_long SRBTotalXferLength; + u_long SRBSGPhyAddr; /* a segment starting address */ + u_int16_t SRBState; + u_int8_t * pMsgPtr; + + u_int8_t SRBSGCount; + u_int8_t SRBSGIndex; + u_int8_t MsgInBuf[6]; + u_int8_t MsgOutBuf[6]; + + u_int8_t AdaptStatus; + u_int8_t TargetStatus; + u_int8_t MsgCnt; + u_int8_t TagNumber; + + u_int8_t SRBStatus; + u_int8_t RetryCnt; + /* b0-AutoReqSense,b6-Read,b7-write */ + /* b4-settimeout,b5-Residual valid */ + u_int8_t SRBFlag; + u_int8_t ScsiCmdLen; + u_int8_t ScsiPhase; + u_int8_t Reserved[3]; /*;for dword alignment */ +}; +typedef struct _SRB TRM_SRB, *PSRB; + +/* + *----------------------------------------------------------------------- + * Device Control Block + *----------------------------------------------------------------------- + */ +struct _DCB +{ + struct _DCB *pNextDCB; + struct _ACB *pDCBACB; + + PSRB pWaitingSRB; + PSRB pWaitLastSRB; + + PSRB pGoingSRB; + PSRB pGoingLastSRB; + + PSRB pActiveSRB; + PSRB RevSRB; + + u_long TagMask; + + u_int16_t GoingSRBCnt; + u_int16_t WaitSRBCnt; + + u_int8_t TargetID; /*; SCSI Target ID (SCSI Only) */ + u_int8_t TargetLUN; /*; SCSI Log. Unit (SCSI Only) */ + u_int8_t DCBFlag; + u_int8_t DevType; + + u_int8_t SyncMode; /* mode ? (1 sync):(0 async) */ + u_int8_t MaxNegoPeriod; /* for nego. */ + u_int8_t SyncPeriod; /* for reg. */ + u_int8_t SyncOffset; /* for reg. and nego.(low nibble) */ + + struct trm_target_info tinfo; /* 10 bytes */ + + u_int16_t MaxCommand; + u_int8_t DevMode; + u_int8_t AdpMode; + + u_int8_t IdentifyMsg; + u_int8_t Reserved[3]; /*for dword alignment */ +}; +typedef struct _DCB TRM_DCB, *PDCB; + +/* + *----------------------------------------------------------------------- + * Adapter Control Block + *----------------------------------------------------------------------- + */ +struct _ACB +{ + bus_space_tag_t tag; + bus_space_handle_t bsh; + bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ + struct _ACB *pNextACB; + /* + * CAM SIM/XPT + */ + struct cam_sim *psim; + struct cam_path *ppath; + + TRM_SRB SRB_array[MAX_SRB_CNT]; /* */ + + TRM_SRB TmpSRB; + + PSRB pTmpSRB; + PSRB RevSRB; + + PSRB pFreeSRB; + PDCB pActiveDCB; + + PDCB pLinkDCB; + PDCB pDCBRunRobin; + + PDCB pDCB[16][8]; + + u_int16_t max_id; + u_int16_t max_lun; + + u_int16_t IOPortBase; + u_int16_t AdapterUnit; /*; nth Adapter this driver */ + + u_int8_t msgin123[4]; + + u_int8_t scan_devices[16][8]; + + u_int8_t AdaptSCSIID; /*; Adapter SCSI Target ID */ + u_int8_t AdaptSCSILUN; /*; Adapter SCSI LUN */ + u_int8_t DeviceCnt; + u_int8_t ACBFlag; + + u_int8_t TagMaxNum; + u_int8_t Config; + u_int8_t Reserved[2]; /* for dword alignment */ +}; +typedef struct _ACB TRM_ACB, *PACB; +/* + * ----SRB State machine definition + */ +#define SRB_FREE 0x0000 +#define SRB_WAIT 0x0001 +#define SRB_READY 0x0002 +#define SRB_MSGOUT 0x0004 /*arbitration+msg_out 1st byte*/ +#define SRB_MSGIN 0x0008 +#define SRB_EXTEND_MSGIN 0x0010 +#define SRB_COMMAND 0x0020 +#define SRB_START_ 0x0040 /*arbitration+msg_out+command_out*/ +#define SRB_DISCONNECT 0x0080 +#define SRB_DATA_XFER 0x0100 +#define SRB_XFERPAD 0x0200 +#define SRB_STATUS 0x0400 +#define SRB_COMPLETED 0x0800 +#define SRB_ABORT_SENT 0x1000 +#define SRB_DO_SYNC_NEGO 0x2000 +#define SRB_DO_WIDE_NEGO 0x4000 +#define SRB_UNEXPECT_RESEL 0x8000 +/* + * + * ACB Config + * + */ +#define HCC_WIDE_CARD 0x20 +#define HCC_SCSI_RESET 0x10 +#define HCC_PARITY 0x08 +#define HCC_AUTOTERM 0x04 +#define HCC_LOW8TERM 0x02 +#define HCC_UP8TERM 0x01 +/* + * ---ACB Flag + */ +#define RESET_DEV 0x00000001 +#define RESET_DETECT 0x00000002 +#define RESET_DONE 0x00000004 + +/* + * ---DCB Flag + */ +#define ABORT_DEV_ 0x00000001 + +/* + * ---SRB status + */ +#define SRB_OK 0x00000001 +#define ABORTION 0x00000002 +#define OVER_RUN 0x00000004 +#define UNDER_RUN 0x00000008 +#define PARITY_ERROR 0x00000010 +#define SRB_ERROR 0x00000020 + +/* + * ---SRB Flag + */ +#define DATAOUT 0x00000080 +#define DATAIN 0x00000040 +#define RESIDUAL_VALID 0x00000020 +#define ENABLE_TIMER 0x00000010 +#define RESET_DEV0 0x00000004 +#define ABORT_DEV 0x00000002 +#define AUTO_REQSENSE 0x00000001 + +/* + * ---Adapter status + */ +#define H_STATUS_GOOD 0x00 +#define H_SEL_TIMEOUT 0x11 +#define H_OVER_UNDER_RUN 0x12 +#define H_UNEXP_BUS_FREE 0x13 +#define H_TARGET_PHASE_F 0x14 +#define H_INVALID_CCB_OP 0x16 +#define H_LINK_CCB_BAD 0x17 +#define H_BAD_TARGET_DIR 0x18 +#define H_DUPLICATE_CCB 0x19 +#define H_BAD_CCB_OR_SG 0x1A +#define H_ABORT 0x0FF + +/* + * ---SCSI Status byte codes + */ +#define SCSI_STAT_GOOD 0x00 /*; Good status */ +#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ +#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ +#define SCSI_STAT_BUSY 0x08 /*; Target busy status */ +#define SCSI_STAT_INTER 0x10 /*; Intermediate status */ +#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */ +#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */ +#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */ +#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */ +#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */ +#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */ +#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */ + +/* + * ---Sync_Mode + */ +#define SYNC_WIDE_TAG_ATNT_DISABLE 0x00000000 +#define SYNC_NEGO_ENABLE 0x00000001 +#define SYNC_NEGO_DONE 0x00000002 +#define WIDE_NEGO_ENABLE 0x00000004 +#define WIDE_NEGO_DONE 0x00000008 +#define EN_TAG_QUEUING 0x00000010 +#define EN_ATN_STOP 0x00000020 + +#define SYNC_NEGO_OFFSET 15 +/* + * ---SCSI bus phase + */ +#define SCSI_DATA_OUT_ 0 +#define SCSI_DATA_IN_ 1 +#define SCSI_COMMAND 2 +#define SCSI_STATUS_ 3 +#define SCSI_NOP0 4 +#define SCSI_NOP1 5 +#define SCSI_MSG_OUT 6 +#define SCSI_MSG_IN 7 + +/* + * ----SCSI MSG u_int8_t + */ +#define MSG_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_SAVE_PTR 0x02 +#define MSG_RESTORE_PTR 0x03 +#define MSG_DISCONNECT 0x04 +#define MSG_INITIATOR_ERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT_ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define MSG_LINK_CMD_COMPL 0x0A +#define MSG_LINK_CMD_COMPL_FLG 0x0B +#define MSG_BUS_RESET 0x0C +#define MSG_ABORT_TAG 0x0D +#define MSG_SIMPLE_QTAG 0x20 +#define MSG_HEAD_QTAG 0x21 +#define MSG_ORDER_QTAG 0x22 +#define MSG_IGNOREWIDE 0x23 +#define MSG_IDENTIFY 0x80 +#define MSG_HOST_ID 0xC0 +/* bus wide length */ +#define MSG_EXT_WDTR_BUS_8_BIT 0x00 +#define MSG_EXT_WDTR_BUS_16_BIT 0x01 +#define MSG_EXT_WDTR_BUS_32_BIT 0x02 +/* + * ----SCSI STATUS u_int8_t + */ +#define STATUS_GOOD 0x00 +#define CHECK_CONDITION_ 0x02 +#define STATUS_BUSY 0x08 +#define STATUS_INTERMEDIATE 0x10 +#define RESERVE_CONFLICT 0x18 + +/* + * ---- cmd->result + */ +#define STATUS_MASK_ 0xFF +#define MSG_MASK 0xFF00 +#define RETURN_MASK 0xFF0000 + +/* + * Inquiry Data format + */ + +typedef struct _SCSIInqData { /* INQ */ + + u_int8_t DevType; /* Periph Qualifier & Periph Dev Type */ + u_int8_t RMB_TypeMod; /* rem media bit & Dev Type Modifier */ + u_int8_t Vers; /* ISO, ECMA, & ANSI versions */ + u_int8_t RDF; /* AEN, TRMIOP, & response data format*/ + u_int8_t AddLen; /* length of additional data */ + u_int8_t Res1; /* reserved */ + u_int8_t Res2; /* reserved */ + u_int8_t Flags; /* RelADr,Wbus32,Wbus16,Sync,etc. */ + u_int8_t VendorID[8]; /* Vendor Identification */ + u_int8_t ProductID[16]; /* Product Identification */ + u_int8_t ProductRev[4]; /* Product Revision */ +} SCSI_INQDATA, *PSCSI_INQDATA; + + +/* + * Inquiry byte 0 masks + */ +#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ +#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ +/* + * Inquiry byte 1 mask + */ +#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */ +/* + * Peripheral Device Type definitions + */ +#define SCSI_DASD 0x00 /* Direct-access Device */ +#define SCSI_SEQACESS 0x01 /* Sequential-access device */ +#define SCSI_PRINTER 0x02 /* Printer device */ +#define SCSI_PROCESSOR 0x03 /* Processor device */ +#define SCSI_WRITEONCE 0x04 /* Write-once device */ +#define SCSI_CDROM 0x05 /* CD-ROM device */ +#define SCSI_SCANNER 0x06 /* Scanner device */ +#define SCSI_OPTICAL 0x07 /* Optical memory device */ +#define SCSI_MEDCHGR 0x08 /* Medium changer device */ +#define SCSI_COMM 0x09 /* Communications device */ +#define SCSI_NODEV 0x1F /* Unknown or no device type */ +/* + * Inquiry flag definitions (Inq data byte 7) + */ +#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing*/ +#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */ +#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */ +#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */ +#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */ +#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */ +#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */ +/* + *========================================================== + * EEPROM byte offset + *========================================================== + */ +typedef struct _EEprom { + u_int8_t EE_MODE1; + u_int8_t EE_SPEED; + u_int8_t xx1; + u_int8_t xx2; +} EEprom, *PEEprom; + +#define EE_ADAPT_SCSI_ID 64 +#define EE_MODE2 65 +#define EE_DELAY 66 +#define EE_TAG_CMD_NUM 67 + +/* + * EE_MODE1 bits definition + */ +#define PARITY_CHK_ 0x00000001 +#define SYNC_NEGO_ 0x00000002 +#define EN_DISCONNECT_ 0x00000004 +#define SEND_START_ 0x00000008 +#define TAG_QUEUING_ 0x00000010 + +/* + * EE_MODE2 bits definition + */ +#define MORE2_DRV 0x00000001 +#define GREATER_1G 0x00000002 +#define RST_SCSI_BUS 0x00000004 +#define ACTIVE_NEGATION 0x00000008 +#define NO_SEEK 0x00000010 +#define LUN_CHECK 0x00000020 + +#define ENABLE_CE 0x01 +#define DISABLE_CE 0x00 +#define EEPROM_READ 0x80 + +/* + * The PCI configuration register offset for TRM_S1040 + * Registers bit Definition + */ +#define TRMREG_ID 0x00 /* Vendor and Device ID */ +#define TRMREG_COMMAND 0x04 /* PCI command register */ +#define TRMREG_IOBASE 0x10 /* I/O Space base address */ +#define TRMREG_ROMBASE 0x30 /* Expansion ROM Base Address */ +#define TRMREG_INTLINE 0x3C /* Interrupt line */ + +/* + * + * The SCSI register offset for TRM_S1040 + * + */ +#define TRMREG_SCSI_STATUS 0x80 /* SCSI Status (R) */ +/* ######### */ +#define COMMANDPHASEDONE 0x2000 /* SCSI command phase done */ +#define SCSIXFERDONE 0x0800 /* SCSI SCSI transfer done */ +#define SCSIXFERCNT_2_ZERO 0x0100 /* SCSI SCSI transfer count to zero*/ +#define SCSIINTERRUPT 0x0080 /* SCSI interrupt pending */ +#define COMMANDABORT 0x0040 /* SCSI command abort */ +#define SEQUENCERACTIVE 0x0020 /* SCSI sequencer active */ +#define PHASEMISMATCH 0x0010 /* SCSI phase mismatch */ +#define PARITYERROR 0x0008 /* SCSI parity error */ + +#define PHASEMASK 0x0007 /* Phase MSG/CD/IO */ +#define PH_DATA_OUT 0x00 /* Data out phase */ +#define PH_DATA_IN 0x01 /* Data in phase */ +#define PH_COMMAND 0x02 /* Command phase */ +#define PH_STATUS 0x03 /* Status phase */ +#define PH_BUS_FREE 0x05 /* Invalid phase used as bus free */ +#define PH_MSG_OUT 0x06 /* Message out phase */ +#define PH_MSG_IN 0x07 /* Message in phase */ + +#define TRMREG_SCSI_CONTROL 0x80 /* SCSI Control (W) */ +/* ######### */ +#define DO_CLRATN 0x0400 /* Clear ATN */ +#define DO_SETATN 0x0200 /* Set ATN */ +#define DO_CMDABORT 0x0100 /* Abort SCSI command */ +#define DO_RSTMODULE 0x0010 /* Reset SCSI chip */ +#define DO_RSTSCSI 0x0008 /* Reset SCSI bus */ +#define DO_CLRFIFO 0x0004 /* Clear SCSI transfer FIFO */ +#define DO_DATALATCH 0x0002 /* Enable SCSI bus data latch */ +#define DO_HWRESELECT 0x0001 /* Enable hardware reselection */ +#define TRMREG_SCSI_FIFOCNT 0x82 /* SCSI FIFO Counter 5bits(R) */ +#define TRMREG_SCSI_SIGNAL 0x83 /* SCSI low level signal (R/W) */ +#define TRMREG_SCSI_INTSTATUS 0x84 /* SCSI Interrupt Status (R) */ +/* ######### */ +#define INT_SCAM 0x80 /* SCAM selection interrupt */ +#define INT_SELECT 0x40 /* Selection interrupt */ +#define INT_SELTIMEOUT 0x20 /* Selection timeout interrupt */ +#define INT_DISCONNECT 0x10 /* Bus disconnected interrupt */ +#define INT_RESELECTED 0x08 /* Reselected interrupt */ +#define INT_SCSIRESET 0x04 /* SCSI reset detected interrupt*/ +#define INT_BUSSERVICE 0x02 /* Bus service interrupt */ +#define INT_CMDDONE 0x01 /* SCSI command done interrupt */ +#define TRMREG_SCSI_OFFSET 0x84 /* SCSI Offset Count (W) */ +/* + * Bit Name Definition + * 07-05 0 RSVD Reversed. Always 0. + * 04 0 OFFSET4 Reversed for LVDS. Always 0. + * 03-00 0 OFFSET[03:00] Offset number from 0 to 15 + */ +#define TRMREG_SCSI_SYNC 0x85 /* SCSI Synchronous Control (R/W)*/ +/* ######### */ +#define LVDS_SYNC 0x20 /* Enable LVDS synchronous */ +#define WIDE_SYNC 0x10 /* Enable WIDE synchronous */ +#define ALT_SYNC 0x08 /* Enable Fast-20 alternate synchronous */ +/* + * SYNCM 7 6 5 4 3 2 1 0 + * Name RSVD RSVD LVDS WIDE ALTPERD PERIOD2 PERIOD1 PERIOD0 + * Default 0 0 0 0 0 0 0 0 + * + * + * Bit Name Definition + * 07-06 0 RSVD Reversed. Always read 0 + * 05 0 LVDS Reversed. Always read 0 + * 04 0 WIDE/WSCSI Enable wide (16-bits) SCSI transfer. + * 03 0 ALTPERD/ALTPD Alternate (Sync./Period) mode. + * + * @@ When this bit is set, + * the synchronous period bits 2:0 + * in the Synchronous Mode register + * are used to transfer data + * at the Fast-20 rate. + * @@ When this bit is reset, + * the synchronous period bits 2:0 + * in the Synchronous Mode Register + * are used to transfer data + * at the Fast-40 rate. + * + * 02-00 0 PERIOD[2:0]/SXPD[02:00] Synchronous SCSI Transfer Rate. + * These 3 bits specify + * the Synchronous SCSI Transfer Rate + * for Fast-20 and Fast-10. + * These bits are also reset + * by a SCSI Bus reset. + * + * For Fast-10 bit ALTPD = 0 and LVDS = 0 + * and 0x00000004,0x00000002,0x00000001 is defined as follows : + * + * 000 100ns, 10.0 Mbytes/s + * 001 150ns, 6.6 Mbytes/s + * 010 200ns, 5.0 Mbytes/s + * 011 250ns, 4.0 Mbytes/s + * 100 300ns, 3.3 Mbytes/s + * 101 350ns, 2.8 Mbytes/s + * 110 400ns, 2.5 Mbytes/s + * 111 450ns, 2.2 Mbytes/s + * + * For Fast-20 bit ALTPD = 1 and LVDS = 0 + * and 0x00000004,0x00000002,0x00000001 is defined as follows : + * + * 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 + * + * For Fast-40 bit ALTPD = 0 and LVDS = 1 + * and 0x00000004,0x00000002,0x00000001 is defined as follows : + * + * 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 + */ + +/* + *************************************** + */ +#define TRMREG_SCSI_TARGETID 0x86 /* SCSI Target ID (R/W) */ +/* + *************************************** + */ +#define TRMREG_SCSI_IDMSG 0x87 /* SCSI Identify Message (R) */ +/* + *************************************** + */ +#define TRMREG_SCSI_HOSTID 0x87 /* SCSI Host ID (W) */ +/* + *************************************** + */ +#define TRMREG_SCSI_COUNTER 0x88 /* SCSI Transfer Counter 24bits(R/W)*/ +/* + *************************************** + */ +#define TRMREG_SCSI_INTEN 0x8C /* SCSI Interrupt Enable (R/W) */ +/* ######### */ +#define EN_SCAM 0x80 /* Enable SCAM selection interrupt*/ +#define EN_SELECT 0x40 /* Enable selection interrupt */ +#define EN_SELTIMEOUT 0x20 /* Enable selection timeout interrupt*/ +#define EN_DISCONNECT 0x10 /* Enable bus disconnected interrupt*/ +#define EN_RESELECTED 0x08 /* Enable reselected interrupt */ +#define EN_SCSIRESET 0x04 /* Enable SCSI reset detected interrupt*/ +#define EN_BUSSERVICE 0x02 /* Enable bus service interrupt */ +#define EN_CMDDONE 0x01 /* Enable SCSI command done interrupt*/ +/* + *************************************** + */ +#define TRMREG_SCSI_CONFIG0 0x8D /* SCSI Configuration 0 (R/W) */ +/* ######### */ +#define PHASELATCH 0x40 /* Enable phase latch */ +#define INITIATOR 0x20 /* Enable initiator mode */ +#define PARITYCHECK 0x10 /* Enable parity check */ +#define BLOCKRST 0x01 /* Disable SCSI reset1 */ +/* + *************************************** + */ +#define TRMREG_SCSI_CONFIG1 0x8E /* SCSI Configuration 1 (R/W) */ +/* ######### */ +#define ACTIVE_NEGPLUS 0x10 /* Enhance active negation */ +#define FILTER_DISABLE 0x08 /* Disable SCSI data filter */ +#define ACTIVE_NEG 0x02 /* Enable active negation */ +/* + *************************************** + */ +#define TRMREG_SCSI_CONFIG2 0x8F /* SCSI Configuration 2 (R/W) */ +/* + *************************************** + */ +#define TRMREG_SCSI_COMMAND 0x90 /* SCSI Command (R/W) */ +/* ######### */ +#define SCMD_COMP 0x12 /* Command complete */ +#define SCMD_SEL_ATN 0x60 /* Selection with ATN */ +#define SCMD_SEL_ATN3 0x64 /* Selection with ATN3 */ +#define SCMD_SEL_ATNSTOP 0xB8 /* Selection with ATN and Stop */ +#define SCMD_FIFO_OUT 0xC0 /* SCSI FIFO transfer out */ +#define SCMD_DMA_OUT 0xC1 /* SCSI DMA transfer out */ +#define SCMD_FIFO_IN 0xC2 /* SCSI FIFO transfer in */ +#define SCMD_DMA_IN 0xC3 /* SCSI DMA transfer in */ +#define SCMD_MSGACCEPT 0xD8 /* Message accept */ +/* + * Code Command Description + * + * 02 Enable reselection with FIFO + * 40 Select without ATN with FIFO + * 60 Select with ATN with FIFO + * 64 Select with ATN3 with FIFO + * A0 Select with ATN and stop with FIFO + * C0 Transfer information out with FIFO + * C1 Transfer information out with DMA + * C2 Transfer information in with FIFO + * C3 Transfer information in with DMA + * 12 Initiator command complete with FIFO + * 50 Initiator transfer information out sequence without ATN with FIFO + * 70 Initiator transfer information out sequence with ATN with FIFO + * 74 Initiator transfer information out sequence with ATN3 with FIFO + * 52 Initiator transfer information in sequence without ATN with FIFO + * 72 Initiator transfer information in sequence with ATN with FIFO + * 76 Initiator transfer information in sequence with ATN3 with FIFO + * 90 Initiator transfer information out command complete with FIFO + * 92 Initiator transfer information in command complete with FIFO + * D2 Enable selection + * 08 Reselection + * 48 Disconnect command with FIFO + * 88 Terminate command with FIFO + * C8 Target command complete with FIFO + * 18 SCAM Arbitration/ Selection + * 5A Enable reselection + * 98 Select without ATN with FIFO + * B8 Select with ATN with FIFO + * D8 Message Accepted + * 58 NOP + */ +/* + *************************************** + */ +#define TRMREG_SCSI_TIMEOUT 0x91 /* SCSI Time Out Value (R/W) */ +/* + *************************************** + */ +#define TRMREG_SCSI_FIFO 0x98 /* SCSI FIFO (R/W) */ +/* + *************************************** + */ +#define TRMREG_SCSI_TCR0 0x9C /* SCSI Target Control 0 (R/W) */ +/* ######### */ +#define TCR0_WIDE_NEGO_DONE 0x8000 /* Wide nego done */ +#define TCR0_SYNC_NEGO_DONE 0x4000 /* Synchronous nego done*/ +#define TCR0_ENABLE_LVDS 0x2000 /* Enable LVDS synchronous*/ +#define TCR0_ENABLE_WIDE 0x1000 /* Enable WIDE synchronous*/ +#define TCR0_ENABLE_ALT 0x0800 /* Enable alternate synchronous */ +#define TCR0_PERIOD_MASK 0x0700 /* Transfer rate */ + +#define TCR0_DO_WIDE_NEGO 0x0080 /* Do wide NEGO */ +#define TCR0_DO_SYNC_NEGO 0x0040 /* Do sync NEGO */ +#define TCR0_DISCONNECT_EN 0x0020 /* Disconnection enable */ +#define TCR0_OFFSET_MASK 0x001F /* Offset number */ +/* + *************************************** + */ +#define TRMREG_SCSI_TCR1 0x9E /* SCSI Target Control 1 (R/W) */ +/* ######### */ +#define MAXTAG_MASK 0x7F00 /* Maximum tags (127) */ +#define NON_TAG_BUSY 0x0080 /* Non tag command active */ +#define ACTTAG_MASK 0x007F /* Active tags */ +/* + * + * The DMA register offset for TRM_S1040 + * + */ +#define TRMREG_DMA_COMMAND 0xA0 /* DMA Command (R/W) */ +/* ######### */ +#define XFERDATAIN 0x0103 /* Transfer data in */ +#define XFERDATAOUT 0x0102 /* Transfer data out */ +/* + *************************************** + */ +#define TRMREG_DMA_FIFOCNT 0xA1 /* DMA FIFO Counter (R) */ +/* + *************************************** + */ +#define TRMREG_DMA_CONTROL 0xA1 /* DMA Control (W) */ +/* ######### */ +#define STOPDMAXFER 0x08 /* Stop DMA transfer */ +#define ABORTXFER 0x04 /* Abort DMA transfer */ +#define CLRXFIFO 0x02 /* Clear DMA transfer FIFO */ +#define STARTDMAXFER 0x01 /* Start DMA transfer */ +/* + *************************************** + */ +#define TRMREG_DMA_STATUS 0xA3 /* DMA Interrupt Status (R/W) */ +/* ######### */ +#define XFERPENDING 0x80 /* Transfer pending */ +#define DMAXFERCOMP 0x02 /* Bus Master XFER Complete status */ +#define SCSICOMP 0x01 /* SCSI complete interrupt */ +/* + *************************************** + */ +#define TRMREG_DMA_INTEN 0xA4 /* DMA Interrupt Enable (R/W)*/ +/* ######### */ +#define EN_SCSIINTR 0x01 /* Enable SCSI complete interrupt */ +/* + *************************************** + */ +#define TRMREG_DMA_CONFIG 0xA6 /* DMA Configuration (R/W) */ +/* ######### */ +#define DMA_ENHANCE 0x8000 /* Enable DMA enhance feature */ +/* + *************************************** + */ +#define TRMREG_DMA_XCNT 0xA8 /* DMA Transfer Counter (R/W)*/ +/* + *************************************** + */ +#define TRMREG_DMA_CXCNT 0xAC /* DMA Current Transfer Counter (R) */ +/* + *************************************** + */ +#define TRMREG_DMA_XLOWADDR 0xB0 /* DMA Transfer Physical Low Address */ +/* + *************************************** + */ +#define TRMREG_DMA_XHIGHADDR 0xB4 /* DMA Transfer Physical High Address */ + +/* + * + * The general register offset for TRM_S1040 + * + */ +#define TRMREG_GEN_CONTROL 0xD4 /* Global Control */ +/* ######### */ +#define EN_EEPROM 0x10 /* Enable EEPROM programming */ +#define AUTOTERM 0x04 /* Enable Auto SCSI terminator */ +#define LOW8TERM 0x02 /* Enable Lower 8 bit SCSI terminator */ +#define UP8TERM 0x01 /* Enable Upper 8 bit SCSI terminator */ +/* + *************************************** + */ +#define TRMREG_GEN_STATUS 0xD5 /* Global Status */ +/* ######### */ +#define GTIMEOUT 0x80 /* Global timer reach 0 */ +#define CON5068 0x10 /* External 50/68 pin connected */ +#define CON68 0x08 /* Internal 68 pin connected */ +#define CON50 0x04 /* Internal 50 pin connected */ +#define WIDESCSI 0x02 /* Wide SCSI card */ +/* + *************************************** + */ +#define TRMREG_GEN_NVRAM 0xD6 /* Serial NON-VOLATILE RAM port */ +/* ######### */ +#define NVR_BITOUT 0x08 /* Serial data out */ +#define NVR_BITIN 0x04 /* Serial data in */ +#define NVR_CLOCK 0x02 /* Serial clock */ +#define NVR_SELECT 0x01 /* Serial select */ +/* + *************************************** + */ +#define TRMREG_GEN_EDATA 0xD7 /* Parallel EEPROM data port */ +/* + *************************************** + */ +#define TRMREG_GEN_EADDRESS 0xD8 /* Parallel EEPROM address */ +/* + *************************************** + */ +#define TRMREG_GEN_TIMER 0xDB /* Global timer */ + +/* + * The SEEPROM structure for TRM_S1040 + */ +typedef struct NVRAM_TARGET_STRUCT +{ + u_int8_t NvmTarCfg0; /* Target configuration byte 0 */ + u_int8_t NvmTarPeriod; /* Target period */ + u_int8_t NvmTarCfg2; /* Target configuration byte 2 */ + u_int8_t NvmTarCfg3; /* Target configuration byte 3 */ +} NVRAMTARGETTYPE; +/* NvmTarCfg0: Target configuration byte 0 :..pDCB->DevMode */ +#define NTC_DO_WIDE_NEGO 0x20 /* Wide negotiate */ +#define NTC_DO_TAG_QUEUING 0x10 /* Enable SCSI tag queuing */ +#define NTC_DO_SEND_START 0x08 /* Send start command SPINUP*/ +#define NTC_DO_DISCONNECT 0x04 /* Enable SCSI disconnect */ +#define NTC_DO_SYNC_NEGO 0x02 /* Sync negotiation */ +#define NTC_DO_PARITY_CHK 0x01 /* (it sould define at NAC ) + Parity check enable */ + +/* + * + * + * + */ +typedef struct NVRAM_STRUC { + u_int8_t NvramSubVendorID[2]; /*0,1 Sub Vendor ID */ + u_int8_t NvramSubSysID[2]; /*2,3 Sub System ID*/ + u_int8_t NvramSubClass; /*4 Sub Class */ + u_int8_t NvramVendorID[2]; /*5,6 Vendor ID */ + u_int8_t NvramDeviceID[2]; /*7,8 Device ID */ + u_int8_t NvramReserved; /*9 Reserved */ + NVRAMTARGETTYPE NvramTarget[MAX_TARGETS];/* *10,11,12,13 + *14,15,16,17 * .... + * .... + *70,71,72,73 + */ + u_int8_t NvramScsiId; /*74 Host Adapter SCSI ID */ + u_int8_t NvramChannelCfg; /*75 Channel configuration */ + u_int8_t NvramDelayTime; /*76 Power on delay time */ + u_int8_t NvramMaxTag; /*77 Maximum tags */ + u_int8_t NvramReserved0; /*78 */ + u_int8_t NvramBootTarget; /*79 */ + u_int8_t NvramBootLun; /*80 */ + u_int8_t NvramReserved1; /*81 */ + u_int16_t Reserved[22]; /*82,..125 */ + u_int16_t NvramCheckSum; /*126,127*/ +} NVRAMTYPE,*PNVRAMTYPE; +/* Nvram Initiater bits definition */ +#define MORE2_DRV 0x00000001 +#define GREATER_1G 0x00000002 +#define RST_SCSI_BUS 0x00000004 +#define ACTIVE_NEGATION 0x00000008 +#define NO_SEEK 0x00000010 +#define LUN_CHECK 0x00000020 + +/* Nvram Adapter Cfg bits definition */ +#define NAC_SCANLUN 0x20 /* Include LUN as BIOS device*/ +#define NAC_POWERON_SCSI_RESET 0x04 /* Power on reset enable */ +#define NAC_GREATER_1G 0x02 /* > 1G support enable */ +#define NAC_GT2DRIVES 0x01 /* Support more than 2 drives*/ +/* + *#define NAC_DO_PARITY_CHK 0x08 // Parity check enable + */ + +#endif /* trm_H */ Index: modules/Makefile =================================================================== RCS file: /home/ncvs/src/sys/modules/Makefile,v retrieving revision 1.267 diff -u -p -r1.267 Makefile --- modules/Makefile 7 Oct 2002 04:08:07 -0000 1.267 +++ modules/Makefile 13 Oct 2002 14:44:38 -0000 @@ -94,6 +94,7 @@ SUBDIR= 3dfx \ ti \ tl \ twe \ + trm \ tx \ txp \ ubsec \ Index: modules/trm/Makefile =================================================================== RCS file: modules/trm/Makefile diff -N modules/trm/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/trm/Makefile 23 Aug 2002 23:37:49 -0000 @@ -0,0 +1,10 @@ +.PATH: ${.CURDIR}/../../dev/trm + +KMOD= trm +SRCS= trm.c trm.h opt_cam.h device_if.h bus_if.h \ + opt_scsi.h pci_if.h + +opt_scsi.h: + echo "#define SCSI_DELAY 15000" > opt_scsi.h + +.include