diff options
Diffstat (limited to 'sys/dev/trm/trm.c')
-rw-r--r-- | sys/dev/trm/trm.c | 3702 |
1 files changed, 3702 insertions, 0 deletions
diff --git a/sys/dev/trm/trm.c b/sys/dev/trm/trm.c new file mode 100644 index 0000000..dda9e87 --- /dev/null +++ b/sys/dev/trm/trm.c @@ -0,0 +1,3702 @@ +/* + * O.S : FreeBSD CAM + * FILE NAME : trm.c + * BY : C.L. Huang (ching@tekram.com.tw) + * Erich Chen (erich@tekram.com.tw) + * Description: Device Driver for Tekram SCSI adapters + * DC395U/UW/F ,DC315/U(TRM-S1040) + * DC395U2D/U2W(TRM-S2080) + * PCI SCSI Bus Master Host Adapter + * (SCSI chip set used Tekram ASIC TRM-S1040,TRM-S2080) + *(C)Copyright 1995-2001 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 + * 1.09 11/03/2000 ERICH CHEN Modify for 4.1.R ,new sim + * 1.10 10/10/2001 Oscar Feng Fixed CAM rescan hang up bug. + * 1.11 10/13/2001 Oscar Feng Fixed wrong Async speed display bug. + */ + +/* + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Imported into FreeBSD source repository, and updated to compile under + * FreeBSD-3.0-DEVELOPMENT, by Stefan Esser <se@FreeBSD.Org>, 1996-12-17 + */ + +/* + * Updated to compile under FreeBSD 5.0-CURRENT by Olivier Houchard + * <doginou@ci0.org>, 2002-03-04 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#if __FreeBSD_version >= 500000 +#include <sys/bio.h> +#endif +#include <sys/buf.h> +#include <sys/bus.h> +#include <sys/kernel.h> + +#include <vm/vm.h> +#include <vm/pmap.h> + +#include <pci/pcivar.h> +#include <pci/pcireg.h> +#include <machine/resource.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> +#include <machine/clock.h> +#include <sys/rman.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/cam_debug.h> + +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_message.h> + +#include <dev/trm/trm.h> + +#define trm_reg_read8(reg) bus_space_read_1(pACB->tag, pACB->bsh, reg) +#define trm_reg_read16(reg) bus_space_read_2(pACB->tag, pACB->bsh, reg) +#define trm_reg_read32(reg) bus_space_read_4(pACB->tag, pACB->bsh, reg) +#define trm_reg_write8(value,reg) bus_space_write_1(pACB->tag, pACB->bsh,\ + reg, value) +#define trm_reg_write16(value,reg) bus_space_write_2(pACB->tag, pACB->bsh,\ + reg, value) +#define trm_reg_write32(value,reg) bus_space_write_4(pACB->tag, pACB->bsh,\ + reg, value) + +#define PCI_Vendor_ID_TEKRAM 0x1DE1 +#define PCI_Device_ID_TRM_S1040 0x0391 +#define PCI_DEVICEID_TRMS1040 0x03911DE1 +#define PCI_DEVICEID_TRMS2080 0x03921DE1 + +#ifdef trm_DEBUG1 +#define TRM_DPRINTF(fmt, arg...) printf("trm: " fmt, ##arg) +#else +#define TRM_DPRINTF(fmt, arg...) {} +#endif /* TRM_DEBUG */ + +static void trm_check_eeprom(PNVRAMTYPE pEEpromBuf,PACB pACB); +static void NVRAM_trm_read_all(PNVRAMTYPE pEEpromBuf,PACB pACB); +static u_int8_t NVRAM_trm_get_data(PACB pACB, u_int8_t bAddr); +static void NVRAM_trm_write_all(PNVRAMTYPE pEEpromBuf,PACB pACB); +static void NVRAM_trm_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData); +static void NVRAM_trm_write_cmd(PACB pACB, u_int8_t bCmd, u_int8_t bAddr); +static void NVRAM_trm_wait_30us(PACB pACB); + +static void trm_Interrupt(void *vpACB); +static void trm_DataOutPhase0(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_DataInPhase0(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_CommandPhase0(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_StatusPhase0(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_MsgOutPhase0(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_MsgInPhase0(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_DataOutPhase1(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_DataInPhase1(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_CommandPhase1(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_StatusPhase1(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_MsgOutPhase1(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_MsgInPhase1(PACB pACB, PSRB pSRB, + u_int16_t * pscsi_status); +static void trm_Nop0(PACB pACB, PSRB pSRB, u_int16_t * pscsi_status); +static void trm_Nop1(PACB pACB, PSRB pSRB, u_int16_t * pscsi_status); +static void trm_SetXferRate(PACB pACB, PSRB pSRB,PDCB pDCB); +static void trm_DataIO_transfer(PACB pACB, PSRB pSRB, u_int16_t ioDir); +static void trm_Disconnect(PACB pACB); +static void trm_Reselect(PACB pACB); +static void trm_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB); +static void trm_DoingSRB_Done(PACB pACB); +static void trm_ScsiRstDetect(PACB pACB); +static void trm_ResetSCSIBus(PACB pACB); +static void trm_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB); +static void trm_EnableMsgOutAbort2(PACB pACB, PSRB pSRB); +static void trm_EnableMsgOutAbort1(PACB pACB, PSRB pSRB); +static void trm_SendSRB(PACB pACB, PSRB pSRB); +static int trm_probe(device_t tag); +static int trm_attach(device_t tag); +static void trm_reset(PACB pACB); + +static u_int16_t trm_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB); + +static int trm_initAdapter(PACB pACB, u_int16_t unit); +static void trm_initDCB(PACB pACB, PDCB pDCB, u_int16_t unit, + u_int32_t i, u_int32_t j); +static int trm_initSRB(PACB pACB); +static void trm_initACB(PACB pACB, u_int8_t adaptType, u_int16_t unit); +/* CAM SIM entry points */ +#define ccb_trmsrb_ptr spriv_ptr0 +#define ccb_trmacb_ptr spriv_ptr1 +static void trm_action(struct cam_sim *psim, union ccb *pccb); +static void trm_poll(struct cam_sim *psim); + + +static void * trm_SCSI_phase0[] = { + trm_DataOutPhase0, /* phase:0 */ + trm_DataInPhase0, /* phase:1 */ + trm_CommandPhase0, /* phase:2 */ + trm_StatusPhase0, /* phase:3 */ + trm_Nop0, /* phase:4 */ + trm_Nop1, /* phase:5 */ + trm_MsgOutPhase0, /* phase:6 */ + trm_MsgInPhase0, /* phase:7 */ +}; + +/* + * + * stateV = (void *) trm_SCSI_phase1[phase] + * + */ +static void * trm_SCSI_phase1[] = { + trm_DataOutPhase1, /* phase:0 */ + trm_DataInPhase1, /* phase:1 */ + trm_CommandPhase1, /* phase:2 */ + trm_StatusPhase1, /* phase:3 */ + trm_Nop0, /* phase:4 */ + trm_Nop1, /* phase:5 */ + trm_MsgOutPhase1, /* phase:6 */ + trm_MsgInPhase1, /* phase:7 */ +}; + + +NVRAMTYPE trm_eepromBuf[TRM_MAX_ADAPTER_NUM]; +/* + *Fast20: 000 50ns, 20.0 Mbytes/s + * 001 75ns, 13.3 Mbytes/s + * 010 100ns, 10.0 Mbytes/s + * 011 125ns, 8.0 Mbytes/s + * 100 150ns, 6.6 Mbytes/s + * 101 175ns, 5.7 Mbytes/s + * 110 200ns, 5.0 Mbytes/s + * 111 250ns, 4.0 Mbytes/s + * + *Fast40: 000 25ns, 40.0 Mbytes/s + * 001 50ns, 20.0 Mbytes/s + * 010 75ns, 13.3 Mbytes/s + * 011 100ns, 10.0 Mbytes/s + * 100 125ns, 8.0 Mbytes/s + * 101 150ns, 6.6 Mbytes/s + * 110 175ns, 5.7 Mbytes/s + * 111 200ns, 5.0 Mbytes/s + */ + /* real period: */ +u_int8_t dc395x_clock_period[] = { + 12,/* 48 ns 20 MB/sec */ + 18,/* 72 ns 13.3 MB/sec */ + 25,/* 100 ns 10.0 MB/sec */ + 31,/* 124 ns 8.0 MB/sec */ + 37,/* 148 ns 6.6 MB/sec */ + 43,/* 172 ns 5.7 MB/sec */ + 50,/* 200 ns 5.0 MB/sec */ + 62 /* 248 ns 4.0 MB/sec */ +}; + +u_int8_t dc395u2x_clock_period[]={ + 10,/* 25 ns 40.0 MB/sec */ + 12,/* 48 ns 20.0 MB/sec */ + 18,/* 72 ns 13.3 MB/sec */ + 25,/* 100 ns 10.0 MB/sec */ + 31,/* 124 ns 8.0 MB/sec */ + 37,/* 148 ns 6.6 MB/sec */ + 43,/* 172 ns 5.7 MB/sec */ + 50,/* 200 ns 5.0 MB/sec */ +}; + +#define dc395x_tinfo_period dc395x_clock_period +#define dc395u2x_tinfo_period dc395u2x_clock_period + +static PSRB +trm_GetSRB(PACB pACB) +{ + int intflag; + PSRB pSRB; + + intflag = splcam(); + pSRB = pACB->pFreeSRB; + if (pSRB) { + pACB->pFreeSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + splx(intflag); + return (pSRB); +} + +static void +trm_RewaitSRB0(PDCB pDCB, PSRB pSRB) +{ + PSRB psrb1; + int intflag; + + intflag = splcam(); + if ((psrb1 = pDCB->pWaitingSRB)) { + pSRB->pNextSRB = psrb1; + pDCB->pWaitingSRB = pSRB; + } else { + pSRB->pNextSRB = NULL; + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitingLastSRB = pSRB; + } + splx(intflag); +} + +static void +trm_RewaitSRB(PDCB pDCB, PSRB pSRB) +{ + PSRB psrb1; + int intflag; + + intflag = splcam(); + pDCB->GoingSRBCnt--; + psrb1 = pDCB->pGoingSRB; + if (pSRB == psrb1) + /* + * if this SRB is GoingSRB + * remove this SRB from GoingSRB Q + */ + pDCB->pGoingSRB = psrb1->pNextSRB; + else { + /* + * if this SRB is not current GoingSRB + * remove this SRB from GoingSRB Q + */ + while (pSRB != psrb1->pNextSRB) + psrb1 = psrb1->pNextSRB; + psrb1->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLastSRB) + pDCB->pGoingLastSRB = psrb1; + } + if ((psrb1 = pDCB->pWaitingSRB)) { + /* + * if WaitingSRB Q is not NULL + * Q back this SRB into WaitingSRB + */ + + pSRB->pNextSRB = psrb1; + pDCB->pWaitingSRB = pSRB; + } else { + pSRB->pNextSRB = NULL; + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitingLastSRB = pSRB; + } + splx(intflag); +} + +static void +trm_DoWaitingSRB(PACB pACB) +{ + int intflag; + PDCB ptr, ptr1; + PSRB pSRB; + + intflag = splcam(); + if (!(pACB->pActiveDCB) && + !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV))) { + ptr = pACB->pDCBRunRobin; + if (!ptr) { + ptr = pACB->pLinkDCB; + pACB->pDCBRunRobin = ptr; + } + ptr1 = ptr; + for (;ptr1 ;) { + pACB->pDCBRunRobin = ptr1->pNextDCB; + if (!(ptr1->MaxActiveCommandCnt > ptr1->GoingSRBCnt) + || !(pSRB = ptr1->pWaitingSRB)) { + if (pACB->pDCBRunRobin == ptr) + break; + ptr1 = ptr1->pNextDCB; + } else { + if (!trm_StartSCSI(pACB, ptr1, pSRB)) { + /* + * If trm_StartSCSI return 0 : + * current interrupt status is interrupt enable + * It's said that SCSI processor is unoccupied + */ + ptr1->GoingSRBCnt++; + if (ptr1->pWaitingLastSRB == pSRB) { + ptr1->pWaitingSRB = NULL; + ptr1->pWaitingLastSRB = NULL; + } else + ptr1->pWaitingSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + if (ptr1->pGoingSRB) + ptr1->pGoingLastSRB->pNextSRB = pSRB; + else + ptr1->pGoingSRB = pSRB; + ptr1->pGoingLastSRB = pSRB; + } + break; + } + } + } + splx(intflag); + return; +} + +static void +trm_SRBwaiting(PDCB pDCB, PSRB pSRB) +{ + + if (pDCB->pWaitingSRB) { + pDCB->pWaitingLastSRB->pNextSRB = pSRB; + pDCB->pWaitingLastSRB = pSRB; + pSRB->pNextSRB = NULL; + } else { + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitingLastSRB = pSRB; + } +} + +static u_int32_t +trm_get_sense_bufaddr(PACB pACB, PSRB pSRB) +{ + int offset; + + offset = pSRB->TagNumber; + return (pACB->sense_busaddr + + (offset * sizeof(struct scsi_sense_data))); +} + +static struct scsi_sense_data * +trm_get_sense_buf(PACB pACB, PSRB pSRB) +{ + int offset; + + offset = pSRB->TagNumber; + return (&pACB->sense_buffers[offset]); +} +static void +trm_ExecuteSRB(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +{ + int flags; + PACB pACB; + PSRB pSRB; + union ccb *ccb; + u_long totalxferlen=0; + + flags = splcam(); + pSRB = (PSRB)arg; + ccb = pSRB->pccb; + pACB = (PACB)ccb->ccb_h.ccb_trmacb_ptr; + TRM_DPRINTF("trm_ExecuteSRB..........\n"); + if (nseg != 0) { + PSEG psg; + bus_dma_segment_t *end_seg; + int op; + + /* Copy the segments into our SG list */ + end_seg = dm_segs + nseg; + psg = pSRB->pSRBSGL; + while (dm_segs < end_seg) { + psg->address = dm_segs->ds_addr; + psg->length = (u_long)dm_segs->ds_len; + totalxferlen += dm_segs->ds_len; + psg++; + dm_segs++; + } + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + op = BUS_DMASYNC_PREREAD; + } else { + op = BUS_DMASYNC_PREWRITE; + } + bus_dmamap_sync(pACB->buffer_dmat, pSRB->dmamap, op); + } + pSRB->RetryCnt = 0; + pSRB->SRBTotalXferLength = totalxferlen; + pSRB->SRBSGCount = nseg; + pSRB->SRBSGIndex = 0; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pSRB->MsgCnt = 0; + pSRB->SRBStatus = 0; + pSRB->SRBFlag = 0; + pSRB->SRBState = 0; + pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */ + + if (ccb->ccb_h.status != CAM_REQ_INPROG) { + if (nseg != 0) + bus_dmamap_unload(pACB->buffer_dmat, pSRB->dmamap); + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + xpt_done(ccb); + splx(flags); + return; + } + ccb->ccb_h.status |= CAM_SIM_QUEUED; +#if 0 + /* XXX Need a timeout handler */ + ccb->ccb_h.timeout_ch = timeout(trmtimeout, (caddr_t)srb, (ccb->ccb_h.timeout * hz) / 1000); +#endif + trm_SendSRB(pACB, pSRB); + splx(flags); + return; +} + +static void +trm_SendSRB(PACB pACB, PSRB pSRB) +{ + PDCB pDCB; + + pDCB = pSRB->pSRBDCB; + if (!(pDCB->MaxActiveCommandCnt > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) + || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV))) { + TRM_DPRINTF("pDCB->MaxCommand=%d \n",pDCB->MaxActiveCommandCnt); + TRM_DPRINTF("pDCB->GoingSRBCnt=%d \n",pDCB->GoingSRBCnt); + TRM_DPRINTF("pACB->pActiveDCB=%8x \n",(u_int)pACB->pActiveDCB); + TRM_DPRINTF("pACB->ACBFlag=%x \n",pACB->ACBFlag); + trm_SRBwaiting(pDCB, pSRB); + goto SND_EXIT; + } + + if (pDCB->pWaitingSRB) { + trm_SRBwaiting(pDCB, pSRB); + pSRB = pDCB->pWaitingSRB; + pDCB->pWaitingSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + + if (!trm_StartSCSI(pACB, pDCB, pSRB)) { + /* + * If trm_StartSCSI return 0 : + * current interrupt status is interrupt enable + * It's said that SCSI processor is unoccupied + */ + pDCB->GoingSRBCnt++; /* stack waiting SRB*/ + if (pDCB->pGoingSRB) { + pDCB->pGoingLastSRB->pNextSRB = pSRB; + pDCB->pGoingLastSRB = pSRB; + } else { + pDCB->pGoingSRB = pSRB; + pDCB->pGoingLastSRB = pSRB; + } + } else { + /* + * If trm_StartSCSI return 1 : + * current interrupt status is interrupt disreenable + * It's said that SCSI processor has more one SRB need to do + */ + trm_RewaitSRB0(pDCB, pSRB); + } +SND_EXIT: + return; +} + + +static void +trm_action(struct cam_sim *psim, union ccb *pccb) +{ + PACB pACB; + int actionflags; + u_int target_id,target_lun; + + CAM_DEBUG(pccb->ccb_h.path, CAM_DEBUG_TRACE, ("trm_action\n")); + + actionflags = splcam(); + pACB = (PACB) cam_sim_softc(psim); + target_id = pccb->ccb_h.target_id; + target_lun = pccb->ccb_h.target_lun; + + switch (pccb->ccb_h.func_code) { + case XPT_NOOP: + TRM_DPRINTF(" XPT_NOOP \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * Execute the requested I/O operation + */ + case XPT_SCSI_IO: { + PDCB pDCB = NULL; + PSRB pSRB; + struct ccb_scsiio *pcsio; + + pcsio = &pccb->csio; + TRM_DPRINTF(" XPT_SCSI_IO \n"); + TRM_DPRINTF("trm: target_id= %d target_lun= %d \n" + ,target_id, target_lun); + TRM_DPRINTF( + "pACB->scan_devices[target_id][target_lun]= %d \n" + ,pACB->scan_devices[target_id][target_lun]); + if((pccb->ccb_h.status & CAM_STATUS_MASK) !=CAM_REQ_INPROG) { + xpt_done(pccb); + splx(actionflags); + return; + } + pDCB = &pACB->DCBarray[target_id][target_lun]; + if(!(pDCB->DCBstatus & DS_IN_QUEUE)) { + pACB->scan_devices[target_id][target_lun] = 1; + trm_initDCB(pACB, pDCB, pACB->AdapterUnit, + target_id, target_lun); + } + /* + * Assign an SRB and connect it with this ccb. + */ + pSRB = trm_GetSRB(pACB); + if (!pSRB) { + /* Freeze SIMQ */ + pccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(pccb); + splx(actionflags); + return; + } + pSRB->pSRBDCB = pDCB; + pccb->ccb_h.ccb_trmsrb_ptr = pSRB; + pccb->ccb_h.ccb_trmacb_ptr = pACB; + pSRB->pccb = pccb; + pSRB->ScsiCmdLen = pcsio->cdb_len; + /* + * move layer of CAM command block to layer of SCSI + * Request Block for SCSI processor command doing + */ + if((pccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { + if((pccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { + bcopy(pcsio->cdb_io.cdb_ptr,pSRB->CmdBlock + ,pcsio->cdb_len); + } else { + pccb->ccb_h.status = CAM_REQ_INVALID; + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB= pSRB; + xpt_done(pccb); + splx(actionflags); + return; + } + } else + bcopy(pcsio->cdb_io.cdb_bytes, + pSRB->CmdBlock, pcsio->cdb_len); + 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 vmflags; + int error; + + vmflags = 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(vmflags); + } 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); + splx(actionflags); + 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); + cpi->base_transfer_speed = 3300; + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "Tekram_TRM", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(psim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(psim); + cpi->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->DCBarray[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->DCBarray[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: + TRM_DPRINTF(" XPT_CALC_GEOMETRY \n"); + cam_calc_geometry(&pccb->ccg, /*extended*/1); + xpt_done(pccb); + break; + case XPT_ENG_INQ: + TRM_DPRINTF(" XPT_ENG_INQ \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * HBA execute engine request + * This structure must match SCSIIO size + */ + case XPT_ENG_EXEC: + TRM_DPRINTF(" XPT_ENG_EXEC \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * XPT_EN_LUN = 0x30, Enable LUN as a target + * Target mode structures. + */ + case XPT_EN_LUN: + /* + * Don't (yet?) support vendor + * specific commands. + */ + TRM_DPRINTF(" XPT_EN_LUN \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * Execute target I/O request + */ + case XPT_TARGET_IO: + /* + * Don't (yet?) support vendor + * specific commands. + */ + TRM_DPRINTF(" XPT_TARGET_IO \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * Accept Host Target Mode CDB + */ + case XPT_ACCEPT_TARGET_IO: + /* + * Don't (yet?) support vendor + * specific commands. + */ + TRM_DPRINTF(" XPT_ACCEPT_TARGET_IO \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * Continue Host Target I/O Connection + */ + case XPT_CONT_TARGET_IO: + /* + * Don't (yet?) support vendor + * specific commands. + */ + TRM_DPRINTF(" XPT_CONT_TARGET_IO \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * Notify Host Target driver of event + */ + case XPT_IMMED_NOTIFY: + TRM_DPRINTF(" XPT_IMMED_NOTIFY \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * Acknowledgement of event + */ + case XPT_NOTIFY_ACK: + TRM_DPRINTF(" XPT_NOTIFY_ACK \n"); + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + /* + * XPT_VUNIQUE = 0x80 + */ + case XPT_VUNIQUE: + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + default: + pccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(pccb); + break; + } + splx(actionflags); +} + +static void +trm_poll(struct cam_sim *psim) +{ + +} + +static void +trm_ResetDevParam(PACB pACB) +{ + PDCB pDCB, pdcb; + PNVRAMTYPE pEEpromBuf; + u_int8_t PeriodIndex; + + pDCB = pACB->pLinkDCB; + if (pDCB == NULL) + return; + pdcb = pDCB; + do { + pDCB->SyncMode &= ~(SYNC_NEGO_DONE+ WIDE_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pEEpromBuf = &trm_eepromBuf[pACB->AdapterUnit]; + pDCB->DevMode = + pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0; + pDCB->AdpMode = pEEpromBuf->NvramChannelCfg; + PeriodIndex = + pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod & 0x07; + if (pACB->AdaptType == 1) /* is U2? */ + pDCB->MaxNegoPeriod = dc395u2x_clock_period[PeriodIndex]; + else + pDCB->MaxNegoPeriod = dc395x_clock_period[PeriodIndex]; + if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && + (pACB->Config & HCC_WIDE_CARD)) + pDCB->SyncMode |= WIDE_NEGO_ENABLE; + pDCB = pDCB->pNextDCB; + } + while (pdcb != pDCB); +} + +static void +trm_RecoverSRB(PACB pACB) +{ + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + u_int16_t cnt, i; + + pDCB = pACB->pLinkDCB; + if (pDCB == NULL) + return; + pdcb = pDCB; + do { + cnt = pdcb->GoingSRBCnt; + psrb = pdcb->pGoingSRB; + for (i = 0; i < cnt; i++) { + psrb2 = psrb; + psrb = psrb->pNextSRB; + if (pdcb->pWaitingSRB) { + psrb2->pNextSRB = pdcb->pWaitingSRB; + pdcb->pWaitingSRB = psrb2; + } else { + pdcb->pWaitingSRB = psrb2; + pdcb->pWaitingLastSRB = psrb2; + psrb2->pNextSRB = NULL; + } + } + pdcb->GoingSRBCnt = 0; + pdcb->pGoingSRB = NULL; + pdcb = pdcb->pNextDCB; + } + while (pdcb != pDCB); +} + +static void +trm_reset(PACB pACB) +{ + int intflag; + u_int16_t i; + + TRM_DPRINTF("trm: RESET"); + intflag = splcam(); + trm_reg_write8(0x00, TRMREG_DMA_INTEN); + trm_reg_write8(0x00, TRMREG_SCSI_INTEN); + + trm_ResetSCSIBus(pACB); + for (i = 0; i < 500; i++) + DELAY(1000); + trm_reg_write8(0x7F, TRMREG_SCSI_INTEN); + /* Enable DMA interrupt */ + trm_reg_write8(EN_SCSIINTR, TRMREG_DMA_INTEN); + /* Clear DMA FIFO */ + trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL); + /* Clear SCSI FIFO */ + trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL); + trm_ResetDevParam(pACB); + trm_DoingSRB_Done(pACB); + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0;/* RESET_DETECT, RESET_DONE ,RESET_DEV */ + trm_DoWaitingSRB(pACB); + /* Tell the XPT layer that a bus reset occured */ + if (pACB->ppath != NULL) + xpt_async(AC_BUS_RESET, pACB->ppath, NULL); + splx(intflag); + return; +} + +static u_int16_t +trm_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB) +{ + u_int16_t return_code; + u_int8_t scsicommand, i,command,identify_message; + u_int8_t * ptr; + union ccb *pccb; + struct ccb_scsiio *pcsio; + + pccb = pSRB->pccb; + pcsio = &pccb->csio; + + trm_reg_write8(pACB->AdaptSCSIID, TRMREG_SCSI_HOSTID); + trm_reg_write8(pDCB->TargetID, TRMREG_SCSI_TARGETID); + trm_reg_write8(pDCB->SyncPeriod, TRMREG_SCSI_SYNC); + trm_reg_write8(pDCB->SyncOffset, TRMREG_SCSI_OFFSET); + pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ + /* Flush FIFO */ + trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL); + + identify_message = pDCB->IdentifyMsg; + + if ((pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE)) { + if (((pDCB->SyncMode & WIDE_NEGO_ENABLE) && + !(pDCB->SyncMode & WIDE_NEGO_DONE)) + || ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && + !(pDCB->SyncMode & SYNC_NEGO_DONE))) { + if (!(pDCB->IdentifyMsg & 7) || + (pSRB->CmdBlock[0] != INQUIRY)) { + scsicommand = SCMD_SEL_ATNSTOP; + pSRB->SRBState = SRB_MSGOUT; + goto polling; + } + } + /* + * Send identify message + */ + trm_reg_write8((identify_message & 0xBF) ,TRMREG_SCSI_FIFO); + scsicommand = SCMD_SEL_ATN; + pSRB->SRBState = SRB_START_; + } else { + /* not inquiry,request sense,auto request sense */ + /* + * Send identify message + */ + trm_reg_write8(identify_message,TRMREG_SCSI_FIFO); + scsicommand = SCMD_SEL_ATN; + pSRB->SRBState = SRB_START_; + if (pDCB->SyncMode & EN_TAG_QUEUING) { + /* Send Tag message */ + trm_reg_write8(MSG_SIMPLE_QTAG, TRMREG_SCSI_FIFO); + trm_reg_write8(pSRB->TagNumber, TRMREG_SCSI_FIFO); + scsicommand = SCMD_SEL_ATN3; + } + } +polling: + /* + * Send CDB ..command block ......... + */ + if (pSRB->SRBFlag & AUTO_REQSENSE) { + trm_reg_write8(REQUEST_SENSE, TRMREG_SCSI_FIFO); + trm_reg_write8((pDCB->IdentifyMsg << 5), TRMREG_SCSI_FIFO); + trm_reg_write8(0, TRMREG_SCSI_FIFO); + trm_reg_write8(0, TRMREG_SCSI_FIFO); + trm_reg_write8(pcsio->sense_len, TRMREG_SCSI_FIFO); + trm_reg_write8(0, TRMREG_SCSI_FIFO); + } else { + ptr = (u_int8_t *) pSRB->CmdBlock; + for (i = 0; i < pSRB->ScsiCmdLen ; i++) { + command = *ptr++; + trm_reg_write8(command,TRMREG_SCSI_FIFO); + } + } + if (trm_reg_read16(TRMREG_SCSI_STATUS) & SCSIINTERRUPT) { + /* + * If trm_StartSCSI return 1 : + * current interrupt status is interrupt disreenable + * It's said that SCSI processor has more one SRB need to do, + * SCSI processor has been occupied by one SRB. + */ + pSRB->SRBState = SRB_READY; + return_code = 1; + } else { + /* + * If trm_StartSCSI return 0 : + * current interrupt status is interrupt enable + * It's said that SCSI processor is unoccupied + */ + pSRB->ScsiPhase = SCSI_NOP1; /* SCSI bus free Phase */ + pACB->pActiveDCB = pDCB; + pDCB->pActiveSRB = pSRB; + return_code = 0; + trm_reg_write16(DO_DATALATCH | DO_HWRESELECT, + TRMREG_SCSI_CONTROL);/* it's important for atn stop*/ + /* + * SCSI cammand + */ + trm_reg_write8(scsicommand,TRMREG_SCSI_COMMAND); + } + return (return_code); +} + +static void +trm_Interrupt(vpACB) +void *vpACB; +{ + PACB pACB; + PDCB pDCB; + PSRB pSRB; + u_int16_t phase; + void (*stateV)(PACB, PSRB, u_int16_t *); + u_int16_t scsi_status=0; + u_int8_t scsi_intstatus; + + pACB = vpACB; + + scsi_status = trm_reg_read16(TRMREG_SCSI_STATUS); + if (!(scsi_status & SCSIINTERRUPT)) { + TRM_DPRINTF("trm_Interrupt: TRMREG_SCSI_STATUS scsi_status = NULL ,return......"); + return; + } + TRM_DPRINTF("scsi_status=%2x,",scsi_status); + + scsi_intstatus = trm_reg_read8(TRMREG_SCSI_INTSTATUS); + + TRM_DPRINTF("scsi_intstatus=%2x,",scsi_intstatus); + + if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) { + trm_Disconnect(pACB); + return; + } + + if (scsi_intstatus & INT_RESELECTED) { + trm_Reselect(pACB); + return; + } + if (scsi_intstatus & INT_SCSIRESET) { + trm_ScsiRstDetect(pACB); + return; + } + + if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) { + pDCB = pACB->pActiveDCB; + 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_int16_t *pscsi_status) +{ + + if (pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT)) + *pscsi_status = PH_BUS_FREE; + /*.. initial phase*/ +} + +static void +trm_MsgOutPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + u_int8_t bval; + u_int16_t i, cnt; + u_int8_t * ptr; + PDCB pDCB; + + trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL); + pDCB = pACB->pActiveDCB; + if (!(pSRB->SRBState & SRB_MSGOUT)) { + cnt = pSRB->MsgCnt; + if (cnt) { + ptr = (u_int8_t *) pSRB->MsgOutBuf; + for (i = 0; i < cnt; i++) { + trm_reg_write8(*ptr, TRMREG_SCSI_FIFO); + ptr++; + } + pSRB->MsgCnt = 0; + if ((pDCB->DCBFlag & ABORT_DEV_) && + (pSRB->MsgOutBuf[0] == MSG_ABORT)) { + pSRB->SRBState = SRB_ABORT_SENT; + } + } else { + bval = MSG_ABORT; + if ((pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE)) { + if (pDCB->SyncMode & SYNC_NEGO_ENABLE) { + goto mop1; + } + } + trm_reg_write8(bval, TRMREG_SCSI_FIFO); + } + } else { +mop1: /* message out phase */ + if (!(pSRB->SRBState & SRB_DO_WIDE_NEGO) + && (pDCB->SyncMode & WIDE_NEGO_ENABLE)) { + /* + * WIDE DATA TRANSFER REQUEST code (03h) + */ + pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP); + trm_reg_write8((pDCB->IdentifyMsg & 0xBF), + TRMREG_SCSI_FIFO); + trm_reg_write8(MSG_EXTENDED,TRMREG_SCSI_FIFO); + /* (01h) */ + trm_reg_write8(2,TRMREG_SCSI_FIFO); + /* Message length (02h) */ + trm_reg_write8(3,TRMREG_SCSI_FIFO); + /* wide data xfer (03h) */ + trm_reg_write8(1,TRMREG_SCSI_FIFO); + /* width:0(8bit),1(16bit),2(32bit) */ + pSRB->SRBState |= SRB_DO_WIDE_NEGO; + } else if (!(pSRB->SRBState & SRB_DO_SYNC_NEGO) + && (pDCB->SyncMode & SYNC_NEGO_ENABLE)) { + /* + * SYNCHRONOUS DATA TRANSFER REQUEST code (01h) + */ + if (!(pDCB->SyncMode & WIDE_NEGO_DONE)) + trm_reg_write8((pDCB->IdentifyMsg & 0xBF), + TRMREG_SCSI_FIFO); + trm_reg_write8(MSG_EXTENDED,TRMREG_SCSI_FIFO); + /* (01h) */ + trm_reg_write8(3,TRMREG_SCSI_FIFO); + /* Message length (03h) */ + trm_reg_write8(1,TRMREG_SCSI_FIFO); + /* SYNCHRONOUS DATA TRANSFER REQUEST code (01h) */ + trm_reg_write8(pDCB->MaxNegoPeriod,TRMREG_SCSI_FIFO); + /* Transfer peeriod factor */ + trm_reg_write8((pACB->AdaptType == 1) ? 31 : 15, + TRMREG_SCSI_FIFO); + /* REQ/ACK offset */ + pSRB->SRBState |= SRB_DO_SYNC_NEGO; + } + } + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_FIFO_OUT, TRMREG_SCSI_COMMAND); +} + +static void +trm_CommandPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + +} + +static void +trm_CommandPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + PDCB pDCB; + u_int8_t * ptr; + u_int16_t i, cnt; + union ccb *pccb; + struct ccb_scsiio *pcsio; + + pccb = pSRB->pccb; + pcsio = &pccb->csio; + + trm_reg_write16(DO_CLRATN | DO_CLRFIFO , TRMREG_SCSI_CONTROL); + if (!(pSRB->SRBFlag & AUTO_REQSENSE)) { + cnt = (u_int16_t) pSRB->ScsiCmdLen; + ptr = (u_int8_t *) pSRB->CmdBlock; + for (i = 0; i < cnt; i++) { + trm_reg_write8(*ptr, TRMREG_SCSI_FIFO); + ptr++; + } + } else { + trm_reg_write8(REQUEST_SENSE, TRMREG_SCSI_FIFO); + pDCB = pACB->pActiveDCB; + /* target id */ + trm_reg_write8((pDCB->IdentifyMsg << 5), TRMREG_SCSI_FIFO); + trm_reg_write8(0, TRMREG_SCSI_FIFO); + trm_reg_write8(0, TRMREG_SCSI_FIFO); + /* sizeof(struct scsi_sense_data) */ + trm_reg_write8(pcsio->sense_len, TRMREG_SCSI_FIFO); + trm_reg_write8(0, TRMREG_SCSI_FIFO); + } + pSRB->SRBState = SRB_COMMAND; + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop*/ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_FIFO_OUT, TRMREG_SCSI_COMMAND); +} + +static void +trm_DataOutPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + PDCB pDCB; + u_int8_t TempDMAstatus,SGIndexTemp; + u_int16_t scsi_status; + PSEG pseg; + u_long TempSRBXferredLength,dLeftCounter=0; + + pDCB = pSRB->pSRBDCB; + scsi_status = *pscsi_status; + + if (!(pSRB->SRBState & SRB_XFERPAD)) { + if (scsi_status & PARITYERROR) + pSRB->SRBStatus |= PARITY_ERROR; + if (!(scsi_status & SCSIXFERDONE)) { + /* + * when data transfer from DMA FIFO to SCSI FIFO + * if there was some data left in SCSI FIFO + */ + dLeftCounter = (u_long) + (trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x3F); + if (pDCB->SyncPeriod & WIDE_SYNC) { + /* + * if WIDE scsi SCSI FIFOCNT unit is word + * so need to * 2 + */ + dLeftCounter <<= 1; + } + } + /* + * caculate all the residue data that not yet tranfered + * SCSI transfer counter + left in SCSI FIFO data + * + * .....TRM_SCSI_COUNTER (24bits) + * The counter always decrement by one for every SCSI byte + *transfer. + * .....TRM_SCSI_FIFOCNT (5bits) + * The counter is SCSI FIFO offset counter + */ + dLeftCounter += trm_reg_read32(TRMREG_SCSI_COUNTER); + if (dLeftCounter == 1) { + dLeftCounter = 0; + trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL); + } + if ((dLeftCounter == 0) || + (scsi_status & SCSIXFERCNT_2_ZERO)) { + TempDMAstatus = trm_reg_read8(TRMREG_DMA_STATUS); + while (!(TempDMAstatus & DMAXFERCOMP)) { + TempDMAstatus = + trm_reg_read8(TRMREG_DMA_STATUS); + } + pSRB->SRBTotalXferLength = 0; + } else { + /* Update SG list */ + /* + * if transfer not yet complete + * there were some data residue in SCSI FIFO or + * SCSI transfer counter not empty + */ + if (pSRB->SRBTotalXferLength != dLeftCounter) { + /* + * data that had transferred length + */ + TempSRBXferredLength = + pSRB->SRBTotalXferLength - dLeftCounter; + /* + * next time to be transferred length + */ + pSRB->SRBTotalXferLength = dLeftCounter; + /* + * parsing from last time disconnect SRBSGIndex + */ + pseg = + pSRB->pSRBSGL + pSRB->SRBSGIndex; + for (SGIndexTemp = pSRB->SRBSGIndex; + SGIndexTemp < pSRB->SRBSGCount; + SGIndexTemp++) { + /* + * find last time which SG transfer be + * disconnect + */ + if (TempSRBXferredLength >= + pseg->length) + TempSRBXferredLength -= + pseg->length; + else { + /* + * update last time disconnected SG + * list + */ + pseg->length -= + TempSRBXferredLength; + /* residue data length */ + pseg->address += + TempSRBXferredLength; + /* residue data pointer */ + pSRB->SRBSGIndex = SGIndexTemp; + break; + } + pseg++; + } + } + } + } + trm_reg_write8(STOPDMAXFER ,TRMREG_DMA_CONTROL); +} + + +static void +trm_DataOutPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + u_int16_t ioDir; + /* + * do prepare befor transfer when data out phase + */ + + ioDir = XFERDATAOUT; + trm_DataIO_transfer(pACB, pSRB, ioDir); +} + +static void +trm_DataInPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + u_int8_t TempDMAstatus, SGIndexTemp; + u_int16_t scsi_status; + PSEG pseg; + u_long TempSRBXferredLength,dLeftCounter = 0; + + scsi_status = *pscsi_status; + if (!(pSRB->SRBState & SRB_XFERPAD)) { + if (scsi_status & PARITYERROR) + pSRB->SRBStatus |= PARITY_ERROR; + dLeftCounter += trm_reg_read32(TRMREG_SCSI_COUNTER); + if ((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO)) { + TempDMAstatus = trm_reg_read8(TRMREG_DMA_STATUS); + while (!(TempDMAstatus & DMAXFERCOMP)) + TempDMAstatus = trm_reg_read8(TRMREG_DMA_STATUS); + pSRB->SRBTotalXferLength = 0; + } else { + /* + * parsing the case: + * when a transfer not yet complete + * but be disconnected by uper layer + * if transfer not yet complete + * there were some data residue in SCSI FIFO or + * SCSI transfer counter not empty + */ + if (pSRB->SRBTotalXferLength != dLeftCounter) { + /* + * data that had transferred length + */ + TempSRBXferredLength = + pSRB->SRBTotalXferLength - dLeftCounter; + /* + * next time to be transferred length + */ + pSRB->SRBTotalXferLength = dLeftCounter; + /* + * parsing from last time disconnect SRBSGIndex + */ + pseg = pSRB->pSRBSGL + pSRB->SRBSGIndex; + for (SGIndexTemp = pSRB->SRBSGIndex; + SGIndexTemp < pSRB->SRBSGCount; + SGIndexTemp++) { + /* + * find last time which SG transfer be disconnect + */ + if (TempSRBXferredLength >= pseg->length) + TempSRBXferredLength -= pseg->length; + else { + /* + * update last time disconnected SG list + */ + pseg->length -= TempSRBXferredLength; + /* residue data length */ + pseg->address += TempSRBXferredLength; + /* residue data pointer */ + pSRB->SRBSGIndex = SGIndexTemp; + break; + } + pseg++; + } + } + } + } +} + +static void +trm_DataInPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + u_int16_t ioDir; + /* + * do prepare befor transfer when data in phase + */ + + ioDir = XFERDATAIN; + trm_DataIO_transfer(pACB, pSRB, ioDir); +} + +static void +trm_DataIO_transfer(PACB pACB, PSRB pSRB, u_int16_t ioDir) +{ + u_int8_t bval; + PDCB pDCB; + + pDCB = pSRB->pSRBDCB; + if (pSRB->SRBSGIndex < pSRB->SRBSGCount) { + if (pSRB->SRBTotalXferLength != 0) { + /* + * load what physical address of Scatter/Gather list + table want to be transfer + */ + TRM_DPRINTF(" SG->address=%8x \n",pSRB->pSRBSGL->address); + TRM_DPRINTF(" SG->length=%8x \n",pSRB->pSRBSGL->length); + TRM_DPRINTF(" pDCB->SyncPeriod=%x \n",pDCB->SyncPeriod); + TRM_DPRINTF(" pSRB->pSRBSGL=%8x \n",(unsigned int)pSRB->pSRBSGL); + TRM_DPRINTF(" pSRB->SRBSGPhyAddr=%8x \n",pSRB->SRBSGPhyAddr); + TRM_DPRINTF(" pSRB->SRBSGIndex=%d \n",pSRB->SRBSGIndex); + TRM_DPRINTF(" pSRB->SRBSGCount=%d \n",pSRB->SRBSGCount); + TRM_DPRINTF(" pSRB->SRBTotalXferLength=%d \n",pSRB->SRBTotalXferLength); + + pSRB->SRBState = SRB_DATA_XFER; + trm_reg_write32(0, TRMREG_DMA_XHIGHADDR); + trm_reg_write32( + (pSRB->SRBSGPhyAddr + + ((u_long)pSRB->SRBSGIndex << 3)), + TRMREG_DMA_XLOWADDR); + /* + * load how many bytes in the Scatter/Gather + * list table + */ + trm_reg_write32( + ((u_long)(pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3), + TRMREG_DMA_XCNT); + /* + * load total transfer length (24bits) max value + * 16Mbyte + */ + trm_reg_write32(pSRB->SRBTotalXferLength, + TRMREG_SCSI_COUNTER); + /* Start DMA transfer */ + trm_reg_write16(ioDir, TRMREG_DMA_COMMAND); + /* Start SCSI transfer */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + bval = (ioDir == XFERDATAOUT) ? + SCMD_DMA_OUT : SCMD_DMA_IN; + trm_reg_write8(bval, TRMREG_SCSI_COMMAND); + } else { + /* xfer pad */ + if (pSRB->SRBSGCount) { + pSRB->AdaptStatus = H_OVER_UNDER_RUN; + pSRB->SRBStatus |= OVER_RUN; + } + if (pDCB->SyncPeriod & WIDE_SYNC) + trm_reg_write32(2,TRMREG_SCSI_COUNTER); + else + trm_reg_write32(1,TRMREG_SCSI_COUNTER); + if (ioDir == XFERDATAOUT) + trm_reg_write16(0, TRMREG_SCSI_FIFO); + else + trm_reg_read16(TRMREG_SCSI_FIFO); + pSRB->SRBState |= SRB_XFERPAD; + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + bval = (ioDir == XFERDATAOUT) ? + SCMD_FIFO_OUT : SCMD_FIFO_IN; + trm_reg_write8(bval, TRMREG_SCSI_COMMAND); + } + } +} + +static void +trm_StatusPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + + pSRB->TargetStatus = trm_reg_read8(TRMREG_SCSI_FIFO); + pSRB->SRBState = SRB_COMPLETED; + *pscsi_status = PH_BUS_FREE; + /*.. initial phase*/ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); +} + + + +static void +trm_StatusPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + + if (trm_reg_read16(TRMREG_DMA_COMMAND) & 0x0001) { + if (!(trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x40)) + trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL); + if (!(trm_reg_read16(TRMREG_DMA_FIFOCNT) & 0x8000)) + trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL); + } else { + if (!(trm_reg_read16(TRMREG_DMA_FIFOCNT) & 0x8000)) + trm_reg_write8(CLRXFIFO, TRMREG_DMA_CONTROL); + if (!(trm_reg_read8(TRMREG_SCSI_FIFOCNT) & 0x40)) + trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL); + } + pSRB->SRBState = SRB_STATUS; + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_COMP, TRMREG_SCSI_COMMAND); +} + +/* + *scsiiom + * trm_MsgInPhase0: one of trm_SCSI_phase0[] vectors + * stateV = (void *) trm_SCSI_phase0[phase] + * if phase =7 + * extended message codes: + * + * code description + * + * 02h Reserved + * 00h MODIFY DATA POINTER + * 01h SYNCHRONOUS DATA TRANSFER REQUEST + * 03h WIDE DATA TRANSFER REQUEST + * 04h - 7Fh Reserved + * 80h - FFh Vendor specific + * + */ + +static void +trm_MsgInPhase0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + u_int8_t message_in_code,bIndex,message_in_tag_id; + PDCB pDCB; + PSRB pSRBTemp; + + pDCB = pACB->pActiveDCB; + + message_in_code = trm_reg_read8(TRMREG_SCSI_FIFO); + if (!(pSRB->SRBState & SRB_EXTEND_MSGIN)) { + if (message_in_code == MSG_DISCONNECT) { + pSRB->SRBState = SRB_DISCONNECT; + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if (message_in_code == MSG_SAVE_PTR) { + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if ((message_in_code == MSG_EXTENDED) || + ((message_in_code >= MSG_SIMPLE_QTAG) && + (message_in_code <= MSG_ORDER_QTAG))) { + pSRB->SRBState |= SRB_EXTEND_MSGIN; + pSRB->MsgInBuf[0] = message_in_code; + /* extended message (01h) */ + pSRB->MsgCnt = 1; + pSRB->pMsgPtr = &pSRB->MsgInBuf[1]; + /* extended message length (n) */ + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if (message_in_code == MSG_REJECT_) { + /* Reject message */ + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) { + /* do wide nego reject */ + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode |= WIDE_NEGO_DONE; + pDCB->SyncMode &= ~(SYNC_NEGO_DONE | + EN_ATN_STOP | WIDE_NEGO_ENABLE); + pSRB->SRBState &= ~(SRB_DO_WIDE_NEGO+SRB_MSGIN); + if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) + && !(pDCB->SyncMode & SYNC_NEGO_DONE)) { + /* Set ATN, in case ATN was clear */ + pSRB->SRBState |= SRB_MSGOUT; + trm_reg_write16( + DO_SETATN, + TRMREG_SCSI_CONTROL); + } else { + /* Clear ATN */ + trm_reg_write16( + DO_CLRATN, + TRMREG_SCSI_CONTROL); + } + } else if (pDCB->SyncMode & SYNC_NEGO_ENABLE) { + /* do sync nego reject */ + trm_reg_write16(DO_CLRATN,TRMREG_SCSI_CONTROL); + if (pSRB->SRBState & SRB_DO_SYNC_NEGO) { + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode &= + ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + /* + * + * program SCSI control register + * + */ + trm_reg_write8(pDCB->SyncPeriod, + TRMREG_SCSI_SYNC); + trm_reg_write8(pDCB->SyncOffset, + TRMREG_SCSI_OFFSET); + trm_SetXferRate(pACB,pSRB,pDCB); + } + } + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if (message_in_code == MSG_IGNOREWIDE) { + trm_reg_write32(1, TRMREG_SCSI_COUNTER); + trm_reg_read8(TRMREG_SCSI_FIFO); + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else { + /* Restore data pointer message */ + /* Save data pointer message */ + /* Completion message */ + /* NOP message */ + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } + } else { + /* + * Parsing incomming extented messages + */ + *pSRB->pMsgPtr = message_in_code; + pSRB->MsgCnt++; + pSRB->pMsgPtr++; + TRM_DPRINTF("pSRB->MsgInBuf[0]=%2x \n ",pSRB->MsgInBuf[0]); + TRM_DPRINTF("pSRB->MsgInBuf[1]=%2x \n ",pSRB->MsgInBuf[1]); + TRM_DPRINTF("pSRB->MsgInBuf[2]=%2x \n ",pSRB->MsgInBuf[2]); + TRM_DPRINTF("pSRB->MsgInBuf[3]=%2x \n ",pSRB->MsgInBuf[3]); + TRM_DPRINTF("pSRB->MsgInBuf[4]=%2x \n ",pSRB->MsgInBuf[4]); + if ((pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) + && (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG)) { + /* + * is QUEUE tag message : + * + * byte 0: + * HEAD QUEUE TAG (20h) + * ORDERED QUEUE TAG (21h) + * SIMPLE QUEUE TAG (22h) + * byte 1: + * Queue tag (00h - FFh) + */ + if (pSRB->MsgCnt == 2) { + pSRB->SRBState = 0; + message_in_tag_id = pSRB->MsgInBuf[1]; + pSRB = pDCB->pGoingSRB; + pSRBTemp = pDCB->pGoingLastSRB; + if (pSRB) { + for (;;) { + if (pSRB->TagNumber != + message_in_tag_id) { + if (pSRB == pSRBTemp) { + goto mingx0; + } + pSRB = pSRB->pNextSRB; + } else + break; + } + if (pDCB->DCBFlag & ABORT_DEV_) { + pSRB->SRBState = SRB_ABORT_SENT; + trm_EnableMsgOutAbort1( + pACB, pSRB); + } + if (!(pSRB->SRBState & SRB_DISCONNECT)) { + TRM_DPRINTF("SRB not yet disconnect........ \n "); + goto mingx0; + } + pDCB->pActiveSRB = pSRB; + pSRB->SRBState = SRB_DATA_XFER; + } else { +mingx0: + pSRB = &pACB->TmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + trm_EnableMsgOutAbort2( + pACB, + pSRB); + } + } + *pscsi_status = PH_BUS_FREE; + /* .. initial phase */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED) && + (pSRB->MsgInBuf[2] == 3) && (pSRB->MsgCnt == 4)) { + /* + * is Wide data xfer Extended message : + * ====================================== + * WIDE DATA TRANSFER REQUEST + * ====================================== + * byte 0 : Extended message (01h) + * byte 1 : Extended message length (02h) + * byte 2 : WIDE DATA TRANSFER code (03h) + * byte 3 : Transfer width exponent + */ + pDCB = pSRB->pSRBDCB; + pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_WIDE_NEGO); + if ((pSRB->MsgInBuf[1] != 2)) { + /* Length is wrong, reject it */ + pDCB->SyncMode &= + ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL); + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) { + /* Do wide negoniation */ + if (pSRB->MsgInBuf[3] > 2) { + /* > 32 bit */ + /* reject_msg: */ + pDCB->SyncMode &= + ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + trm_reg_write16(DO_SETATN, + TRMREG_SCSI_CONTROL); + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } + if (pSRB->MsgInBuf[3] == 2) { + pSRB->MsgInBuf[3] = 1; + /* do 16 bits */ + } else { + if (!(pDCB->SyncMode + & WIDE_NEGO_DONE)) { + pSRB->SRBState &= + ~(SRB_DO_WIDE_NEGO+SRB_MSGIN); + pDCB->SyncMode |= + WIDE_NEGO_DONE; + pDCB->SyncMode &= + ~(SYNC_NEGO_DONE | + EN_ATN_STOP | + WIDE_NEGO_ENABLE); + if (pSRB->MsgInBuf[3] != 0) { + /* is Wide data xfer */ + pDCB->SyncPeriod |= + WIDE_SYNC; + pDCB->tinfo.current.width + = MSG_EXT_WDTR_BUS_16_BIT; + pDCB->tinfo.goal.width + = MSG_EXT_WDTR_BUS_16_BIT; + } + } + } + } else + pSRB->MsgInBuf[3] = 0; + pSRB->SRBState |= SRB_MSGOUT; + trm_reg_write16(DO_SETATN,TRMREG_SCSI_CONTROL); + *pscsi_status = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* + * SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if ((pSRB->MsgInBuf[0] == MSG_EXTENDED) && + (pSRB->MsgInBuf[2] == 1) && (pSRB->MsgCnt == 5)) { + /* + * is 8bit transfer Extended message : + * ================================= + * SYNCHRONOUS DATA TRANSFER REQUEST + * ================================= + * byte 0 : Extended message (01h) + * byte 1 : Extended message length (03) + * byte 2 : SYNCHRONOUS DATA TRANSFER code (01h) + * byte 3 : Transfer period factor + * byte 4 : REQ/ACK offset + */ + pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_SYNC_NEGO); + if ((pSRB->MsgInBuf[1] != 3) || + (pSRB->MsgInBuf[2] != 1)) { + /* reject_msg: */ + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL); + *pscsi_status = PH_BUS_FREE; + /* .. initial phase */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else if (!(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4])) { + /* set async */ + pDCB = pSRB->pSRBDCB; + /* disable sync & sync nego */ + pDCB->SyncMode &= + ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->tinfo.goal.period = 0; + pDCB->tinfo.goal.offset = 0; + pDCB->tinfo.current.period = 0; + pDCB->tinfo.current.offset = 0; + pDCB->tinfo.current.width = + MSG_EXT_WDTR_BUS_8_BIT; + /* + * + * program SCSI control register + * + */ + trm_reg_write8(pDCB->SyncPeriod,TRMREG_SCSI_SYNC); + trm_reg_write8(pDCB->SyncOffset,TRMREG_SCSI_OFFSET); + trm_SetXferRate(pACB,pSRB,pDCB); + *pscsi_status = PH_BUS_FREE; + /* .. initial phase */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + return; + } else { + /* set sync */ + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode |= + SYNC_NEGO_ENABLE+SYNC_NEGO_DONE; + pDCB->MaxNegoPeriod = pSRB->MsgInBuf[3]; + /* Transfer period factor */ + pDCB->SyncOffset = pSRB->MsgInBuf[4]; + /* REQ/ACK offset */ + if(pACB->AdaptType == 1) { + for(bIndex = 0; bIndex < 7; bIndex++) { + if(pSRB->MsgInBuf[3] <= + dc395u2x_clock_period[bIndex]) { + pDCB->tinfo.goal.period = + dc395u2x_tinfo_period[bIndex]; + pDCB->tinfo.current.period = + dc395u2x_tinfo_period[bIndex]; + pDCB->tinfo.goal.offset = + pDCB->SyncOffset; + pDCB->tinfo.current.offset = + pDCB->SyncOffset; + pDCB->SyncPeriod |= (bIndex|LVDS_SYNC); + break; + } + } + } else { + for(bIndex = 0; bIndex < 7; bIndex++) { + if(pSRB->MsgInBuf[3] <= + dc395x_clock_period[bIndex]) { + pDCB->tinfo.goal.period = + dc395x_tinfo_period[bIndex]; + pDCB->tinfo.current.period = + dc395x_tinfo_period[bIndex]; + pDCB->tinfo.goal.offset = + pDCB->SyncOffset; + pDCB->tinfo.current.offset = + pDCB->SyncOffset; + pDCB->SyncPeriod |= + (bIndex|ALT_SYNC); + break; + } + } + } + /* + * + * program SCSI control register + * + */ + trm_reg_write8(pDCB->SyncPeriod, + TRMREG_SCSI_SYNC); + trm_reg_write8(pDCB->SyncOffset, + TRMREG_SCSI_OFFSET); + trm_SetXferRate(pACB,pSRB,pDCB); + *pscsi_status=PH_BUS_FREE;/*.. initial phase*/ + trm_reg_write16(DO_DATALATCH,TRMREG_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI command + */ + trm_reg_write8(SCMD_MSGACCEPT,TRMREG_SCSI_COMMAND); + return; + } + } + *pscsi_status = PH_BUS_FREE; + /* .. initial phase */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop */ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + } +} + +static void +trm_MsgInPhase1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + + trm_reg_write16(DO_CLRFIFO, TRMREG_SCSI_CONTROL); + trm_reg_write32(1,TRMREG_SCSI_COUNTER); + if (!(pSRB->SRBState & SRB_MSGIN)) { + pSRB->SRBState &= SRB_DISCONNECT; + pSRB->SRBState |= SRB_MSGIN; + } + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop*/ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_FIFO_IN, TRMREG_SCSI_COMMAND); +} + +static void +trm_Nop0(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + +} + +static void +trm_Nop1(PACB pACB, PSRB pSRB, u_int16_t *pscsi_status) +{ + +} + +static void +trm_SetXferRate(PACB pACB,PSRB pSRB, PDCB pDCB) +{ + union ccb *pccb; + struct ccb_trans_settings neg; + u_int16_t cnt, i; + u_int8_t bval; + PDCB pDCBTemp; + + /* + * set all lun device's period , offset + */ + TRM_DPRINTF("trm_SetXferRate\n"); + pccb = pSRB->pccb; + neg.sync_period = pDCB->tinfo.goal.period; + neg.sync_offset = pDCB->tinfo.goal.offset; + neg.valid = CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID; + xpt_setup_ccb(&neg.ccb_h, pccb->ccb_h.path, /* priority */1); + xpt_async(AC_TRANSFER_NEG, pccb->ccb_h.path, &neg); + if (!(pDCB->IdentifyMsg & 0x07)) { + pDCBTemp = pACB->pLinkDCB; + cnt = pACB->DeviceCnt; + bval = pDCB->TargetID; + for (i = 0; i < cnt; i++) { + if (pDCBTemp->TargetID == bval) { + pDCBTemp->SyncPeriod = pDCB->SyncPeriod; + pDCBTemp->SyncOffset = pDCB->SyncOffset; + pDCBTemp->SyncMode = pDCB->SyncMode; + } + pDCBTemp = pDCBTemp->pNextDCB; + } + } + return; +} + +/* + * scsiiom + * trm_Interrupt + * + * + * ---SCSI bus phase + * + * PH_DATA_OUT 0x00 Data out phase + * PH_DATA_IN 0x01 Data in phase + * PH_COMMAND 0x02 Command phase + * PH_STATUS 0x03 Status phase + * PH_BUS_FREE 0x04 Invalid phase used as bus free + * PH_BUS_FREE 0x05 Invalid phase used as bus free + * PH_MSG_OUT 0x06 Message out phase + * PH_MSG_IN 0x07 Message in phase + * + */ +static void +trm_Disconnect(PACB pACB) +{ + PDCB pDCB; + PSRB pSRB, psrb; + u_int16_t i,j, cnt; + u_int target_id,target_lun; + + TRM_DPRINTF("trm_Disconnect...............\n "); + + pDCB = pACB->pActiveDCB; + if (!pDCB) { + TRM_DPRINTF(" Exception Disconnect DCB=NULL..............\n "); + j = 400; + while (--j) + DELAY(1); + /* 1 msec */ + trm_reg_write16((DO_CLRFIFO | DO_HWRESELECT), + TRMREG_SCSI_CONTROL); + return; + } + pSRB = pDCB->pActiveSRB; + /* bug pSRB=0 */ + target_id = pSRB->pccb->ccb_h.target_id; + target_lun = pSRB->pccb->ccb_h.target_lun; + TRM_DPRINTF(":pDCB->pActiveSRB= %8x \n ",(u_int) pDCB->pActiveSRB); + pACB->pActiveDCB = 0; + pSRB->ScsiPhase = PH_BUS_FREE; + /* SCSI bus free Phase */ + trm_reg_write16((DO_CLRFIFO | DO_HWRESELECT), TRMREG_SCSI_CONTROL); + if (pSRB->SRBState & SRB_UNEXPECT_RESEL) { + pSRB->SRBState = 0; + trm_DoWaitingSRB(pACB); + } else if (pSRB->SRBState & SRB_ABORT_SENT) { + pDCB->DCBFlag = 0; + cnt = pDCB->GoingSRBCnt; + pDCB->GoingSRBCnt = 0; + pSRB = pDCB->pGoingSRB; + for (i = 0; i < cnt; i++) { + psrb = pSRB->pNextSRB; + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pSRB = psrb; + } + pDCB->pGoingSRB = 0; + trm_DoWaitingSRB(pACB); + } else { + if ((pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || + !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED))) { + /* Selection time out */ + if (!(pACB->scan_devices[target_id][target_lun]) && + pSRB->CmdBlock[0] != 0x00 && /* TEST UNIT READY */ + pSRB->CmdBlock[0] != INQUIRY) { + pSRB->SRBState = SRB_READY; + trm_RewaitSRB(pDCB, pSRB); + } else { + pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; + goto disc1; + } + } else if (pSRB->SRBState & SRB_DISCONNECT) { + /* + * SRB_DISCONNECT + */ + trm_DoWaitingSRB(pACB); + } else if (pSRB->SRBState & SRB_COMPLETED) { +disc1: + /* + * SRB_COMPLETED + */ + pDCB->pActiveSRB = 0; + pSRB->SRBState = SRB_FREE; + trm_SRBdone(pACB, pDCB, pSRB); + } + } + return; +} + +static void +trm_Reselect(PACB pACB) +{ + PDCB pDCB; + PSRB pSRB; + u_int16_t RselTarLunId; + + TRM_DPRINTF("trm_Reselect................. \n"); + pDCB = pACB->pActiveDCB; + if (pDCB) { + /* Arbitration lost but Reselection win */ + pSRB = pDCB->pActiveSRB; + pSRB->SRBState = SRB_READY; + trm_RewaitSRB(pDCB, pSRB); + } + /* Read Reselected Target Id and LUN */ + RselTarLunId = trm_reg_read16(TRMREG_SCSI_TARGETID) & 0x1FFF; + pDCB = pACB->pLinkDCB; + while (RselTarLunId != *((u_int16_t *) &pDCB->TargetID)) { + /* get pDCB of the reselect id */ + pDCB = pDCB->pNextDCB; + } + + pACB->pActiveDCB = pDCB; + if (pDCB->SyncMode & EN_TAG_QUEUING) { + pSRB = &pACB->TmpSRB; + pDCB->pActiveSRB = pSRB; + } else { + pSRB = pDCB->pActiveSRB; + if (!pSRB || !(pSRB->SRBState & SRB_DISCONNECT)) { + /* + * abort command + */ + pSRB = &pACB->TmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + trm_EnableMsgOutAbort1(pACB, pSRB); + } else { + if (pDCB->DCBFlag & ABORT_DEV_) { + pSRB->SRBState = SRB_ABORT_SENT; + trm_EnableMsgOutAbort1(pACB, pSRB); + } else + pSRB->SRBState = SRB_DATA_XFER; + } + } + pSRB->ScsiPhase = PH_BUS_FREE; + /* SCSI bus free Phase */ + /* + * Program HA ID, target ID, period and offset + */ + trm_reg_write8((u_int8_t) RselTarLunId,TRMREG_SCSI_TARGETID); + /* target ID */ + trm_reg_write8(pACB->AdaptSCSIID,TRMREG_SCSI_HOSTID); + /* host ID */ + trm_reg_write8(pDCB->SyncPeriod,TRMREG_SCSI_SYNC); + /* period */ + trm_reg_write8(pDCB->SyncOffset,TRMREG_SCSI_OFFSET); + /* offset */ + trm_reg_write16(DO_DATALATCH, TRMREG_SCSI_CONTROL); + /* it's important for atn stop*/ + /* + * SCSI cammand + */ + trm_reg_write8(SCMD_MSGACCEPT, TRMREG_SCSI_COMMAND); + /* to rls the /ACK signal */ +} + +static void +trm_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB) +{ + PSRB psrb; + u_int8_t bval, bval1,status; + union ccb *pccb; + struct ccb_scsiio *pcsio; + PSCSI_INQDATA ptr; + int intflag; + u_int target_id,target_lun; + PDCB pTempDCB; + + pccb = pSRB->pccb; + if (pccb == NULL) + return; + pcsio = &pccb->csio; + target_id = pSRB->pccb->ccb_h.target_id; + target_lun = pSRB->pccb->ccb_h.target_lun; + if ((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { + bus_dmasync_op_t op; + if ((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + op = BUS_DMASYNC_POSTREAD; + else + op = BUS_DMASYNC_POSTWRITE; + bus_dmamap_sync(pACB->buffer_dmat, pSRB->dmamap, op); + bus_dmamap_unload(pACB->buffer_dmat, pSRB->dmamap); + } + /* + * + * target status + * + */ + status = pSRB->TargetStatus; + pcsio->scsi_status=SCSI_STAT_GOOD; + pccb->ccb_h.status = CAM_REQ_CMP; + if (pSRB->SRBFlag & AUTO_REQSENSE) { + /* + * status of auto request sense + */ + pSRB->SRBFlag &= ~AUTO_REQSENSE; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = SCSI_STATUS_CHECK_COND; + + if (status == SCSI_STATUS_CHECK_COND) { + pccb->ccb_h.status = CAM_SEL_TIMEOUT; + goto ckc_e; + } + *((u_long *) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + *((u_long *) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + pSRB->SRBTotalXferLength = pSRB->Segment1[1]; + pSRB->pSRBSGL->address = pSRB->SgSenseTemp.address; + pSRB->pSRBSGL->length = pSRB->SgSenseTemp.length; + pcsio->scsi_status = SCSI_STATUS_CHECK_COND; + bzero(&pcsio->sense_data, pcsio->sense_len); + bcopy(trm_get_sense_buf(pACB, pSRB), &pcsio->sense_data, + pcsio->sense_len); + pcsio->ccb_h.status = CAM_SCSI_STATUS_ERROR + | CAM_AUTOSNS_VALID; + goto ckc_e; + } + /* + * target status + */ + if (status) { + if (status == SCSI_STATUS_CHECK_COND) { + if ((pcsio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) { + TRM_DPRINTF("trm_RequestSense..................\n"); + trm_RequestSense(pACB, pDCB, pSRB); + return; + } + pcsio->scsi_status = SCSI_STATUS_CHECK_COND; + pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + goto ckc_e; + } else if (status == SCSI_STAT_QUEUEFULL) { + bval = (u_int8_t) pDCB->GoingSRBCnt; + bval--; + pDCB->MaxActiveCommandCnt = bval; + trm_RewaitSRB(pDCB, pSRB); + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + return; + } else if (status == SCSI_STAT_SEL_TIMEOUT) { + pSRB->AdaptStatus = H_SEL_TIMEOUT; + pSRB->TargetStatus = 0; + pcsio->scsi_status = SCSI_STAT_SEL_TIMEOUT; + pccb->ccb_h.status = CAM_SEL_TIMEOUT; + } else if (status == SCSI_STAT_BUSY) { + TRM_DPRINTF("trm: target busy at %s %d\n", + __FILE__, __LINE__); + pcsio->scsi_status = SCSI_STAT_BUSY; + pccb->ccb_h.status = CAM_SCSI_BUSY; + return; + /* The device busy, try again later? */ + } else if (status == SCSI_STAT_RESCONFLICT) { + TRM_DPRINTF("trm: target reserved at %s %d\n", + __FILE__, __LINE__); + pcsio->scsi_status = SCSI_STAT_RESCONFLICT; + pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; /*XXX*/ + return; + } else { + pSRB->AdaptStatus = 0; + if (pSRB->RetryCnt) { + pSRB->RetryCnt--; + pSRB->TargetStatus = 0; + pSRB->SRBSGIndex = 0; + if (trm_StartSCSI(pACB, pDCB, pSRB)) { + /* + * If trm_StartSCSI return 1 : + * current interrupt status is interrupt + * disreenable + * It's said that SCSI processor has more + * one SRB need to do + */ + trm_RewaitSRB(pDCB, pSRB); + } + return; + } else { + TRM_DPRINTF("trm: driver stuffup at %s %d\n", + __FILE__, __LINE__); + pccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + } + } + } else { + /* + * process initiator status.......................... + * Adapter (initiator) status + */ + status = pSRB->AdaptStatus; + if (status & H_OVER_UNDER_RUN) { + pSRB->TargetStatus = 0; + pccb->ccb_h.status = CAM_DATA_RUN_ERR; + /* Illegal length (over/under run) */ + } else if (pSRB->SRBStatus & PARITY_ERROR) { + TRM_DPRINTF("trm: driver stuffup %s %d\n", + __FILE__, __LINE__); + pDCB->tinfo.goal.period = 0; + pDCB->tinfo.goal.offset = 0; + /* Driver failed to perform operation */ + pccb->ccb_h.status = CAM_UNCOR_PARITY; + } else { + /* no error */ + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pccb->ccb_h.status = CAM_REQ_CMP; + /* there is no error, (sense is invalid) */ + } + } +ckc_e: + if (pACB->scan_devices[target_id][target_lun]) { + /* + * if SCSI command in "scan devices" duty + */ + if (pSRB->CmdBlock[0] == TEST_UNIT_READY) + pACB->scan_devices[target_id][target_lun] = 0; + /* SCSI command phase :test unit ready */ + else if (pSRB->CmdBlock[0] == INQUIRY) { + /* + * SCSI command phase :inquiry scsi device data + * (type,capacity,manufacture.... + */ + if (pccb->ccb_h.status == CAM_SEL_TIMEOUT) + goto NO_DEV; + ptr = (PSCSI_INQDATA) pcsio->data_ptr; + /* page fault */ + TRM_DPRINTF("trm_SRBdone..PSCSI_INQDATA:%2x \n", + ptr->DevType); + bval1 = ptr->DevType & SCSI_DEVTYPE; + if (bval1 == SCSI_NODEV) { +NO_DEV: + TRM_DPRINTF("trm_SRBdone NO Device:target_id= %d ,target_lun= %d \n", + target_id, + target_lun); + intflag = splcam(); + pACB->scan_devices[target_id][target_lun] = 0; + /* no device set scan device flag =0*/ + /* pDCB Q link */ + /* move the head of DCB to tempDCB*/ + pTempDCB=pACB->pLinkDCB; + /* search current DCB for pass link */ + while (pTempDCB->pNextDCB != pDCB) { + pTempDCB = pTempDCB->pNextDCB; + } + /* + * when the current DCB found than connect + * current DCB tail + */ + /* to the DCB tail that before current DCB */ + pTempDCB->pNextDCB = pDCB->pNextDCB; + /* + * if there was only one DCB ,connect his tail + * to his head + */ + if (pACB->pLinkDCB == pDCB) + pACB->pLinkDCB = pTempDCB->pNextDCB; + if (pACB->pDCBRunRobin == pDCB) + pACB->pDCBRunRobin = pTempDCB->pNextDCB; + pDCB->DCBstatus &= ~DS_IN_QUEUE; + pACB->DeviceCnt--; + if (pACB->DeviceCnt == 0) { + pACB->pLinkDCB = NULL; + pACB->pDCBRunRobin = NULL; + } + splx(intflag); + } else { +#ifdef trm_DEBUG1 + int j; + for (j = 0; j < 28; j++) { + TRM_DPRINTF("ptr=%2x ", + ((u_int8_t *)ptr)[j]); + } +#endif + pDCB->DevType = bval1; + if (bval1 == SCSI_DASD || + bval1 == SCSI_OPTICAL) { + if ((((ptr->Vers & 0x07) >= 2) || + ((ptr->RDF & 0x0F) == 2)) && + (ptr->Flags & SCSI_INQ_CMDQUEUE) && + (pDCB->DevMode & TAG_QUEUING_) && + (pDCB->DevMode & EN_DISCONNECT_)) { + if (pDCB->DevMode & + TAG_QUEUING_) { + pDCB-> + MaxActiveCommandCnt = + pACB->TagMaxNum; + pDCB->SyncMode |= + EN_TAG_QUEUING; + pDCB->tinfo.disc_tag |= + TRM_CUR_TAGENB; + } else { + pDCB->SyncMode |= + EN_ATN_STOP; + pDCB->tinfo.disc_tag &= + ~TRM_CUR_TAGENB; + } + } + } + } + /* pSRB->CmdBlock[0] == INQUIRY */ + } + /* pACB->scan_devices[target_id][target_lun] */ + } + intflag = splcam(); + /* ReleaseSRB(pDCB, pSRB); */ + if (pSRB == pDCB->pGoingSRB) + pDCB->pGoingSRB = pSRB->pNextSRB; + else { + psrb = pDCB->pGoingSRB; + while (psrb->pNextSRB != pSRB) { + psrb = psrb->pNextSRB; + } + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLastSRB) { + pDCB->pGoingLastSRB = psrb; + } + } + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pDCB->GoingSRBCnt--; + trm_DoWaitingSRB(pACB); + + splx(intflag); + /* Notify cmd done */ + xpt_done (pccb); +} + +static void +trm_DoingSRB_Done(PACB pACB) +{ + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + u_int16_t cnt, i; + union ccb *pccb; + + pDCB = pACB->pLinkDCB; + if (pDCB == NULL) + return; + pdcb = pDCB; + do { + cnt = pdcb->GoingSRBCnt; + psrb = pdcb->pGoingSRB; + for (i = 0; i < cnt; i++) { + psrb2 = psrb->pNextSRB; + pccb = psrb->pccb; + pccb->ccb_h.status = CAM_SEL_TIMEOUT; + /* ReleaseSRB(pDCB, pSRB); */ + psrb->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = psrb; + xpt_done(pccb); + psrb = psrb2; + } + pdcb->GoingSRBCnt = 0;; + pdcb->pGoingSRB = NULL; + pdcb = pdcb->pNextDCB; + } + while (pdcb != pDCB); +} + +static void +trm_ResetSCSIBus(PACB pACB) +{ + int intflag; + + intflag = splcam(); + pACB->ACBFlag |= RESET_DEV; + + trm_reg_write16(DO_RSTSCSI,TRMREG_SCSI_CONTROL); + while (!(trm_reg_read16(TRMREG_SCSI_INTSTATUS) & INT_SCSIRESET)); + splx(intflag); + return; +} + +static void +trm_ScsiRstDetect(PACB pACB) +{ + int intflag; + u_long wlval; + + TRM_DPRINTF("trm_ScsiRstDetect \n"); + wlval = 1000; + while (--wlval) + DELAY(1000); + intflag = splcam(); + trm_reg_write8(STOPDMAXFER,TRMREG_DMA_CONTROL); + + trm_reg_write16(DO_CLRFIFO,TRMREG_SCSI_CONTROL); + + if (pACB->ACBFlag & RESET_DEV) + pACB->ACBFlag |= RESET_DONE; + else { + pACB->ACBFlag |= RESET_DETECT; + trm_ResetDevParam(pACB); + /* trm_DoingSRB_Done(pACB); ???? */ + trm_RecoverSRB(pACB); + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; + trm_DoWaitingSRB(pACB); + } + splx(intflag); + return; +} + +static void +trm_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB) +{ + union ccb *pccb; + struct ccb_scsiio *pcsio; + + pccb = pSRB->pccb; + pcsio = &pccb->csio; + + pSRB->SRBFlag |= AUTO_REQSENSE; + pSRB->Segment0[0] = *((u_long *) &(pSRB->CmdBlock[0])); + pSRB->Segment0[1] = *((u_long *) &(pSRB->CmdBlock[4])); + pSRB->Segment1[0] = (u_long) ((pSRB->ScsiCmdLen << 8) + + pSRB->SRBSGCount); + pSRB->Segment1[1] = pSRB->SRBTotalXferLength; /* ?????????? */ + + /* $$$$$$ Status of initiator/target $$$$$$$$ */ + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + /* $$$$$$ Status of initiator/target $$$$$$$$ */ + + pSRB->SRBTotalXferLength = sizeof(pcsio->sense_data); + pSRB->SgSenseTemp.address = pSRB->pSRBSGL->address; + pSRB->SgSenseTemp.length = pSRB->pSRBSGL->length; + pSRB->pSRBSGL->address = trm_get_sense_bufaddr(pACB, pSRB); + pSRB->pSRBSGL->length = (u_long) sizeof(struct scsi_sense_data); + pSRB->SRBSGCount = 1; + pSRB->SRBSGIndex = 0; + + *((u_long *) &(pSRB->CmdBlock[0])) = 0x00000003; + pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; + *((u_int16_t *) &(pSRB->CmdBlock[4])) = pcsio->sense_len; + pSRB->ScsiCmdLen = 6; + + if (trm_StartSCSI(pACB, pDCB, pSRB)) + /* + * If trm_StartSCSI return 1 : + * current interrupt status is interrupt disreenable + * It's said that SCSI processor has more one SRB need to do + */ + trm_RewaitSRB(pDCB, pSRB); +} + +static void +trm_EnableMsgOutAbort2(PACB pACB, PSRB pSRB) +{ + + pSRB->MsgCnt = 1; + trm_reg_write16(DO_SETATN, TRMREG_SCSI_CONTROL); +} + +static void +trm_EnableMsgOutAbort1(PACB pACB, PSRB pSRB) +{ + + pSRB->MsgOutBuf[0] = MSG_ABORT; + trm_EnableMsgOutAbort2(pACB, pSRB); +} + +static void +trm_initDCB(PACB pACB, PDCB pDCB, u_int16_t unit,u_int32_t i,u_int32_t j) +{ + PNVRAMTYPE pEEpromBuf; + u_int8_t bval,PeriodIndex; + u_int target_id,target_lun; + PDCB pTempDCB; + int intflag; + + target_id = i; + target_lun = j; + + /* + * Using the lun 0 device to init other DCB first, if the device + * has been initialized. + * I don't want init sync arguments one by one, it is the same. + */ + if (target_lun != 0 && + (pACB->DCBarray[target_id][0].DCBstatus & DS_IN_QUEUE)) + bcopy(&pACB->DCBarray[target_id][0], pDCB, + sizeof(TRM_DCB)); + intflag = splcam(); + if (pACB->pLinkDCB == 0) { + pACB->pLinkDCB = pDCB; + /* + * RunRobin impersonate the role + * that let each device had good proportion + * about SCSI command proceeding + */ + pACB->pDCBRunRobin = pDCB; + pDCB->pNextDCB = pDCB; + } else { + pTempDCB=pACB->pLinkDCB; + /* search the last nod of DCB link */ + while (pTempDCB->pNextDCB != pACB->pLinkDCB) + pTempDCB = pTempDCB->pNextDCB; + /* connect current DCB with last DCB tail */ + pTempDCB->pNextDCB = pDCB; + /* connect current DCB tail to this DCB Q head */ + pDCB->pNextDCB=pACB->pLinkDCB; + } + splx(intflag); + + pACB->DeviceCnt++; + pDCB->TargetID = target_id; + pDCB->TargetLUN = target_lun; + pDCB->pWaitingSRB = NULL; + pDCB->pGoingSRB = NULL; + pDCB->GoingSRBCnt = 0; + pDCB->pActiveSRB = NULL; + pDCB->MaxActiveCommandCnt = 1; + pDCB->DCBFlag = 0; + pDCB->DCBstatus |= DS_IN_QUEUE; + /* $$$$$$$ */ + pEEpromBuf = &trm_eepromBuf[unit]; + pDCB->DevMode = pEEpromBuf->NvramTarget[target_id].NvmTarCfg0; + pDCB->AdpMode = pEEpromBuf->NvramChannelCfg; + /* $$$$$$$ */ + /* + * disconnect enable ? + */ + if (pDCB->DevMode & NTC_DO_DISCONNECT) { + bval = 0xC0; + pDCB->tinfo.disc_tag |= TRM_USR_DISCENB ; + } else { + bval = 0x80; + pDCB->tinfo.disc_tag &= ~(TRM_USR_DISCENB); + } + bval |= target_lun; + pDCB->IdentifyMsg = bval; + if (target_lun != 0 && + (pACB->DCBarray[target_id][0].DCBstatus & DS_IN_QUEUE)) + return; + /* $$$$$$$ */ + /* + * tag Qing enable ? + */ + if (pDCB->DevMode & TAG_QUEUING_) { + pDCB->tinfo.disc_tag |= TRM_USR_TAGENB ; + } else + pDCB->tinfo.disc_tag &= ~(TRM_USR_TAGENB); + /* $$$$$$$ */ + /* + * wide nego ,sync nego enable ? + */ + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + PeriodIndex = pEEpromBuf->NvramTarget[target_id].NvmTarPeriod & 0x07; + if(pACB->AdaptType==1) {/* is U2? */ + pDCB->MaxNegoPeriod=dc395u2x_clock_period[ PeriodIndex ]; + pDCB->tinfo.user.period=pDCB->MaxNegoPeriod; + pDCB->tinfo.user.offset=(pDCB->SyncMode & SYNC_NEGO_ENABLE) ? 31 : 0; + } else { + pDCB->MaxNegoPeriod=dc395x_clock_period[ PeriodIndex ]; + pDCB->tinfo.user.period=pDCB->MaxNegoPeriod; + pDCB->tinfo.user.offset=(pDCB->SyncMode & SYNC_NEGO_ENABLE) ? 15 : 0; + } + pDCB->SyncMode = 0; + if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && + (pACB->Config & HCC_WIDE_CARD)) + pDCB->SyncMode |= WIDE_NEGO_ENABLE; + /* enable wide nego */ + if (pDCB->DevMode & NTC_DO_SYNC_NEGO) + pDCB->SyncMode |= SYNC_NEGO_ENABLE; + /* enable sync nego */ + /* $$$$$$$ */ + /* + * Fill in tinfo structure. + */ + pDCB->tinfo.user.width = (pDCB->SyncMode & WIDE_NEGO_ENABLE) ? + MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT; + + pDCB->tinfo.current.period = 0; + pDCB->tinfo.current.offset = 0; + pDCB->tinfo.current.width = MSG_EXT_WDTR_BUS_8_BIT; +} + +static void +trm_srbmapSG(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + PSRB pSRB; + + pSRB=(PSRB) arg; + pSRB->SRBSGPhyAddr=segs->ds_addr; + return; +} + +static int +trm_initSRB(PACB pACB) +{ + u_int16_t i; + PSRB pSRB; + + for(i = 0; i < TRM_MAX_SRB_CNT; i++) { + pSRB = (PSRB)&pACB->pFreeSRB[i]; + + /* DMA tag for our S/G structures */ + if(bus_dma_tag_create( + /*parent_dmat*/pSRB->parent_dmat, + /*alignment*/ 1, + /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/ NULL, + /*filterarg*/ NULL, + /*maxsize*/ TRM_MAX_SG_LISTENTRY * sizeof(SGentry), + /*nsegments*/ 1, + /*maxsegsz*/ TRM_MAXTRANSFER_SIZE, + /*flags*/ 0, + /*dmat*/ &pSRB->sg_dmat) != 0) { + return ENXIO; + } + if(bus_dmamem_alloc(pSRB->sg_dmat, (void **)&pSRB->pSRBSGL, + BUS_DMA_NOWAIT, &pSRB->sg_dmamap) !=0 ) { + return ENXIO; + } + bus_dmamap_load(pSRB->sg_dmat, pSRB->sg_dmamap, pSRB->pSRBSGL, + TRM_MAX_SG_LISTENTRY * sizeof(SGentry), + trm_srbmapSG, pSRB, /*flags*/0); + if(i != TRM_MAX_SRB_CNT - 1) { + /* + ** link all SRB + */ + pSRB->pNextSRB = &pACB->pFreeSRB[i+1]; + } else { + /* + ** load NULL to NextSRB of the last SRB + */ + pSRB->pNextSRB = NULL; + } + pSRB->TagNumber = i; + } + return (0); +} + + + + +static void +trm_initACB(PACB pACB, u_int8_t adaptType, u_int16_t unit) +{ + PNVRAMTYPE pEEpromBuf; + + pEEpromBuf = &trm_eepromBuf[unit]; + pACB->max_id = 15; + + if (pEEpromBuf->NvramChannelCfg & NAC_SCANLUN) + pACB->max_lun = 7; + else + pACB->max_lun = 0; + + TRM_DPRINTF("trm: pACB->max_id= %d pACB->max_lun= %d \n", + pACB->max_id, pACB->max_lun); + pACB->pLinkDCB = NULL; + pACB->pDCBRunRobin = NULL; + pACB->pActiveDCB = NULL; + pACB->AdapterUnit = (u_int8_t)unit; + pACB->AdaptSCSIID = pEEpromBuf->NvramScsiId; + pACB->AdaptSCSILUN = 0; + pACB->DeviceCnt = 0; + pACB->AdaptType = adaptType; + pACB->TagMaxNum = 2 << pEEpromBuf->NvramMaxTag; + pACB->ACBFlag = 0; + return; +} + +static void +NVRAM_trm_write_all(PNVRAMTYPE pEEpromBuf,PACB pACB) +{ + u_int8_t *bpEeprom = (u_int8_t *) pEEpromBuf; + u_int8_t bAddr; + + /* Enable SEEPROM */ + trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) | EN_EEPROM), + TRMREG_GEN_CONTROL); + /* + * Write enable + */ + NVRAM_trm_write_cmd(pACB, 0x04, 0xFF); + trm_reg_write8(0, TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++) { + NVRAM_trm_set_data(pACB, bAddr, *bpEeprom); + } + /* + * Write disable + */ + NVRAM_trm_write_cmd(pACB, 0x04, 0x00); + trm_reg_write8(0 , TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + /* Disable SEEPROM */ + trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) & ~EN_EEPROM), + TRMREG_GEN_CONTROL); + return; +} + +static void +NVRAM_trm_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData) +{ + int i; + u_int8_t bSendData; + /* + * Send write command & address + */ + + NVRAM_trm_write_cmd(pACB, 0x05, bAddr); + /* + * Write data + */ + for (i = 0; i < 8; i++, bData <<= 1) { + bSendData = NVR_SELECT; + if (bData & 0x80) + /* Start from bit 7 */ + bSendData |= NVR_BITOUT; + trm_reg_write8(bSendData , TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + } + trm_reg_write8(NVR_SELECT , TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + /* + * Disable chip select + */ + trm_reg_write8(0 , TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + trm_reg_write8(NVR_SELECT ,TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + /* + * Wait for write ready + */ + while (1) { + trm_reg_write8((NVR_SELECT | NVR_CLOCK), TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + trm_reg_write8(NVR_SELECT, TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + if (trm_reg_read8(TRMREG_GEN_NVRAM) & NVR_BITIN) { + break; + } + } + /* + * Disable chip select + */ + trm_reg_write8(0, TRMREG_GEN_NVRAM); + return; +} + +static void +NVRAM_trm_read_all(PNVRAMTYPE pEEpromBuf, PACB pACB) +{ + u_int8_t *bpEeprom = (u_int8_t*) pEEpromBuf; + u_int8_t bAddr; + + /* + * Enable SEEPROM + */ + trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) | EN_EEPROM), + TRMREG_GEN_CONTROL); + for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++) + *bpEeprom = NVRAM_trm_get_data(pACB, bAddr); + /* + * Disable SEEPROM + */ + trm_reg_write8((trm_reg_read8(TRMREG_GEN_CONTROL) & ~EN_EEPROM), + TRMREG_GEN_CONTROL); + return; +} + +static u_int8_t +NVRAM_trm_get_data(PACB pACB, u_int8_t bAddr) +{ + int i; + u_int8_t bReadData, bData = 0; + /* + * Send read command & address + */ + + NVRAM_trm_write_cmd(pACB, 0x06, bAddr); + + for (i = 0; i < 8; i++) { + /* + * Read data + */ + trm_reg_write8((NVR_SELECT | NVR_CLOCK) , TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + trm_reg_write8(NVR_SELECT , TRMREG_GEN_NVRAM); + /* + * Get data bit while falling edge + */ + bReadData = trm_reg_read8(TRMREG_GEN_NVRAM); + bData <<= 1; + if (bReadData & NVR_BITIN) { + bData |= 1; + } + NVRAM_trm_wait_30us(pACB); + } + /* + * Disable chip select + */ + trm_reg_write8(0, TRMREG_GEN_NVRAM); + return (bData); +} + +static void +NVRAM_trm_wait_30us(PACB pACB) +{ + + /* ScsiPortStallExecution(30); wait 30 us */ + trm_reg_write8(5, TRMREG_GEN_TIMER); + while (!(trm_reg_read8(TRMREG_GEN_STATUS) & GTIMEOUT)); + return; +} + +static void +NVRAM_trm_write_cmd(PACB pACB, u_int8_t bCmd, u_int8_t bAddr) +{ + int i; + u_int8_t bSendData; + + for (i = 0; i < 3; i++, bCmd <<= 1) { + /* + * Program SB+OP code + */ + bSendData = NVR_SELECT; + if (bCmd & 0x04) + bSendData |= NVR_BITOUT; + /* start from bit 2 */ + trm_reg_write8(bSendData, TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + } + for (i = 0; i < 7; i++, bAddr <<= 1) { + /* + * Program address + */ + bSendData = NVR_SELECT; + if (bAddr & 0x40) + /* Start from bit 6 */ + bSendData |= NVR_BITOUT; + trm_reg_write8(bSendData , TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + trm_reg_write8((bSendData | NVR_CLOCK), TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); + } + trm_reg_write8(NVR_SELECT, TRMREG_GEN_NVRAM); + NVRAM_trm_wait_30us(pACB); +} + +static void +trm_check_eeprom(PNVRAMTYPE pEEpromBuf, PACB pACB) +{ + u_int16_t *wpEeprom = (u_int16_t *) pEEpromBuf; + u_int16_t wAddr, wCheckSum; + u_long dAddr, *dpEeprom; + + NVRAM_trm_read_all(pEEpromBuf,pACB); + wCheckSum = 0; + for (wAddr = 0, wpEeprom = (u_int16_t *) pEEpromBuf; + wAddr < 64; wAddr++, wpEeprom++) { + wCheckSum += *wpEeprom; + } + if (wCheckSum != 0x1234) { + /* + * Checksum error, load default + */ + pEEpromBuf->NvramSubVendorID[0] = (u_int8_t) PCI_Vendor_ID_TEKRAM; + pEEpromBuf->NvramSubVendorID[1] = + (u_int8_t) (PCI_Vendor_ID_TEKRAM >> 8); + pEEpromBuf->NvramSubSysID[0] = (u_int8_t) PCI_Device_ID_TRM_S1040; + pEEpromBuf->NvramSubSysID[1] = + (u_int8_t) (PCI_Device_ID_TRM_S1040 >> 8); + pEEpromBuf->NvramSubClass = 0x00; + pEEpromBuf->NvramVendorID[0] = (u_int8_t) PCI_Vendor_ID_TEKRAM; + pEEpromBuf->NvramVendorID[1] = + (u_int8_t) (PCI_Vendor_ID_TEKRAM >> 8); + pEEpromBuf->NvramDeviceID[0] = (u_int8_t) PCI_Device_ID_TRM_S1040; + pEEpromBuf->NvramDeviceID[1] = + (u_int8_t) (PCI_Device_ID_TRM_S1040 >> 8); + pEEpromBuf->NvramReserved = 0x00; + + for (dAddr = 0, dpEeprom = (u_long *) pEEpromBuf->NvramTarget; + dAddr < 16; dAddr++, dpEeprom++) { + *dpEeprom = 0x00000077; + /* NvmTarCfg3,NvmTarCfg2,NvmTarPeriod,NvmTarCfg0 */ + } + + *dpEeprom++ = 0x04000F07; + /* NvramMaxTag,NvramDelayTime,NvramChannelCfg,NvramScsiId */ + *dpEeprom++ = 0x00000015; + /* NvramReserved1,NvramBootLun,NvramBootTarget,NvramReserved0 */ + for (dAddr = 0; dAddr < 12; dAddr++, dpEeprom++) + *dpEeprom = 0x00; + pEEpromBuf->NvramCheckSum = 0x00; + for (wAddr = 0, wCheckSum = 0, wpEeprom = (u_int16_t *) pEEpromBuf; + wAddr < 63; wAddr++, wpEeprom++) + wCheckSum += *wpEeprom; + *wpEeprom = 0x1234 - wCheckSum; + NVRAM_trm_write_all(pEEpromBuf,pACB); + } + return; +} +static int +trm_initAdapter(PACB pACB, u_int16_t unit) +{ + PNVRAMTYPE pEEpromBuf; + u_int16_t wval; + u_int8_t bval; + + pEEpromBuf = &trm_eepromBuf[unit]; + + /* 250ms selection timeout */ + trm_reg_write8(SEL_TIMEOUT, TRMREG_SCSI_TIMEOUT); + /* Mask all the interrupt */ + trm_reg_write8(0x00, TRMREG_DMA_INTEN); + trm_reg_write8(0x00, TRMREG_SCSI_INTEN); + /* Reset SCSI module */ + trm_reg_write16(DO_RSTMODULE, TRMREG_SCSI_CONTROL); + /* program configuration 0 */ + pACB->Config = HCC_AUTOTERM | HCC_PARITY; + if (trm_reg_read8(TRMREG_GEN_STATUS) & WIDESCSI) + pACB->Config |= HCC_WIDE_CARD; + if (pEEpromBuf->NvramChannelCfg & NAC_POWERON_SCSI_RESET) + pACB->Config |= HCC_SCSI_RESET; + if (pACB->Config & HCC_PARITY) + bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK; + else + bval = PHASELATCH | INITIATOR | BLOCKRST ; + trm_reg_write8(bval,TRMREG_SCSI_CONFIG0); + /* program configuration 1 */ + trm_reg_write8(0x13, TRMREG_SCSI_CONFIG1); + /* program Host ID */ + bval = pEEpromBuf->NvramScsiId; + trm_reg_write8(bval, TRMREG_SCSI_HOSTID); + /* set ansynchronous transfer */ + trm_reg_write8(0x00, TRMREG_SCSI_OFFSET); + /* Trun LED control off*/ + wval = trm_reg_read16(TRMREG_GEN_CONTROL) & 0x7F; + trm_reg_write16(wval, TRMREG_GEN_CONTROL); + /* DMA config */ + wval = trm_reg_read16(TRMREG_DMA_CONFIG) | DMA_ENHANCE; + trm_reg_write16(wval, TRMREG_DMA_CONFIG); + /* Clear pending interrupt status */ + trm_reg_read8(TRMREG_SCSI_INTSTATUS); + /* Enable SCSI interrupt */ + trm_reg_write8(0x7F, TRMREG_SCSI_INTEN); + trm_reg_write8(EN_SCSIINTR, TRMREG_DMA_INTEN); + return (0); +} + +static void +trm_mapSRB(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + PACB pACB; + + pACB = (PACB)arg; + pACB->srb_physbase = segs->ds_addr; +} + +static void +trm_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *baddr; + + baddr = (bus_addr_t *)arg; + *baddr = segs->ds_addr; +} + +static PACB +trm_init(u_int16_t unit, device_t dev) +{ + PACB pACB; + int rid = PCIR_MAPS, i = 0, j = 0; + u_int16_t adaptType = 0; + + pACB = (PACB) device_get_softc(dev); + if (!pACB) { + printf("trm%d: cannot allocate ACB !\n", unit); + return (NULL); + } + bzero (pACB, sizeof (struct _ACB)); + pACB->iores = bus_alloc_resource(dev, SYS_RES_IOPORT, + &rid, 0, ~0, 1, RF_ACTIVE); + if (pACB->iores == NULL) { + printf("trm_init: bus_alloc_resource failed!\n"); + return (NULL); + } + switch (pci_get_devid(dev)) { + case PCI_DEVICEID_TRMS1040: + adaptType = 0; + break; + case PCI_DEVICEID_TRMS2080: + adaptType = 1; + break; + default: + printf("trm_init %d: unknown adapter type!\n", unit); + goto bad; + } + pACB->dev = dev; + pACB->tag = rman_get_bustag(pACB->iores); + pACB->bsh = rman_get_bushandle(pACB->iores); + if (bus_dma_tag_create(/*parent_dmat*/ pACB->parent_dmat, + /*alignment*/ 1, + /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/ NULL, + /*filterarg*/ NULL, + /*maxsize*/ MAXBSIZE, + /*nsegments*/ TRM_NSEG, + /*maxsegsz*/ TRM_MAXTRANSFER_SIZE, + /*flags*/ BUS_DMA_ALLOCNOW, + &pACB->buffer_dmat) != 0) + goto bad; + /* DMA tag for our ccb structures */ + if(bus_dma_tag_create( + /*parent_dmat*/pACB->parent_dmat, + /*alignment*/ 1, + /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/ NULL, + /*filterarg*/ NULL, + /*maxsize*/ TRM_MAX_SRB_CNT * sizeof(TRM_SRB), + /*nsegments*/ 1, + /*maxsegsz*/ TRM_MAXTRANSFER_SIZE, + /*flags*/ 0, + /*dmat*/ &pACB->srb_dmat) != 0) { + printf("trm_init %d: bus_dma_tag_create SRB failure\n", unit); + goto bad; + } + if (bus_dmamem_alloc(pACB->srb_dmat, (void **)&pACB->pFreeSRB, + BUS_DMA_NOWAIT, &pACB->srb_dmamap) != 0) { + printf("trm_init %d: bus_dmamem_alloc SRB failure\n", unit); + goto bad; + } + bus_dmamap_load(pACB->srb_dmat, pACB->srb_dmamap, pACB->pFreeSRB, + TRM_MAX_SRB_CNT * sizeof(TRM_SRB), trm_mapSRB, pACB, + /* flags */0); + /* Create, allocate, and map DMA buffers for autosense data */ + if (bus_dma_tag_create(/*parent_dmat*/NULL, /*alignment*/1, + /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + sizeof(struct scsi_sense_data) * TRM_MAX_SRB_CNT, + /*nsegments*/1, + /*maxsegsz*/TRM_MAXTRANSFER_SIZE, + /*flags*/0, &pACB->sense_dmat) != 0) { + if (bootverbose) + device_printf(dev, "cannot create sense buffer dmat\n"); + goto bad; + } + + if (bus_dmamem_alloc(pACB->sense_dmat, (void **)&pACB->sense_buffers, + BUS_DMA_NOWAIT, &pACB->sense_dmamap) != 0) + goto bad; + + bus_dmamap_load(pACB->sense_dmat, pACB->sense_dmamap, + pACB->sense_buffers, + sizeof(struct scsi_sense_data) * TRM_MAX_SRB_CNT, + trm_dmamap_cb, &pACB->sense_busaddr, /*flags*/0); + + trm_check_eeprom(&trm_eepromBuf[unit],pACB); + trm_initACB(pACB, adaptType, unit); + for (i = 0; i < (pACB->max_id + 1); i++) { + if (pACB->AdaptSCSIID == i) + continue; + for(j = 0; j < (pACB->max_lun + 1); j++) { + pACB->scan_devices[i][j] = 1; + /* we assume we need to scan all devices */ + trm_initDCB(pACB, &pACB->DCBarray[i][j], unit, i, j); + } + } + bzero(pACB->pFreeSRB, TRM_MAX_SRB_CNT * sizeof(TRM_SRB)); + if (trm_initSRB(pACB)) { + printf("trm_initSRB: error\n"); + goto bad; + } + if (trm_initAdapter(pACB, unit)) { + printf("trm_initAdapter: initial ERROR\n"); + goto bad; + } + return (pACB); +bad: + if (pACB->iores) + bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS, + pACB->iores); + if (pACB->sense_dmamap) { + bus_dmamap_unload(pACB->sense_dmat, pACB->sense_dmamap); + bus_dmamem_free(pACB->sense_dmat, pACB->sense_buffers, + pACB->sense_dmamap); + bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap); + } + if (pACB->sense_dmat) + bus_dma_tag_destroy(pACB->sense_dmat); + if (pACB->srb_dmamap) { + bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap); + bus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB, + pACB->srb_dmamap); + bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap); + } + if (pACB->srb_dmat) + bus_dma_tag_destroy(pACB->srb_dmat); + if (pACB->buffer_dmat) + bus_dma_tag_destroy(pACB->buffer_dmat); + return (NULL); +} + +static int +trm_attach(device_t dev) +{ + struct cam_devq *device_Q; + u_long device_id; + PACB pACB = 0; + int rid = 0; + int unit = device_get_unit(dev); + + device_id = pci_get_devid(dev); + /* + * These cards do not allow memory mapped accesses + */ + if ((pACB = trm_init((u_int16_t) unit, + dev)) == NULL) { + printf("trm%d: trm_init error!\n",unit); + return (ENXIO); + } + /* After setting up the adapter, map our interrupt */ + /* + * Now let the CAM generic SCSI layer find the SCSI devices on the bus + * start queue to reset to the idle loop. + * Create device queue of SIM(s) + * (MAX_START_JOB - 1) : max_sim_transactions + */ + pACB->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, + ~0, 1, RF_SHAREABLE | RF_ACTIVE); + if (pACB->irq == NULL || + bus_setup_intr(dev, pACB->irq, + INTR_TYPE_CAM, trm_Interrupt, pACB, &pACB->ih)) { + printf("trm%d: register Interrupt handler error!\n", unit); + goto bad; + } + device_Q = cam_simq_alloc(TRM_MAX_START_JOB); + if (device_Q == NULL){ + printf("trm%d: device_Q == NULL !\n",unit); + goto bad; + } + /* + * Now tell the generic SCSI layer + * about our bus. + * If this is the xpt layer creating a sim, then it's OK + * to wait for an allocation. + * XXX Should we pass in a flag to indicate that wait is OK? + * + * SIM allocation + * + * SCSI Interface Modules + * The sim driver creates a sim for each controller. The sim device + * queue is separately created in order to allow resource sharing betwee + * sims. For instance, a driver may create one sim for each channel of + * a multi-channel controller and use the same queue for each channel. + * In this way, the queue resources are shared across all the channels + * of the multi-channel controller. + * trm_action : sim_action_func + * trm_poll : sim_poll_func + * "trm" : sim_name ,if sim_name = "xpt" ..M_DEVBUF,M_WAITOK + * pACB : *softc if sim_name <> "xpt" ..M_DEVBUF,M_NOWAIT + * pACB->unit : unit + * 1 : max_dev_transactions + * MAX_TAGS : max_tagged_dev_transactions + * + * *******Construct our first channel SIM entry + */ + pACB->psim = cam_sim_alloc(trm_action, + trm_poll, + "trm", + pACB, + unit, + 1, + TRM_MAX_TAGS_CMD_QUEUE, + device_Q); + if (pACB->psim == NULL) { + printf("trm%d: SIM allocate fault !\n",unit); + cam_simq_free(device_Q); /* SIM allocate fault*/ + goto bad; + } + if (xpt_bus_register(pACB->psim, 0) != CAM_SUCCESS) { + printf("trm%d: xpt_bus_register fault !\n",unit); + goto bad; + } + if (xpt_create_path(&pACB->ppath, + NULL, + cam_sim_path(pACB->psim), + CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + printf("trm%d: xpt_create_path fault !\n",unit); + xpt_bus_deregister(cam_sim_path(pACB->psim)); + goto bad; + } + return (0); +bad: + if (pACB->iores) + bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS, + pACB->iores); + if (pACB->srb_dmamap) { + bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap); + bus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB, + pACB->srb_dmamap); + bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap); + } + if (pACB->srb_dmat) + bus_dma_tag_destroy(pACB->srb_dmat); + if (pACB->sense_dmamap) { + bus_dmamap_unload(pACB->sense_dmat, pACB->sense_dmamap); + bus_dmamem_free(pACB->sense_dmat, pACB->sense_buffers, + pACB->sense_dmamap); + bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap); + } + if (pACB->sense_dmat) + bus_dma_tag_destroy(pACB->sense_dmat); + if (pACB->buffer_dmat) + bus_dma_tag_destroy(pACB->buffer_dmat); + if (pACB->ih) + bus_teardown_intr(dev, pACB->irq, pACB->ih); + if (pACB->irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irq); + if (pACB->psim) + cam_sim_free(pACB->psim, TRUE); + + return (ENXIO); + +} + +/* +* pci_device +* trm_probe (device_t tag, pcidi_t type) +* +*/ +static int +trm_probe(device_t dev) +{ + switch (pci_get_devid(dev)) { + case PCI_DEVICEID_TRMS1040: + device_set_desc(dev, + "Tekram DC395U/UW/F DC315/U Fast20 Wide SCSI Adapter"); + return (0); + case PCI_DEVICEID_TRMS2080: + device_set_desc(dev, + "Tekram DC395U2D/U2W Fast40 Wide SCSI Adapter"); + return 0; + default: + return (ENXIO); + } +} + +static int +trm_detach(device_t dev) +{ + PACB pACB = device_get_softc(dev); + + bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS, pACB->iores); + bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap); + bus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB, + pACB->srb_dmamap); + bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap); + bus_dma_tag_destroy(pACB->srb_dmat); + bus_dmamap_unload(pACB->sense_dmat, pACB->sense_dmamap); + bus_dmamem_free(pACB->sense_dmat, pACB->sense_buffers, + pACB->sense_dmamap); + bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap); + bus_dma_tag_destroy(pACB->sense_dmat); + bus_dma_tag_destroy(pACB->buffer_dmat); + bus_teardown_intr(dev, pACB->irq, pACB->ih); + bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irq); + xpt_async(AC_LOST_DEVICE, pACB->ppath, NULL); + xpt_free_path(pACB->ppath); + xpt_bus_deregister(cam_sim_path(pACB->psim)); + cam_sim_free(pACB->psim, TRUE); + return (0); +} +static device_method_t trm_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, trm_probe), + DEVMETHOD(device_attach, trm_attach), + DEVMETHOD(device_detach, trm_detach), + { 0, 0 } +}; + +static driver_t trm_driver = { + "trm", trm_methods, sizeof(struct _ACB) +}; + +static devclass_t trm_devclass; +DRIVER_MODULE(trm, pci, trm_driver, trm_devclass, 0, 0); |