diff options
-rw-r--r-- | sys/pci/scsiiom.c | 1493 | ||||
-rw-r--r-- | sys/pci/tek390.c | 1679 | ||||
-rw-r--r-- | sys/pci/tek390.h | 667 |
3 files changed, 3839 insertions, 0 deletions
diff --git a/sys/pci/scsiiom.c b/sys/pci/scsiiom.c new file mode 100644 index 0000000..29fdb2d --- /dev/null +++ b/sys/pci/scsiiom.c @@ -0,0 +1,1493 @@ +/*********************************************************************** + * FILE NAME : SCSIIOM.C * + * BY : C.L. Huang (ching@tekram.com.tw) * + * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * + * Bus Master Host Adapter * + ***********************************************************************/ + + +static USHORT +DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + USHORT ioport, rc; + UCHAR bval, bval1, i, cnt; + PUCHAR ptr; + ULONG wlval; + + pSRB->TagNumber = 31; + ioport = pACB->IOPortBase; + bval = pDCB->UnitSCSIID; + OutB(bval,ioport+Scsi_Dest_ID); + bval = pDCB->SyncPeriod; + OutB(bval,ioport+Sync_Period); + bval = pDCB->SyncOffset; + OutB(bval,ioport+Sync_Offset); + bval = pDCB->CtrlR1; + OutB(bval,ioport+CtrlReg1); + bval = pDCB->CtrlR3; + OutB(bval,ioport+CtrlReg3); + bval = pDCB->CtrlR4; + OutB(bval,ioport+CtrlReg4); + bval = CLEAR_FIFO_CMD; /* Flush FIFO */ + OutB(bval,ioport+ScsiCmd); + + pSRB->ScsiPhase = SCSI_NOP0; + bval = pDCB->IdentifyMsg; + if( !(pDCB->SyncMode & EN_ATN_STOP) ) + { + if( (pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE) ) + { + bval &= 0xBF; /* NO disconnection */ + OutB(bval,ioport+ScsiFifo); + bval1 = SELECT_W_ATN; + pSRB->SRBState = SRB_START_; + if( pDCB->SyncMode & SYNC_ENABLE ) + { + if( !(pDCB->IdentifyMsg & 7) || + (pSRB->CmdBlock[0] != INQUIRY) ) + { + bval1 = SEL_W_ATN_STOP; + pSRB->SRBState = SRB_MSGOUT; + } + } + } + else + { + if(pDCB->SyncMode & EN_TAG_QUEUING) + { + OutB(bval,ioport+ScsiFifo); + bval = MSG_SIMPLE_QTAG; + OutB(bval,ioport+ScsiFifo); + wlval = 1; + bval = 0; + while( wlval & pDCB->TagMask ) + { + wlval = wlval << 1; + bval++; + } + OutB(bval,ioport+ScsiFifo); + pDCB->TagMask |= wlval; + pSRB->TagNumber = bval; + bval1 = SEL_W_ATN2; + pSRB->SRBState = SRB_START_; + } + else + { + OutB(bval,ioport+ScsiFifo); + bval1 = SELECT_W_ATN; + pSRB->SRBState = SRB_START_; + } + } + + if( pSRB->SRBFlag & AUTO_REQSENSE ) + { + bval = REQUEST_SENSE; + OutB(bval,ioport+ScsiFifo); + bval = pDCB->IdentifyMsg << 5; + OutB(bval,ioport+ScsiFifo); + bval = 0; + OutB(bval,ioport+ScsiFifo); + OutB(bval,ioport+ScsiFifo); + bval = sizeof(struct scsi_sense_data); + OutB(bval,ioport+ScsiFifo); + bval = 0; + OutB(bval,ioport+ScsiFifo); + } + else + { + cnt = pSRB->ScsiCmdLen; + ptr = (PUCHAR) pSRB->CmdBlock; + for(i=0; i<cnt; i++) + { + bval = *ptr++; + OutB(bval,ioport+ScsiFifo); + } + } + } + else /* ATN_STOP */ + { + if( (pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE) ) + { + bval &= 0xBF; + OutB(bval,ioport+ScsiFifo); + bval1 = SELECT_W_ATN; + pSRB->SRBState = SRB_START_; + if( pDCB->SyncMode & SYNC_ENABLE ) + { + if( !(pDCB->IdentifyMsg & 7) || + (pSRB->CmdBlock[0] != INQUIRY) ) + { + bval1 = SEL_W_ATN_STOP; + pSRB->SRBState = SRB_MSGOUT; + } + } + } + else + { + if(pDCB->SyncMode & EN_TAG_QUEUING) + { + OutB(bval,ioport+ScsiFifo); + pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; + wlval = 1; + bval = 0; + while( wlval & pDCB->TagMask ) + { + wlval = wlval << 1; + bval++; + } + pDCB->TagMask |= wlval; + pSRB->TagNumber = bval; + pSRB->MsgOutBuf[1] = bval; + pSRB->MsgCnt = 2; + bval1 = SEL_W_ATN_STOP; + pSRB->SRBState = SRB_START_; + } + else + { + OutB(bval,ioport+ScsiFifo); + pSRB->MsgOutBuf[0] = MSG_NOP; + pSRB->MsgCnt = 1; + pSRB->SRBState = SRB_START_; + bval1 = SEL_W_ATN_STOP; + } + } + } + bval = inb( ioport+Scsi_Status ); + if( bval & INTERRUPT ) + { + pSRB->SRBState = SRB_READY; + pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); + rc = 1; + } + else + { + pSRB->ScsiPhase = SCSI_NOP1; + pACB->pActiveDCB = pDCB; + pDCB->pActiveSRB = pSRB; + rc = 0; + OutB(bval1,ioport+ScsiCmd); + } + return( rc ); +} + + +#ifdef REL_2_1_0 +static int DC390_Interrupt( PACB pACB ) +#endif +#ifdef REL_2_1_5 +static void DC390_Interrupt( PACB pACB ) +#endif +{ + PDCB pDCB; + PSRB pSRB; + USHORT ioport = 0; + USHORT phase; + void (*stateV)( PACB, PSRB, PUCHAR ); + UCHAR istate = 0; + UCHAR sstatus=0, istatus; + + if( pACB == NULL ) +#ifdef REL_2_1_0 + return 0; +#endif +#ifdef REL_2_1_5 + return; +#endif + ioport = pACB->IOPortBase; + sstatus = inb( ioport+Scsi_Status ); + if( !(sstatus & INTERRUPT) ) +#ifdef REL_2_1_0 + return 0; +#endif +#ifdef REL_2_1_5 + return; +#endif + +#ifdef DC390_DEBUG1 + printf("sstatus=%2x,",sstatus); +#endif + + istate = inb( ioport+Intern_State ); + istatus = inb( ioport+INT_Status ); + +#ifdef DC390_DEBUG1 + printf("Istatus=%2x,",istatus); +#endif + + if(istatus & DISCONNECTED) + { + DC390_Disconnect( pACB ); +#ifdef REL_2_1_0 + return 1; +#endif +#ifdef REL_2_1_5 + return; +#endif + } + + if(istatus & RESELECTED) + { + DC390_Reselect( pACB ); +#ifdef REL_2_1_0 + return 1; +#endif +#ifdef REL_2_1_5 + return; +#endif + } + + if(istatus & INVALID_CMD) + { + DC390_InvalidCmd( pACB ); +#ifdef REL_2_1_0 + return 1; +#endif +#ifdef REL_2_1_5 + return; +#endif + } + + if(istatus & SCSI_RESET_) + { + DC390_ScsiRstDetect( pACB ); +#ifdef REL_2_1_0 + return 1; +#endif +#ifdef REL_2_1_5 + return; +#endif + } + + if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) ) + { + pDCB = pACB->pActiveDCB; + pSRB = pDCB->pActiveSRB; + if( pDCB ) + { + if( pDCB->DCBFlag & ABORT_DEV_ ) + EnableMsgOut( pACB, pSRB ); + } + + phase = (USHORT) pSRB->ScsiPhase; + stateV = (void *) DC390_phase0[phase]; + stateV( pACB, pSRB, &sstatus ); + + pSRB->ScsiPhase = sstatus & 7; + phase = (USHORT) sstatus & 7; + stateV = (void *) DC390_phase1[phase]; + stateV( pACB, pSRB, &sstatus ); + } +#ifdef REL_2_1_0 + return 1; +#endif +} + + +static void +DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR sstatus, bval; + USHORT ioport; + PSEG psgl; + ULONG ResidCnt, xferCnt; + + ioport = pACB->IOPortBase; + sstatus = *psstatus; + + if( !(pSRB->SRBState & SRB_XFERPAD) ) + { + if( sstatus & PARITY_ERR ) + pSRB->SRBStatus |= PARITY_ERROR; + + if( sstatus & COUNT_2_ZERO ) + { + bval = inb(ioport+DMA_Status); + while( !(bval & DMA_XFER_DONE) ) + bval = inb(ioport+DMA_Status); + pSRB->TotalXferredLen += pSRB->SGToBeXferLen; + pSRB->SGIndex++; + if( pSRB->SGIndex < pSRB->SGcount ) + { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + pSRB->SGPhysAddr = psgl->SGXPtr; + pSRB->SGToBeXferLen = psgl->SGXLen; + } + else + pSRB->SGToBeXferLen = 0; + } + else + { + bval = inb( ioport+Current_Fifo ); + bval &= 0x1f; + ResidCnt = (ULONG) inb(ioport+CtcReg_High); + ResidCnt = ResidCnt << 8; + ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid); + ResidCnt = ResidCnt << 8; + ResidCnt |= (ULONG) inb(ioport+CtcReg_Low); + ResidCnt += (ULONG) bval; + + xferCnt = pSRB->SGToBeXferLen - ResidCnt; + pSRB->SGPhysAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = ResidCnt; + } + } + bval = WRITE_DIRECTION+DMA_IDLE_CMD; + OutB( bval, ioport+DMA_Cmd); +} + +static void +DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR sstatus, bval; + USHORT i, ioport, residual; + PSEG psgl; + ULONG ResidCnt, xferCnt; + PUCHAR ptr; + + + ioport = pACB->IOPortBase; + sstatus = *psstatus; + + if( !(pSRB->SRBState & SRB_XFERPAD) ) + { + if( sstatus & PARITY_ERR ) + pSRB->SRBStatus |= PARITY_ERROR; + + if( sstatus & COUNT_2_ZERO ) + { + bval = inb(ioport+DMA_Status); + while( !(bval & DMA_XFER_DONE) ) + bval = inb(ioport+DMA_Status); + + bval = READ_DIRECTION+DMA_IDLE_CMD; + OutB( bval, ioport+DMA_Cmd); + + pSRB->TotalXferredLen += pSRB->SGToBeXferLen; + pSRB->SGIndex++; + if( pSRB->SGIndex < pSRB->SGcount ) + { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + pSRB->SGPhysAddr = psgl->SGXPtr; + pSRB->SGToBeXferLen = psgl->SGXLen; + } + else + pSRB->SGToBeXferLen = 0; + } + else /* phase changed */ + { + residual = 0; + bval = inb(ioport+Current_Fifo); + while( bval & 0x1f ) + { + if( (bval & 0x1f) == 1 ) + { + for(i=0; i< 0x100; i++) + { + bval = inb(ioport+Current_Fifo); + if( !(bval & 0x1f) ) + goto din_1; + else if( i == 0x0ff ) + { + residual = 1; /* ;1 residual byte */ + goto din_1; + } + } + } + else + bval = inb(ioport+Current_Fifo); + } +din_1: + bval = READ_DIRECTION+DMA_BLAST_CMD; + OutB(bval, ioport+DMA_Cmd); + for(i=0; i<0x8000; i++) + { + bval = inb(ioport+DMA_Status); + if(bval & BLAST_COMPLETE) + break; + } + bval = READ_DIRECTION+DMA_IDLE_CMD; + OutB(bval, ioport+DMA_Cmd); + + ResidCnt = (ULONG) inb(ioport+CtcReg_High); + ResidCnt = ResidCnt << 8; + ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid); + ResidCnt = ResidCnt << 8; + ResidCnt |= (ULONG) inb(ioport+CtcReg_Low); + + xferCnt = pSRB->SGToBeXferLen - ResidCnt; + pSRB->SGPhysAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = ResidCnt; + + if( residual ) + { + bval = inb(ioport+ScsiFifo); /* get residual byte */ + ptr = phystovirt( pSRB, xferCnt); + *ptr = bval; + pSRB->SGPhysAddr++; + pSRB->TotalXferredLen++; + pSRB->SGToBeXferLen--; + } + } + } +} + +static void +DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ +} + +static void +DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR bval; + USHORT ioport; + + ioport = pACB->IOPortBase; + bval = inb(ioport+ScsiFifo); + pSRB->TargetStatus = bval; + bval++; + bval = inb(ioport+ScsiFifo); /* get message */ + pSRB->EndMessage = bval; + + *psstatus = SCSI_NOP0; + pSRB->SRBState = SRB_COMPLETED; + bval = MSG_ACCEPTED_CMD; + OutB(bval, ioport+ScsiCmd); +} + +static void +DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) + *psstatus = SCSI_NOP0; +} + +static void +DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR bval; + USHORT ioport, wval, wval1; + PDCB pDCB; + PSRB psrb; + + ioport = pACB->IOPortBase; + pDCB = pACB->pActiveDCB; + + bval = inb( ioport+ScsiFifo ); + if( !(pSRB->SRBState & SRB_MSGIN_MULTI) ) + { + if(bval == MSG_DISCONNECT) + { + pSRB->SRBState = SRB_DISCONNECT; + } + else if( bval == MSG_SAVE_PTR ) + goto min6; + else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) && + (bval <= MSG_ORDER_QTAG)) ) + { + pSRB->SRBState |= SRB_MSGIN_MULTI; + pSRB->MsgInBuf[0] = bval; + pSRB->MsgCnt = 1; + pSRB->pMsgPtr = &pSRB->MsgInBuf[1]; + } + else if(bval == MSG_REJECT_) + { + bval = RESET_ATN_CMD; + OutB(bval, ioport+ScsiCmd); + if( pSRB->SRBState & DO_SYNC_NEGO) + goto set_async; + } + else if( bval == MSG_RESTORE_PTR) + goto min6; + else + goto min6; + } + else + { /* minx: */ + + *pSRB->pMsgPtr = bval; + pSRB->MsgCnt++; + pSRB->pMsgPtr++; + if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) && + (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) ) + { + if( pSRB->MsgCnt == 2) + { + pSRB->SRBState = 0; + bval = pSRB->MsgInBuf[1]; + pSRB = pDCB->pGoingSRB; + psrb = pDCB->pGoingLast; + if( pSRB ) + { + for( ;; ) + { + if(pSRB->TagNumber != bval) + { + if( pSRB == psrb ) + goto mingx0; + pSRB = pSRB->pNextSRB; + } + else + break; + } + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + pSRB->SRBState = SRB_ABORT_SENT; + EnableMsgOut( pACB, pSRB ); + } + if( !(pSRB->SRBState & SRB_DISCONNECT) ) + goto mingx0; + pDCB->pActiveSRB = pSRB; + pSRB->SRBState = SRB_DATA_XFER; + } + else + { +mingx0: + pSRB = pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + EnableMsgOut2( pACB, pSRB ); + } + } + } + else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) ) + { + pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO); + if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) ) + { /* reject_msg: */ + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + bval = SET_ATN_CMD; + OutB(bval, ioport+ScsiCmd); + } + else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) ) + { +set_async: + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->CtrlR3 = FAST_CLK; /* ;non_fast */ + pDCB->CtrlR4 &= 0x3f; + pDCB->CtrlR4 |= EATER_25NS; /* ; 25ns glitch eater */ + goto re_prog; + } + else + { /* set_sync: */ + + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE; + pDCB->SyncOffset &= 0x0f0; + pDCB->SyncOffset |= pSRB->MsgInBuf[4]; + pDCB->NegoPeriod = pSRB->MsgInBuf[3]; + wval = (USHORT) pSRB->MsgInBuf[3]; + wval = wval << 2; + wval--; + wval1 = wval / 25; + if( (wval1 * 25) != wval) + wval1++; + bval = FAST_CLK+FAST_SCSI; + pDCB->CtrlR4 &= 0x3f; + if(wval1 >= 8) + { + wval1--; + bval = FAST_CLK; /* ;fast clock/normal scsi */ + pDCB->CtrlR4 |= EATER_25NS; /* ;25 ns glitch eater */ + } + pDCB->CtrlR3 = bval; + pDCB->SyncPeriod = (UCHAR)wval1; +re_prog: + bval = pDCB->SyncPeriod; + OutB(bval, ioport+Sync_Period); + bval = pDCB->SyncOffset; + OutB(bval, ioport+Sync_Offset); + bval = pDCB->CtrlR3; + OutB(bval, ioport+CtrlReg3); + bval = pDCB->CtrlR4; + OutB(bval, ioport+CtrlReg4); + SetXferRate( pACB, pDCB); + } + } + } +min6: + *psstatus = SCSI_NOP0; + bval = MSG_ACCEPTED_CMD; + OutB(bval, ioport+ScsiCmd); +} + +static void +DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) +{ + PSEG psgl; + UCHAR bval; + USHORT ioport; + ULONG lval; + + + ioport = pACB->IOPortBase; + if( pSRB->SGIndex < pSRB->SGcount ) + { + bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */ + OutB( bval, ioport+DMA_Cmd); + if( !pSRB->SGToBeXferLen ) + { + psgl = pSRB->pSegmentList; + pSRB->SGPhysAddr = psgl->SGXPtr; + pSRB->SGToBeXferLen = psgl->SGXLen; + } + lval = pSRB->SGToBeXferLen; + bval = (UCHAR) lval; + OutB(bval,ioport+CtcReg_Low); + lval = lval >> 8; + bval = (UCHAR) lval; + OutB(bval,ioport+CtcReg_Mid); + lval = lval >> 8; + bval = (UCHAR) lval; + OutB(bval,ioport+CtcReg_High); + + lval = pSRB->SGToBeXferLen; + OutL(lval, ioport+DMA_XferCnt); + + lval = pSRB->SGPhysAddr; + OutL( lval, ioport+DMA_XferAddr); + + pSRB->SRBState = SRB_DATA_XFER; + + bval = DMA_COMMAND+INFO_XFER_CMD; + OutB(bval, ioport+ScsiCmd); + + bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */ + OutB(bval, ioport+DMA_Cmd); + + bval = DMA_START_CMD | ioDir; /* ;+EN_DMA_INT */ + OutB(bval, ioport+DMA_Cmd); + } + else /* xfer pad */ + { + if( pSRB->SGcount ) + { + pSRB->AdaptStatus = H_OVER_UNDER_RUN; + pSRB->SRBStatus |= OVER_RUN; + } + bval = 0; + OutB(bval,ioport+CtcReg_Low); + OutB(bval,ioport+CtcReg_Mid); + OutB(bval,ioport+CtcReg_High); + + pSRB->SRBState |= SRB_XFERPAD; + bval = DMA_COMMAND+XFER_PAD_BYTE; + OutB(bval, ioport+ScsiCmd); +/* + bval = DMA_IDLE_CMD | ioDir; ;+EN_DMA_INT + OutB(bval, ioport+DMA_Cmd); + bval = DMA_START_CMD | ioDir; ;+EN_DMA_INT + OutB(bval, ioport+DMA_Cmd); +*/ + } +} + + +static void +DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR ioDir; + + ioDir = WRITE_DIRECTION; + DataIO_Comm( pACB, pSRB, ioDir); +} + +static void +DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR ioDir; + + ioDir = READ_DIRECTION; + DataIO_Comm( pACB, pSRB, ioDir); +} + +static void +DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + PDCB pDCB; + UCHAR bval; + PUCHAR ptr; + USHORT ioport, i, cnt; + + + ioport = pACB->IOPortBase; + bval = RESET_ATN_CMD; + OutB(bval, ioport+ScsiCmd); + bval = CLEAR_FIFO_CMD; + OutB(bval, ioport+ScsiCmd); + if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) + { + cnt = (USHORT) pSRB->ScsiCmdLen; + ptr = (PUCHAR) pSRB->CmdBlock; + for(i=0; i < cnt; i++) + { + OutB(*ptr, ioport+ScsiFifo); + ptr++; + } + } + else + { + bval = REQUEST_SENSE; + OutB(bval, ioport+ScsiFifo); + pDCB = pACB->pActiveDCB; + bval = pDCB->IdentifyMsg << 5; + OutB(bval, ioport+ScsiFifo); + bval = 0; + OutB(bval, ioport+ScsiFifo); + OutB(bval, ioport+ScsiFifo); + bval = sizeof(struct scsi_sense_data); + OutB(bval, ioport+ScsiFifo); + bval = 0; + OutB(bval, ioport+ScsiFifo); + } + pSRB->SRBState = SRB_COMMAND; + bval = INFO_XFER_CMD; + OutB(bval, ioport+ScsiCmd); +} + +static void +DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR bval; + USHORT ioport; + + ioport = pACB->IOPortBase; + bval = CLEAR_FIFO_CMD; + OutB(bval, ioport+ScsiCmd); + pSRB->SRBState = SRB_STATUS; + bval = INITIATOR_CMD_CMPLTE; + OutB(bval, ioport+ScsiCmd); +} + +static void +DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR bval; + USHORT ioport, i, cnt; + PUCHAR ptr; + PDCB pDCB; + + ioport = pACB->IOPortBase; + bval = CLEAR_FIFO_CMD; + OutB(bval, ioport+ScsiCmd); + pDCB = pACB->pActiveDCB; + if( !(pSRB->SRBState & SRB_MSGOUT) ) + { + cnt = pSRB->MsgCnt; + if( cnt ) + { + ptr = (PUCHAR) pSRB->MsgOutBuf; + for(i=0; i < cnt; i++) + { + OutB(*ptr, ioport+ScsiFifo); + ptr++; + } + pSRB->MsgCnt = 0; + if( (pDCB->DCBFlag & ABORT_DEV_) && + (pSRB->MsgOutBuf[0] == MSG_ABORT) ) + pSRB->SRBState = SRB_ABORT_SENT; + } + else + { + bval = MSG_ABORT; /* ??? MSG_NOP */ + if( (pSRB->CmdBlock[0] == INQUIRY ) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE) ) + { + if( pDCB->SyncMode & SYNC_ENABLE ) + goto mop1; + } + OutB(bval, ioport+ScsiFifo); + } + bval = INFO_XFER_CMD; + OutB( bval, ioport+ScsiCmd); + } + else + { +mop1: + bval = MSG_EXTENDED; + OutB(bval, ioport+ScsiFifo); + bval = 3; /* ;length of extended msg */ + OutB(bval, ioport+ScsiFifo); + bval = 1; /* ; sync nego */ + OutB(bval, ioport+ScsiFifo); + bval = pDCB->NegoPeriod; + OutB(bval, ioport+ScsiFifo); + bval = SYNC_NEGO_OFFSET; + OutB(bval, ioport+ScsiFifo); + pSRB->SRBState |= DO_SYNC_NEGO; + bval = INFO_XFER_CMD; + OutB(bval, ioport+ScsiCmd); + } +} + +static void +DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR bval; + USHORT ioport; + + ioport = pACB->IOPortBase; + bval = CLEAR_FIFO_CMD; + OutB(bval, ioport+ScsiCmd); + if( !(pSRB->SRBState & SRB_MSGIN) ) + { + pSRB->SRBState &= SRB_DISCONNECT; + pSRB->SRBState |= SRB_MSGIN; + } + bval = INFO_XFER_CMD; + OutB(bval, ioport+ScsiCmd); +} + +static void +DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ +} + +static void +DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ +} + + +static void +SetXferRate( PACB pACB, PDCB pDCB ) +{ + UCHAR bval; + USHORT cnt, i; + PDCB ptr; + + if( !(pDCB->IdentifyMsg & 0x07) ) + { + if( pACB->scan_devices ) + { + CurrSyncOffset = pDCB->SyncOffset; + } + else + { + ptr = pACB->pLinkDCB; + cnt = pACB->DeviceCnt; + bval = pDCB->UnitSCSIID; + for(i=0; i<cnt; i++) + { + if( ptr->UnitSCSIID == bval ) + { + ptr->SyncPeriod = pDCB->SyncPeriod; + ptr->SyncOffset = pDCB->SyncOffset; + ptr->CtrlR3 = pDCB->CtrlR3; + ptr->CtrlR4 = pDCB->CtrlR4; + ptr->SyncMode = pDCB->SyncMode; + } + ptr = ptr->pNextDCB; + } + } + } + return; +} + + +static void +DC390_Disconnect( PACB pACB ) +{ + PDCB pDCB; + PSRB pSRB, psrb; + int flags; + USHORT ioport, i, cnt; + UCHAR bval; + +#ifdef DC390_DEBUG0 + printf("DISC,"); +#endif + + flags = splbio(); + ioport = pACB->IOPortBase; + pDCB = pACB->pActiveDCB; + pSRB = pDCB->pActiveSRB; + pACB->pActiveDCB = 0; + pSRB->ScsiPhase = SCSI_NOP0; + bval = EN_SEL_RESEL; + OutB(bval, ioport+ScsiCmd); + if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) + { + pSRB->SRBState = 0; + DoWaitingSRB( pACB ); + } + else if( pSRB->SRBState & SRB_ABORT_SENT ) + { + pDCB->TagMask = 0; + pDCB->DCBFlag = 0; + cnt = pDCB->GoingSRBCnt; + pDCB->GoingSRBCnt = 0; + pSRB = pDCB->pGoingSRB; + for( i=0; i < cnt; i++) + { + psrb = pSRB->pNextSRB; + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pSRB = psrb; + } + pDCB->pGoingSRB = 0; + DoWaitingSRB( pACB ); + } + else + { + if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || + !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) + { /* Selection time out */ + if( !(pACB->scan_devices) ) + { + pSRB->SRBState = SRB_READY; + RewaitSRB( pDCB, pSRB); + } + else + { + pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; + goto disc1; + } + } + else if( pSRB->SRBState & SRB_DISCONNECT ) + { + DoWaitingSRB( pACB ); + } + else if( pSRB->SRBState & SRB_COMPLETED ) + { +disc1: + if(pDCB->MaxCommand > 1) + { + bval = pSRB->TagNumber; + pDCB->TagMask &= (~(1 << bval)); /* free tag mask */ + } + pDCB->pActiveSRB = 0; + pSRB->SRBState = SRB_FREE; + SRBdone( pACB, pDCB, pSRB); + } + } + splx(flags); + return; +} + + +static void +DC390_Reselect( PACB pACB ) +{ + PDCB pDCB; + PSRB pSRB; + USHORT ioport, wval; + UCHAR bval, bval1; + + +#ifdef DC390_DEBUG0 + printf("RSEL,"); +#endif + ioport = pACB->IOPortBase; + pDCB = pACB->pActiveDCB; + if( pDCB ) + { /* Arbitration lost but Reselection win */ + pSRB = pDCB->pActiveSRB; + if( !( pACB->scan_devices ) ) + { + pSRB->SRBState = SRB_READY; + RewaitSRB( pDCB, pSRB); + } + } + bval = inb(ioport+ScsiFifo); /* get ID */ + bval = bval ^ pACB->HostID_Bit; + wval = 0; + bval1 = 1; + for(;;) + { + if( !(bval & bval1) ) + { + bval1 = bval1 << 1; + wval++; + } + else + break; + } + wval |= ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8; /* get LUN */ + pDCB = pACB->pLinkDCB; + while( wval != *((PUSHORT) &pDCB->UnitSCSIID) ) + pDCB = pDCB->pNextDCB; + pACB->pActiveDCB = pDCB; + if( pDCB->SyncMode & EN_TAG_QUEUING ) + { + pSRB = pACB->pTmpSRB; + pDCB->pActiveSRB = pSRB; + } + else + { + pSRB = pDCB->pActiveSRB; + if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) ) + { + pSRB= pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + EnableMsgOut( pACB, pSRB ); + } + else + { + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + pSRB->SRBState = SRB_ABORT_SENT; + EnableMsgOut( pACB, pSRB ); + } + else + pSRB->SRBState = SRB_DATA_XFER; + } + } + pSRB->ScsiPhase = SCSI_NOP0; + bval = pDCB->UnitSCSIID; + OutB( bval, ioport+Scsi_Dest_ID); + bval = pDCB->SyncPeriod; + OutB(bval, ioport+Sync_Period); + bval = pDCB->SyncOffset; + OutB( bval, ioport+Sync_Offset); + bval = pDCB->CtrlR1; + OutB(bval, ioport+CtrlReg1); + bval = pDCB->CtrlR3; + OutB(bval, ioport+CtrlReg3); + bval = pDCB->CtrlR4; /* ; Glitch eater */ + OutB(bval, ioport+CtrlReg4); + bval = MSG_ACCEPTED_CMD; /* ;to rls the /ACK signal */ + OutB(bval, ioport+ScsiCmd); +} + + +static void +SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + PSRB psrb; + UCHAR bval, bval1, i, j, status; + PSCSICMD pcmd; + PSCLINK plink; + PSCSI_INQDATA ptr; + USHORT disable_tag; + int flags; + PSEG ptr2; + ULONG swlval; + + pcmd = pSRB->pcmd; + if( !(pcmd->flags & SCSI_NOMASK) ) + untimeout(DC390_timeout, (caddr_t) pSRB); + plink = pcmd->sc_link; + status = pSRB->TargetStatus; + if(pSRB->SRBFlag & AUTO_REQSENSE) + { + pSRB->SRBFlag &= ~AUTO_REQSENSE; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = SCSI_STAT_CHECKCOND; + if(status == SCSI_STAT_CHECKCOND) + { + pcmd->error = XS_TIMEOUT; + goto ckc_e; + } + + if(pSRB->RetryCnt == 0) + { + *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + pSRB->TotalXferredLen = pSRB->Segment1[1]; + if( pSRB->TotalXferredLen ) + { + pcmd->resid = pcmd->datalen - pSRB->TotalXferredLen; + pcmd->error = XS_SENSE; + pcmd->flags |= SCSI_RESID_VALID; + } + else + { + pcmd->error = XS_SENSE; + pcmd->status = SCSI_STAT_CHECKCOND; + } + goto ckc_e; + } + else + { + pSRB->RetryCnt--; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + { + pcmd->error = XS_SENSE; + pcmd->status = SCSI_STAT_CHECKCOND; + goto ckc_e; + } + pcmd->error = XS_SENSE; + pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; + pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + pSRB->pSegmentList = (PSEG) &pSRB->SGsegment[0]; + pSRB->SGIndex = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) + RewaitSRB( pDCB, pSRB ); + return; + } + } + if( status ) + { + if( status == SCSI_STAT_CHECKCOND) + { + if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) + { + bval = pSRB->SGcount; + swlval = pSRB->SGToBeXferLen; + ptr2 = pSRB->pSegmentList; + ptr2++; + for( i=pSRB->SGIndex+1; i < bval; i++) + { + swlval += ptr2->SGXLen; + ptr2++; + } +#ifdef DC390_DEBUG0 + printf("XferredLen=%8x,NotXferLen=%8x,", + (UINT) pSRB->TotalXferredLen, (UINT) swlval); +#endif + } + RequestSense( pACB, pDCB, pSRB ); + return; + } + else if( status == SCSI_STAT_QUEUEFULL ) + { + bval = (UCHAR) pDCB->GoingSRBCnt; + bval--; + pDCB->MaxCommand = bval; + 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; + pcmd->error = XS_TIMEOUT; + } + else + { + pSRB->AdaptStatus = 0; + if( pSRB->RetryCnt ) + { + pSRB->RetryCnt--; + pSRB->TargetStatus = 0; + pSRB->SGIndex = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + pSRB->pSegmentList = (PSEG) &pSRB->SGsegment[0]; + if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) + RewaitSRB( pDCB, pSRB ); + return; + } + else + { + pcmd->error = XS_DRIVER_STUFFUP; + } + } + } + else + { + status = pSRB->AdaptStatus; + if(status & H_OVER_UNDER_RUN) + { + pSRB->TargetStatus = 0; + pcmd->error = XS_LENGTH; + } + else if( pSRB->SRBStatus & PARITY_ERROR) + { + pcmd->error = XS_DRIVER_STUFFUP; + } + else /* No error */ + { + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pcmd->error = XS_NOERROR; + } + } + +ckc_e: + if( pACB->scan_devices ) + { + if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + { + if(pcmd->error == XS_TIMEOUT ) + { + pACB->DCBmap[plink->target] &= ~(1 << plink->lun); + pPrevDCB->pNextDCB = pACB->pLinkDCB; + } + else + { + pPrevDCB->pNextDCB = pDCB; + pDCB->pNextDCB = pACB->pLinkDCB; + } + } + else if( pSRB->CmdBlock[0] == INQUIRY ) + { + if( (plink->target == pACB->max_id) && (plink->lun == pACB->max_lun) ) + pACB->scan_devices = 0; + if(pcmd->error == XS_TIMEOUT ) + goto NO_DEV; + ptr = (PSCSI_INQDATA) (pcmd->data); + bval1 = ptr->DevType & SCSI_DEVTYPE; + if(bval1 == SCSI_NODEV) + { +NO_DEV: + pACB->DCBmap[plink->target] &= ~(1 << plink->lun); + pPrevDCB->pNextDCB = pACB->pLinkDCB; + } + else + { + pACB->DeviceCnt++; + pPrevDCB = pDCB; + pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB )); + 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_) ) + { + disable_tag = 0; + for(i=0; i<BADDEVCNT; i++) + { + for(j=0; j<28; j++) + { + if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j]) + break; + } + if(j == 28) + { + disable_tag = 1; + break; + } + } + + if( !disable_tag ) + { + pDCB->MaxCommand = pACB->TagMaxNum; + pDCB->SyncMode |= EN_TAG_QUEUING; + pDCB->TagMask = 0; + } + else + { + pDCB->SyncMode |= EN_ATN_STOP; + } + } + } + } + } + } + + flags = splbio(); +/* 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->pGoingLast ) + pDCB->pGoingLast = psrb; + } + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pDCB->GoingSRBCnt--; + + DoWaitingSRB( pACB ); + splx(flags); + + pcmd->flags |= ITSDONE; + +/* Notify cmd done */ + scsi_done( pcmd ); +} + + +static void +DoingSRB_Done( PACB pACB ) +{ + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + USHORT cnt, i; + PSCSICMD pcmd; + + pDCB = pACB->pLinkDCB; + pdcb = pDCB; + do + { + cnt = pdcb->GoingSRBCnt; + psrb = pdcb->pGoingSRB; + for( i=0; i<cnt; i++) + { + psrb2 = psrb->pNextSRB; + pcmd = psrb->pcmd; + pcmd->error = XS_TIMEOUT; + +/* ReleaseSRB( pDCB, pSRB ); */ + + psrb->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = psrb; + + scsi_done( pcmd ); + psrb = psrb2; + } + pdcb->GoingSRBCnt = 0;; + pdcb->pGoingSRB = NULL; + pdcb->TagMask = 0; + pdcb = pdcb->pNextDCB; + } + while( pdcb != pDCB ); +} + + +static void +DC390_ResetSCSIBus( PACB pACB ) +{ + USHORT ioport; + UCHAR bval; + int flags; + + flags = splbio(); + pACB->ACBFlag |= RESET_DEV; + ioport = pACB->IOPortBase; + + bval = DMA_IDLE_CMD; + OutB(bval,ioport+DMA_Cmd); + + bval = RST_SCSI_BUS_CMD; + OutB(bval,ioport+ScsiCmd); + + splx(flags); + return; +} + + +static void +DC390_ScsiRstDetect( PACB pACB ) +{ + int flags; + ULONG wlval; + USHORT ioport; + UCHAR bval; + +#ifdef DC390_DEBUG0 + printf("RST_DETEC"); +#endif + wlval = 1000; + while( --wlval ) /* delay 1 sec */ + { + DELAY(1000); + } + flags = splbio(); + ioport = pACB->IOPortBase; + bval = DMA_IDLE_CMD; + OutB(bval,ioport+DMA_Cmd); + bval = CLEAR_FIFO_CMD; + OutB(bval,ioport+ScsiCmd); + + if( pACB->ACBFlag & RESET_DEV ) + pACB->ACBFlag |= RESET_DONE; + else + { + pACB->ACBFlag |= RESET_DETECT; + + ResetDevParam( pACB ); +/* DoingSRB_Done( pACB ); ???? */ + RecoverSRB( pACB ); + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; + DoWaitingSRB( pACB ); + } + splx(flags); + return; +} + + +static void +RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + PSCSICMD pcmd; + + pSRB->SRBFlag |= AUTO_REQSENSE; + pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0])); + pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4])); + pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); + pSRB->Segment1[1] = pSRB->TotalXferredLen; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + + pcmd = pSRB->pcmd; + + pSRB->Segmentx.SGXPtr = (ULONG) vtophys(&pcmd->sense); + pSRB->Segmentx.SGXLen = (ULONG) sizeof(struct scsi_sense_data); + pSRB->pSegmentList = &pSRB->Segmentx; + pSRB->SGcount = 1; + pSRB->SGIndex = 0; + + *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003; + pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; + *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(struct scsi_sense_data); + pSRB->ScsiCmdLen = 6; + + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) + RewaitSRB( pDCB, pSRB ); +} + + +static void +EnableMsgOut2( PACB pACB, PSRB pSRB ) +{ + USHORT ioport; + UCHAR bval; + + ioport = pACB->IOPortBase; + pSRB->MsgCnt = 1; + bval = SET_ATN_CMD; + OutB(bval, ioport+ScsiCmd); +} + + +static void +EnableMsgOut( PACB pACB, PSRB pSRB ) +{ + pSRB->MsgOutBuf[0] = MSG_ABORT; + EnableMsgOut2( pACB, pSRB ); +} + + +static void +DC390_InvalidCmd( PACB pACB ) +{ + UCHAR bval; + USHORT ioport; + PSRB pSRB; + + pSRB = pACB->pActiveDCB->pActiveSRB; + if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) + { + ioport = pACB->IOPortBase; + bval = CLEAR_FIFO_CMD; + OutB(bval,(ioport+ScsiCmd)); + } +} + diff --git a/sys/pci/tek390.c b/sys/pci/tek390.c new file mode 100644 index 0000000..606b50b --- /dev/null +++ b/sys/pci/tek390.c @@ -0,0 +1,1679 @@ +/*********************************************************************** + * FILE NAME : TEK390.C * + * BY : C.L. Huang (ching@tekram.com.tw) * + * Description: Device Driver for Tekram DC-390(T) PCI SCSI * + * Bus Master Host Adapter * + * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * + ***********************************************************************/ +/*********************************************************************** + * HISTORY: * + * * + * REV# DATE NAME DESCRIPTION * + * 1.00 07/02/96 CLH First release for RELEASE-2.1.0 * + * 1.01 08/20/96 CLH Update for RELEASE-2.1.5 * + * * + ***********************************************************************/ + +/************************************************************************** + * + * + * 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. + * + **************************************************************************/ + +/* #define REL_2_1_0 */ +#define REL_2_1_5 + +#define DC390_DEBUG + +#include <stddef.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/proc.h> + +#ifdef KERNEL +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/kernel.h> + +#include <machine/clock.h> +#include <machine/cpu.h> /* bootverbose */ + +#include <vm/vm.h> +#include <vm/vm_extern.h> +#endif /* KERNEL */ + +#include <sys/devconf.h> +#include <pci/pcivar.h> +#include <pci/pcireg.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <machine/clock.h> + +#include "tek390.h" + +#define INT32 int32 +#define U_INT32 u_int32 +#define TIMEOUT (timeout_func_t) + + +#define OutB(val, port) outb(port, val) +#define OutW(val, port) outw(port, val) +#define OutL(val, port) outl(port, val) + +#define PCI_DEVICE_ID_AMD53C974 0x20201022ul +#define PCI_BASE_ADDR0 0x10 + + +#ifdef REL_2_1_0 +static int DC390_Interrupt (PACB pACB); +#endif +#ifdef REL_2_1_5 +static void DC390_Interrupt (PACB pACB); +#endif +static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus); + +static void SetXferRate( PACB pACB, PDCB pDCB ); +static void DC390_Disconnect( PACB pACB ); +static void DC390_Reselect( PACB pACB ); +static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DoingSRB_Done( PACB pACB ); +static void DC390_ScsiRstDetect( PACB pACB ); +static void DC390_ResetSCSIBus( PACB pACB ); +static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void EnableMsgOut2( PACB pACB, PSRB pSRB ); +static void EnableMsgOut( PACB pACB, PSRB pSRB ); +static void DC390_InvalidCmd( PACB pACB ); + +static void DC390_timeout( void *arg1); +static void DC390_reset (PACB pACB); +static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt ); + +void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); +void DC390_initSRB( PSRB psrb ); +void DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index ); +int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index, + pcici_t config_id ); +void DC390_EnableCfg( USHORT mechnum, UCHAR regval ); +void DC390_DisableCfg( USHORT mechnum ); +UCHAR DC390_inByte( USHORT mechnum, UCHAR regval ); +USHORT DC390_inWord( USHORT mechnum, UCHAR regval ); +ULONG DC390_inDword(USHORT mechnum, UCHAR regval ); +void DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval ); +void DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval ); +void DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry ); +UCHAR DC390_EEpromInDO( USHORT mechnum ); +USHORT EEpromGetData1( USHORT mechnum ); +void DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd ); +void DC390_ReadEEprom( USHORT mechnum, USHORT index ); +USHORT DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index ); +USHORT DC390_ToMech( USHORT Mechnum, pcici_t config_id ); + + +#ifdef KERNEL + +static char* trmamd_probe( pcici_t tag, pcidi_t type); +static void trmamd_attach( pcici_t tag, int unit); + +#ifdef REL_2_1_0 +static int32 trmamd_scsi_cmd( struct scsi_xfer *sx); +#endif + +#ifdef REL_2_1_5 +static int32_t trmamd_scsi_cmd( struct scsi_xfer *sx); +#endif + +static void trmamd_min_phys( struct buf *pbuf); + +#ifdef REL_2_1_0 +static u_int32 trmamd_info( int unit ); +#endif + +#endif /* KERNEL */ + + +static u_long trmamd_count; + +struct pci_device trmamd_device = { + "trmamd", + trmamd_probe, + trmamd_attach, + &trmamd_count, + NULL +}; + +DATA_SET (pcidevice_set, trmamd_device); + + + +struct scsi_adapter trmamd_switch = +{ + trmamd_scsi_cmd, + trmamd_min_phys, + 0, + 0, +#ifdef REL_2_1_0 + trmamd_info, +#endif +#ifdef REL_2_1_5 + 0, +#endif + "trmamd", +}; + +struct scsi_device trmamd_dev = +{ + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "trmamd", +}; + + +static PACB pACB0[MAX_ADAPTER_NUM]={0}; +static PACB pACB_start= NULL; +static PACB pACB_current = NULL; +static PDCB pPrevDCB = NULL; +static USHORT adapterCnt = 0; +static USHORT CurrSyncOffset = 0; +static USHORT mech2Agent; +static ULONG mech1addr; +static UCHAR mech2bus, mech2CfgSPenR, CurrentID, CurrentLUN; + +static PVOID DC390_phase0[]={ + DC390_DataOut_0, + DC390_DataIn_0, + DC390_Command_0, + DC390_Status_0, + DC390_Nop_0, + DC390_Nop_0, + DC390_MsgOut_0, + DC390_MsgIn_0, + DC390_Nop_1 + }; + +static PVOID DC390_phase1[]={ + DC390_DataOutPhase, + DC390_DataInPhase, + DC390_CommandPhase, + DC390_StatusPhase, + DC390_Nop_0, + DC390_Nop_0, + DC390_MsgOutPhase, + DC390_MsgInPhase, + DC390_Nop_1, + }; + +UCHAR eepromBuf[MAX_ADAPTER_NUM][128]; + + +UCHAR clock_period1[] = {4, 5, 6, 7 ,8, 10, 13, 20}; + +UCHAR baddevname1[2][28] ={ + "SEAGATE ST3390N ??? 9546", + "HP C3323-300 4269"}; + +#define BADDEVCNT 2 + + +/*********************************************************************** + * + * + * + **********************************************************************/ +static PSRB +GetSRB( PACB pACB ) +{ + int flags; + PSRB pSRB; + + flags = splbio(); + + pSRB = pACB->pFreeSRB; + if( pSRB ) + { + pACB->pFreeSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + splx(flags); + return( pSRB ); +} + + +static void +RewaitSRB0( PDCB pDCB, PSRB pSRB ) +{ + PSRB psrb1; + int flags; + + flags = splbio(); + + if( (psrb1 = pDCB->pWaitingSRB) ) + { + pSRB->pNextSRB = psrb1; + pDCB->pWaitingSRB = pSRB; + } + else + { + pSRB->pNextSRB = NULL; + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLast = pSRB; + } + splx(flags); +} + + +static void +RewaitSRB( PDCB pDCB, PSRB pSRB ) +{ + PSRB psrb1; + int flags; + UCHAR bval; + + flags = splbio(); + + pDCB->GoingSRBCnt--; + psrb1 = pDCB->pGoingSRB; + if( pSRB == psrb1 ) + { + pDCB->pGoingSRB = psrb1->pNextSRB; + } + else + { + while( pSRB != psrb1->pNextSRB ) + psrb1 = psrb1->pNextSRB; + psrb1->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pGoingLast ) + pDCB->pGoingLast = psrb1; + } + if( (psrb1 = pDCB->pWaitingSRB) ) + { + pSRB->pNextSRB = psrb1; + pDCB->pWaitingSRB = pSRB; + } + else + { + pSRB->pNextSRB = NULL; + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLast = pSRB; + } + + bval = pSRB->TagNumber; + pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ + splx(flags); +} + + +static void +DoWaitingSRB( PACB pACB ) +{ + int flags; + PDCB ptr, ptr1; + PSRB pSRB; + + flags = splbio(); + + if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) + { + ptr = pACB->pDCBRunRobin; + if( !ptr ) + { + ptr = pACB->pLinkDCB; + pACB->pDCBRunRobin = ptr; + } + ptr1 = ptr; + for( ;ptr1; ) + { + pACB->pDCBRunRobin = ptr1->pNextDCB; + if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || + !( pSRB = ptr1->pWaitingSRB ) ) + { + if(pACB->pDCBRunRobin == ptr) + break; + ptr1 = ptr1->pNextDCB; + } + else + { + if( !DC390_StartSCSI(pACB, ptr1, pSRB) ) + { + ptr1->GoingSRBCnt++; + if( ptr1->pWaitLast == pSRB ) + { + ptr1->pWaitingSRB = NULL; + ptr1->pWaitLast = NULL; + } + else + { + ptr1->pWaitingSRB = pSRB->pNextSRB; + } + pSRB->pNextSRB = NULL; + + if( ptr1->pGoingSRB ) + ptr1->pGoingLast->pNextSRB = pSRB; + else + ptr1->pGoingSRB = pSRB; + ptr1->pGoingLast = pSRB; + } + break; + } + } + } + splx(flags); + return; +} + + +static void +SRBwaiting( PDCB pDCB, PSRB pSRB) +{ + if( pDCB->pWaitingSRB ) + { + pDCB->pWaitLast->pNextSRB = pSRB; + pDCB->pWaitLast = pSRB; + pSRB->pNextSRB = NULL; + } + else + { + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLast = pSRB; + } +} + + +static void +SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) +{ + int flags; + PDCB pDCB; + + flags = splbio(); + + pDCB = pSRB->pSRBDCB; + if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || + (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) + { + SRBwaiting(pDCB, pSRB); + goto SND_EXIT; + } + + if( pDCB->pWaitingSRB ) + { + SRBwaiting(pDCB, pSRB); +/* pSRB = GetWaitingSRB(pDCB); */ + pSRB = pDCB->pWaitingSRB; + pDCB->pWaitingSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + + if( !DC390_StartSCSI(pACB, pDCB, pSRB) ) + { + pDCB->GoingSRBCnt++; + if( pDCB->pGoingSRB ) + { + pDCB->pGoingLast->pNextSRB = pSRB; + pDCB->pGoingLast = pSRB; + } + else + { + pDCB->pGoingSRB = pSRB; + pDCB->pGoingLast = pSRB; + } + } + else + RewaitSRB0( pDCB, pSRB ); + +SND_EXIT: + splx(flags); + return; +} + + +/*********************************************************************** + * Function : static int32 dc390_scsi_cmd (struct scsi_xfer *cmd) + * Purpose : enqueues a SCSI command + ***********************************************************************/ + +#ifdef REL_2_1_0 +int32 +#endif +#ifdef REL_2_1_5 +int32_t +#endif +trmamd_scsi_cmd ( PSCSICMD cmd ) +{ + USHORT ioport, i; + PSCSICMD pcmd; + PSCLINK plink; + PACB pACB; + PDCB pDCB; + PSRB pSRB; + int flags, cflags, unit, CurrPgVaddr; + ULONG sglen, pglen, datalen, CurrPgPaddr, NextPgPaddr; + PUCHAR ptr,ptr1; + PSEG psg; + UCHAR sgc, sstatus; + + plink = cmd->sc_link; + unit = plink->adapter_unit; + pACB = pACB0[unit]; + ioport = pACB->IOPortBase; + +#ifdef DC390_DEBUG0 + printf("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmd->opcode, + plink->target, plink->lun); +#endif + + if( pACB->scan_devices ) + { + if( (plink->target >= CurrentID) && (plink->lun >= CurrentLUN) ) + { + CurrentID = plink->target; + CurrentLUN = plink->lun; + } + else + { + pACB->scan_devices = 0; + pPrevDCB->pNextDCB = pACB->pLinkDCB; + } + } + + if ( ( plink->target > pACB->max_id ) || ( plink->lun > pACB->max_lun ) ) + { +#ifdef DC390_DEBUG0 + printf("DC390: Ignore target %d lun %d\n", + plink->target, plink->lun); +#endif + cmd->error = XS_DRIVER_STUFFUP; + return( COMPLETE ); + } + + if( (pACB->scan_devices) && !(pACB->DCBmap[plink->target] & (1 << plink->lun)) ) + { + if( pACB->DeviceCnt < MAX_DEVICES ) + { + pACB->DCBmap[plink->target] |= (1 << plink->lun); + pDCB = pACB->pDCB_free; +#ifdef DC390_DEBUG0 + printf("pDCB=%8x,ID=%2x,", (UINT) pDCB, plink->target); +#endif + DC390_initDCB( pACB, pDCB, cmd ); + } + else /* ???? */ + { +#ifdef DC390_DEBUG0 + printf("DC390: Ignore target %d lun %d\n", + plink->target, plink->lun); +#endif + cmd->error = XS_DRIVER_STUFFUP; + return( COMPLETE ); + } + } + else if( !(pACB->scan_devices) && !(pACB->DCBmap[plink->target] & (1 << plink->lun)) ) + { +#ifdef DC390_DEBUG0 + printf("DC390: Ignore target %d lun %d\n", + plink->target, plink->lun); +#endif + cmd->error = XS_DRIVER_STUFFUP; + return( COMPLETE ); + } + else + { + pDCB = pACB->pLinkDCB; + while( (pDCB->UnitSCSIID != plink->target) || + (pDCB->UnitSCSILUN != plink->lun) ) + { + pDCB = pDCB->pNextDCB; + } +#ifdef DC390_DEBUG0 + printf("pDCB=%8x,ID=%2x,", (UINT) pDCB, plink->target); +#endif + } + + cflags = cmd->flags; + if(cflags & SCSI_RESET) + { + DC390_reset (pACB); + cmd->error = XS_NOERROR; + return(COMPLETE); + } + + if( cflags & ITSDONE ) + { + printf("DC390: Is it done?\n"); + cmd->flags &= ~ITSDONE; + } + if( !(cflags & INUSE) ) + { + printf("DC390: In Use?\n"); + cmd->flags |= INUSE; + } + + cmd->error = 0; + cmd->resid = 0; + + flags = splbio(); + + pcmd = cmd; + + pSRB = GetSRB( pACB ); + + if( !pSRB ) + { + pcmd->error = XS_DRIVER_STUFFUP; + splx(flags); + return( TRY_AGAIN_LATER); + } + +/* BuildSRB(pSRB); */ + + pSRB->pSRBDCB = pDCB; + pSRB->pcmd = pcmd; + ptr = (PUCHAR) pSRB->CmdBlock; + ptr1 = (PUCHAR) pcmd->cmd; + pSRB->ScsiCmdLen = pcmd->cmdlen; + for(i=0; i< pcmd->cmdlen; i++) + { + *ptr = *ptr1; + ptr++; + ptr1++; + } + if( pcmd->datalen ) + { + psg = (PSEG) &pSRB->SGsegment[0]; + pSRB->pSegmentList = psg; + sgc = 0; + + /* Set up the scatter gather list */ + datalen = pcmd->datalen; + CurrPgVaddr = (int) pcmd->data; + CurrPgPaddr = vtophys(CurrPgVaddr); + + while ((datalen) && (sgc < MAX_SG_ENTRY)) + { + sglen = 0; + psg->SGXPtr = CurrPgPaddr; + NextPgPaddr = CurrPgPaddr; + while ((datalen) && (CurrPgPaddr == NextPgPaddr)) + { + /* + * This page is contiguous (physically) with the the last, + * just extend the length + */ + + NextPgPaddr = (CurrPgPaddr & (~(PAGELEN - 1))) + PAGELEN; + pglen = NextPgPaddr - CurrPgPaddr; + + if( datalen < pglen ) + pglen = datalen; + sglen += pglen; + datalen -= pglen; + CurrPgVaddr = (CurrPgVaddr & (~(PAGELEN - 1))) + PAGELEN; + if( datalen ) + CurrPgPaddr = vtophys(CurrPgVaddr); + } + /* + next page isn't contiguous, finish this segment + */ + psg->SGXLen = sglen; + psg++; + sgc++; + } + pSRB->SGcount = sgc; + + if (datalen) + { + printf("DC390: Out Of Segment Buffer!\n"); + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pcmd->error = XS_DRIVER_STUFFUP; + splx(flags); + return (HAD_ERROR); + } + } + else + pSRB->SGcount = 0; + + pSRB->SGIndex = 0; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pSRB->MsgCnt = 0; + if( pDCB->DevType != SCSI_SEQACESS ) + pSRB->RetryCnt = 1; + else + pSRB->RetryCnt = 0; + pSRB->SRBStatus = 0; + pSRB->SRBFlag = 0; + pSRB->SRBState = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGPhysAddr = 0; + pSRB->SGToBeXferLen = 0; + pSRB->ScsiPhase = 0; + pSRB->EndMessage = 0; + splx(flags); + + if( !(cflags & SCSI_NOMASK) ) + { + flags = splbio(); + SendSRB( pcmd, pACB, pSRB ); + timeout(DC390_timeout, (caddr_t)pSRB, (pcmd->timeout * hz)/1000); + splx(flags); + return( SUCCESSFULLY_QUEUED); + } + else + { + SendSRB( pcmd, pACB, pSRB ); + do + { + while(--pcmd->timeout) + { + DELAY(1000); + sstatus = inb( ioport+Scsi_Status ); + if( sstatus & INTERRUPT ) + break; + } + if( pcmd->timeout == 0 ) + { + return(HAD_ERROR); + } + else + { + DC390_Interrupt( pACB ); + } + } + while( !(pcmd->flags & ITSDONE) ); + if( pcmd->error == XS_TIMEOUT) + return(HAD_ERROR); + else + return(COMPLETE); + } +} + + +void +trmamd_min_phys( struct buf *bp ) +{ + if (bp->b_bcount > ((MAX_SG_ENTRY - 1) * PAGELEN)) + bp->b_bcount = ((MAX_SG_ENTRY - 1) * PAGELEN); +} + + +#ifdef REL_2_1_0 +u_int32 +trmamd_info( int unit ) +{ + return (MAX_CMD_PER_LUN); /* outstanding requests at a time per device */ +} +#endif + + +static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt ) +{ + int dataPtr; + PSCSICMD pcmd; + UCHAR i; + PSEG pseg; + + pcmd = pSRB->pcmd; + dataPtr = (int) pcmd->data; + pseg = pSRB->SGsegment; + for(i=0; i < pSRB->SGIndex; i++) + { + dataPtr += (int) pseg->SGXLen; + pseg++; + } + dataPtr += (int) xferCnt; + return( (PUCHAR) dataPtr); +} + + +/*********************************************************************** + * Function : int DC390_abort (SCSICMD *cmd) + * + * Purpose : Abort an errant SCSI command + * + * Inputs : cmd - command to abort + * + * Returns : 0 on success, -1 on failure. + ***********************************************************************/ +/* +int +DC390_abort (SCSICMD *cmd) +{ + int flags; + PACB pACB; + PDCB pDCB, pdcb; + PSRB pSRB, psrb; + USHORT count, i; + PSCSICMD pcmd, pcmd1; + int status; + + +#ifdef DC390_DEBUG0 + printf("DC390 : Abort Cmd."); +#endif + + flags = splbio(); + + pACB = (PACB) cmd->host->hostdata; + pDCB = pACB->pLinkDCB; + pdcb = pDCB; + while( (pDCB->UnitSCSIID != cmd->sc_link->target) || + (pDCB->UnitSCSILUN != cmd->sc_link->lun) ) + { + pDCB = pDCB->pNextDCB; + if( pDCB == pdcb ) + goto NOT_RUN; + } + + + pSRB = pDCB->pWaitingSRB; + if( !pSRB ) + goto ON_GOING; + if( pSRB->pcmd == cmd ) + { + pDCB->pWaitingSRB = pSRB->pNextSRB; + goto IN_WAIT; + } + else + { + psrb = pSRB; + while( psrb->pNextSRB->pcmd != cmd ) + { + psrb = psrb->pNextSRB; + if( !psrb ) + goto ON_GOING; + } + pSRB = psrb->pNextSRB; + psrb->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pWaitLast ) + pDCB->pWaitLast = psrb; +IN_WAIT: + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + cmd->next = NULL; + status = SCSI_ABORT_SUCCESS; + goto ABO_X; + } + +ON_GOING: + pSRB = pDCB->pGoingSRB; + for( count = pDCB->GoingSRBCnt, i=0; i<count; i++) + { + if( pSRB->pcmd != cmd ) + pSRB = pSRB->pNextSRB; + else + { + if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) ) + { + status = SCSI_ABORT_BUSY; + goto ABO_X; + } + else + { + status = SCSI_ABORT_SNOOZE; + goto ABO_X; + } + } + } + +NOT_RUN: + status = SCSI_ABORT_NOT_RUNNING; + +ABO_X: + cmd->error = XS_NOERROR; + scsi_done(cmd); + splx(flags); + return( status ); +} +*/ + +static void +ResetDevParam( PACB pACB ) +{ + PDCB pDCB, pdcb; + + pDCB = pACB->pLinkDCB; + if( pDCB == NULL ) + return; + pdcb = pDCB; + do + { + pDCB->SyncMode &= ~SYNC_NEGO_DONE; + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->CtrlR3 = FAST_CLK; + pDCB->CtrlR4 &= NEGATE_REQACKDATA; + pDCB->CtrlR4 |= EATER_25NS; + pDCB = pDCB->pNextDCB; + } + while( pdcb != pDCB ); +} + + +static void +RecoverSRB( PACB pACB ) +{ + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + USHORT 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; +/* RewaitSRB( pDCB, psrb ); */ + if( pdcb->pWaitingSRB ) + { + psrb2->pNextSRB = pdcb->pWaitingSRB; + pdcb->pWaitingSRB = psrb2; + } + else + { + pdcb->pWaitingSRB = psrb2; + pdcb->pWaitLast = psrb2; + psrb2->pNextSRB = NULL; + } + } + pdcb->GoingSRBCnt = 0; + pdcb->pGoingSRB = NULL; + pdcb->TagMask = 0; + pdcb = pdcb->pNextDCB; + } + while( pdcb != pDCB ); +} + + +/*********************************************************************** + * Function : DC390_reset (PACB pACB) + * + * Purpose : perform a hard reset on the SCSI bus( and AMD chip). + * + * Inputs : cmd - command which caused the SCSI RESET + * + ***********************************************************************/ + +static void +DC390_reset (PACB pACB) +{ + USHORT ioport; + int flags; + UCHAR bval; + USHORT i; + + +#ifdef DC390_DEBUG0 + printf("DC390: RESET,"); +#endif + + flags = splbio(); + + ioport = pACB->IOPortBase; + bval = inb(ioport+CtrlReg1); + bval |= DIS_INT_ON_SCSI_RST; + OutB(bval,ioport+CtrlReg1); /* disable interrupt */ + DC390_ResetSCSIBus( pACB ); + for( i=0; i<500; i++ ) + DELAY(1000); + bval = inb(ioport+CtrlReg1); + bval &= ~DIS_INT_ON_SCSI_RST; + OutB(bval,ioport+CtrlReg1); /* re-enable interrupt */ + + bval = DMA_IDLE_CMD; + OutB(bval,ioport+DMA_Cmd); + bval = CLEAR_FIFO_CMD; + OutB(bval,ioport+ScsiCmd); + + ResetDevParam( pACB ); + DoingSRB_Done( pACB ); + pACB->pActiveDCB = NULL; + + pACB->ACBFlag = 0; + DoWaitingSRB( pACB ); + splx(flags); + return; +} + + +void +DC390_timeout( void *arg1) +{ + PSRB pSRB; + + pSRB = (PSRB) arg1; +} + + +#include "scsiiom.c" + + +/*********************************************************************** + * Function : static void DC390_initDCB + * + * Purpose : initialize the internal structures for a given DCB + * + * Inputs : cmd - pointer to this scsi cmd request block structure + * + ***********************************************************************/ +void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) +{ + PEEprom prom; + UCHAR bval; + USHORT index; + PSCLINK plink; + + if( pACB->DeviceCnt == 0 ) + { + pACB->pLinkDCB = pDCB; + pACB->pDCBRunRobin = pDCB; + pDCB->pNextDCB = pDCB; + pPrevDCB = pDCB; + } + else + pPrevDCB->pNextDCB = pDCB; + + plink = cmd->sc_link; + pDCB->pDCBACB = pACB; + pDCB->UnitSCSIID = plink->target; + pDCB->UnitSCSILUN = plink->lun; + pDCB->pWaitingSRB = NULL; + pDCB->pGoingSRB = NULL; + pDCB->GoingSRBCnt = 0; + pDCB->pActiveSRB = NULL; + pDCB->TagMask = 0; + pDCB->MaxCommand = 1; + pDCB->AdaptIndex = pACB->AdapterIndex; + index = pACB->AdapterIndex; + pDCB->DCBFlag = 0; + + prom = (PEEprom) &eepromBuf[index][plink->target << 2]; + pDCB->DevMode = prom->EE_MODE1; + pDCB->AdpMode = eepromBuf[index][EE_MODE2]; + + if( pDCB->DevMode & EN_DISCONNECT_ ) + bval = 0xC0; + else + bval = 0x80; + bval |= plink->lun; + pDCB->IdentifyMsg = bval; + + pDCB->SyncMode = 0; + if( pDCB->DevMode & SYNC_NEGO_ ) + { + if( !(plink->lun) || CurrSyncOffset ) + pDCB->SyncMode = SYNC_ENABLE; + } + + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2; + + pDCB->CtrlR1 = pACB->AdaptSCSIID; + if( pDCB->DevMode & PARITY_CHK_ ) + pDCB->CtrlR1 |= PARITY_ERR_REPO; + + pDCB->CtrlR3 = FAST_CLK; + + pDCB->CtrlR4 = EATER_25NS; + if( pDCB->AdpMode & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA; +} + + +/*********************************************************************** + * Function : static void DC390_initSRB + * + * Purpose : initialize the internal structures for a given SRB + * + * Inputs : psrb - pointer to this scsi request block structure + * + ***********************************************************************/ +void DC390_initSRB( PSRB psrb ) +{ + psrb->PhysSRB = vtophys( psrb ); +} + + +void DC390_linkSRB( PACB pACB ) +{ + USHORT count, i; + PSRB psrb; + + count = pACB->SRBCount; + + for( i=0; i< count; i++) + { + if( i != count - 1) + pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; + else + pACB->SRB_array[i].pNextSRB = NULL; + psrb = (PSRB) &pACB->SRB_array[i]; + DC390_initSRB( psrb ); + } +} + + +/*********************************************************************** + * Function : static void DC390_initACB + * + * Purpose : initialize the internal structures for a given SCSI host + * + * Inputs : psh - pointer to this host adapter's structure + * + ***********************************************************************/ +void DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index ) +{ + USHORT i; + + + pACB->max_id = 7; + if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] ) + pACB->max_id--; + if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) + pACB->max_lun = 7; + else + pACB->max_lun = 0; + + pACB->IOPortBase = (USHORT) io_port; + pACB->pLinkDCB = NULL; + pACB->pDCBRunRobin = NULL; + pACB->pActiveDCB = NULL; + pACB->pFreeSRB = pACB->SRB_array; + pACB->SRBCount = MAX_SRB_CNT; + pACB->AdapterIndex = index; + pACB->status = 0; + pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID]; + pACB->HostID_Bit = (1 << pACB->AdaptSCSIID); + pACB->AdaptSCSILUN = 0; + pACB->DeviceCnt = 0; + pACB->IRQLevel = Irq; + pACB->TagMaxNum = (eepromBuf[index][EE_TAG_CMD_NUM]) << 2; + pACB->ACBFlag = 0; + pACB->scan_devices = 1; + pACB->Gmode2 = eepromBuf[index][EE_MODE2]; + if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) + pACB->LUNchk = 1; + pACB->pDCB_free = &pACB->DCB_array[0]; + DC390_linkSRB( pACB ); + pACB->pTmpSRB = &pACB->TmpSRB; + DC390_initSRB( pACB->pTmpSRB ); + for(i=0; i<MAX_SCSI_ID; i++) + pACB->DCBmap[i] = 0; + + pACB->ScsiLink.adapter_unit = index; + pACB->ScsiLink.adapter_targ = pACB->AdaptSCSIID; + pACB->ScsiLink.fordriver = 0; + pACB->ScsiLink.opennings = 2; + pACB->ScsiLink.adapter = &trmamd_switch; + pACB->ScsiLink.device = &trmamd_dev; + pACB->ScsiLink.flags = 0; +} + + +/*********************************************************************** + * Function : static int DC390_initAdapter + * + * Purpose : initialize the SCSI chip ctrl registers + * + * Inputs : psh - pointer to this host adapter's structure + * + ***********************************************************************/ +int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index, + pcici_t config_id ) +{ + USHORT ioport; + UCHAR bval; + +#ifdef CHECK_SHARE_INT + PACB pacb; + USHORT used_irq = 0; + + pacb = pACB_start; + if( pacb != NULL ) + { + for ( ; (pacb != (PACB) -1) ; ) + { + if( pacb->IRQLevel == Irq ) + { + used_irq = 1; + break; + } + else + pacb = pacb->pNextACB; + } + } + + if( !used_irq ) + { +#endif + if( !pci_map_int (config_id, (PVOID)DC390_Interrupt, pACB, &bio_imask) ) + { + if(bootverbose) + printf("DC390: register Interrupt handler error!\n"); + return( -1 ); + } + +#ifdef CHECK_SHARE_INT + } +#endif + + ioport = (USHORT) io_port; + bval = 153; /* 250ms selection timeout */ + OutB(bval,ioport+Scsi_TimeOut); + + bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */ + OutB(bval,ioport+Clk_Factor); + + bval = NOP_CMD; /* NOP cmd - clear command register */ + OutB(bval,ioport+ScsiCmd); + + bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */ + OutB(bval,ioport+CtrlReg2); + + bval = FAST_CLK; /* fast clock */ + OutB(bval,ioport+CtrlReg3); + + bval = EATER_25NS; + if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION ) + bval |= NEGATE_REQACKDATA; + OutB(bval,ioport+CtrlReg4); + + bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */ + OutB(bval,ioport+CtrlReg1); + + return(0); +} + + +void +DC390_EnableCfg( USHORT mechnum, UCHAR regval ) +{ + ULONG wlval; + + if(mechnum == 2) + { + OutB(mech2bus, PCI_CFG2_FORWARD_REG); + OutB(mech2CfgSPenR, PCI_CFG2_ENABLE_REG); + } + else + { + regval &= 0xFC; + wlval = mech1addr; + wlval |= (((ULONG)regval) & 0xff); + OutL(wlval, PCI_CFG1_ADDRESS_REG); + } +} + + +void +DC390_DisableCfg( USHORT mechnum ) +{ + + if(mechnum == 2) + OutB(0, PCI_CFG2_ENABLE_REG); + else + OutL(0, PCI_CFG1_ADDRESS_REG); +} + + +UCHAR +DC390_inByte( USHORT mechnum, UCHAR regval ) +{ + UCHAR bval; + USHORT wval; + int flags; + + flags = splbio(); + DC390_EnableCfg( mechnum, regval ); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= ((USHORT) regval) & 0xff; + bval = inb(wval); + } + else + { + regval &= 3; + bval = inb(PCI_CFG1_DATA_REG | regval); + } + DC390_DisableCfg(mechnum); + splx(flags); + return(bval); +} + + +USHORT +DC390_inWord( USHORT mechnum, UCHAR regval ) +{ + USHORT wval; + int flags; + + flags = splbio(); + DC390_EnableCfg(mechnum,regval); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= regval; + wval = inw(wval); + } + else + { + regval &= 3; + wval = inw(PCI_CFG1_DATA_REG | regval); + } + DC390_DisableCfg(mechnum); + splx(flags); + return(wval); +} + + +ULONG +DC390_inDword(USHORT mechnum, UCHAR regval ) +{ + ULONG wlval; + int flags; + USHORT wval; + + flags = splbio(); + DC390_EnableCfg(mechnum,regval); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= regval; + wlval = inl(wval); + } + else + { + wlval = inl(PCI_CFG1_DATA_REG); + } + DC390_DisableCfg(mechnum); + splx(flags); + return(wlval); +} + + +void +DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval ) +{ + + USHORT wval; + int flags; + + flags = splbio(); + DC390_EnableCfg(mechnum,regval); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= regval; + OutB(bval, wval); + } + else + { + regval &= 3; + OutB(bval, PCI_CFG1_DATA_REG | regval); + } + DC390_DisableCfg(mechnum); + splx(flags); +} + + +void +DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval ) +{ + + UCHAR bval; + + bval = 0; + if(mode == ENABLE_CE) + *regval = 0xc0; + else + *regval = 0x80; + DC390_OutB(mechnum,*regval,bval); + if(mode == DISABLE_CE) + DC390_OutB(mechnum,*regval,bval); + DELAY(160); +} + + +void +DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry ) +{ + UCHAR bval; + + bval = 0; + if(Carry) + { + bval = 0x40; + *regval = 0x80; + DC390_OutB(mechnum,*regval,bval); + } + DELAY(160); + bval |= 0x80; + DC390_OutB(mechnum,*regval,bval); + DELAY(160); + bval = 0; + DC390_OutB(mechnum,*regval,bval); + DELAY(160); +} + + +UCHAR +DC390_EEpromInDO( USHORT mechnum ) +{ + UCHAR bval,regval; + + regval = 0x80; + bval = 0x80; + DC390_OutB(mechnum,regval,bval); + DELAY(160); + bval = 0x40; + DC390_OutB(mechnum,regval,bval); + DELAY(160); + regval = 0x0; + bval = DC390_inByte(mechnum,regval); + if(bval == 0x22) + return(1); + else + return(0); +} + + +USHORT +EEpromGetData1( USHORT mechnum ) +{ + UCHAR i; + UCHAR carryFlag; + USHORT wval; + + wval = 0; + for(i=0; i<16; i++) + { + wval <<= 1; + carryFlag = DC390_EEpromInDO(mechnum); + wval |= carryFlag; + } + return(wval); +} + + +void +DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd ) +{ + UCHAR i,j; + USHORT carryFlag; + + carryFlag = 1; + j = 0x80; + for(i=0; i<9; i++) + { + DC390_EEpromOutDI(mechnum,regval,carryFlag); + carryFlag = (EEpromCmd & j) ? 1 : 0; + j >>= 1; + } +} + + +void +DC390_ReadEEprom( USHORT mechnum, USHORT index ) +{ + UCHAR regval,cmd; + PUSHORT ptr; + USHORT i; + + ptr = (PUSHORT) &eepromBuf[index][0]; + cmd = EEPROM_READ; + for(i=0; i<0x40; i++) + { + DC390_EnDisableCE(ENABLE_CE, mechnum, ®val); + DC390_Prepare(mechnum, ®val, cmd); + *ptr = EEpromGetData1(mechnum); + ptr++; + cmd++; + DC390_EnDisableCE(DISABLE_CE,mechnum,®val); + } +} + + +USHORT +DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index ) +{ + USHORT wval, rc, *ptr; + UCHAR i; + + DC390_ReadEEprom( MechNum, index ); + wval = 0; + ptr = (PUSHORT) &eepromBuf[index][0]; + for(i=0; i<128 ;i+=2, ptr++) + wval += *ptr; + if( wval == 0x1234 ) + rc = 0; + else + rc = -1; + return( rc ); +} + + +USHORT +DC390_ToMech( USHORT Mechnum, pcici_t config_id ) +{ + + if(Mechnum == 2) + { + mech2bus = config_id.cfg2.forward; /* Bus num */ + mech2Agent = config_id.cfg2.port >> 8; /* Dev num */ + mech2CfgSPenR = config_id.cfg2.enable; /* Fun num */ + } + else /* use mech #1 method */ + { + mech1addr = config_id.cfg1; + } + return(0); +} + +/*********************************************************************** + * Function : static int DC390_init (struct Scsi_Host *host) + * + * Purpose : initialize the internal structures for a given SCSI host + * + * Inputs : host - pointer to this host adapter's structure/ + * + * Preconditions : when this function is called, the chip_type + * field of the pACB structure MUST have been set. + ***********************************************************************/ + +static int +DC390_init( ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum, + pcici_t config_id) +{ + PACB pACB; + + if( !DC390_CheckEEpromCheckSum( MechNum, index) ) + { + pACB = (PACB) malloc (sizeof (struct _ACB), M_DEVBUF, M_WAITOK); + if( !pACB ) + { + printf("DC390%d: cannot allocate ACB !\n", index); + return( -1 ); + } + bzero (pACB, sizeof (struct _ACB)); + DC390_initACB( pACB, io_port, Irq, index ); + if( !DC390_initAdapter( pACB, io_port, Irq, index, config_id) ) + { + if( !pACB_start ) + { + pACB_start = pACB; + pACB_current = pACB; + pACB->pNextACB = (PACB) -1; + } + else + { + pACB_current->pNextACB = pACB; + pACB_current = pACB; + pACB->pNextACB = (PACB) -1; + } + pACB0[index] = pACB; + +#ifdef DC390_DEBUG0 + printf("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n", + (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array); + printf("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n", + sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) ); +#endif + + return( 0 ); + } + else + { + free( pACB, M_DEVBUF); + return( -1 ); + } + } + else + { + printf("DC390_init: EEPROM reading error!\n"); + return( -1 ); + } +} + + + +void +trmamd_attach (pcici_t config_id, int unit) +{ + struct scsibus_data *scbus; + UCHAR irq; + USHORT MechNum; + ULONG io_port, wlval; + PACB pACB = 0; + int flags; + + if( unit >= MAX_ADAPTER_NUM ) + return; + + if( pACB0[unit] ) + return; + + CurrentID = 0; + CurrentLUN = 0; + MechNum = pci_mechanism; + +#ifdef DC390_DEBUG0 + if(bootverbose) + printf("DC390: Mech=%2x,\n",(UCHAR) MechNum); +#endif + + if( !DC390_ToMech( MechNum, config_id ) ) + { + wlval = DC390_inDword( MechNum, PCI_ID_REG); + if(wlval == PCI_DEVICE_ID_AMD53C974 ) + { + io_port =DC390_inDword(MechNum,PCI_BASE_ADDR0) & 0xFFFE; + irq = DC390_inByte( MechNum, PCI_INTERRUPT_REG); +#ifdef DC390_DEBUG0 + if(bootverbose) + printf("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq); +#endif + if( !DC390_init( io_port, irq, (USHORT) unit, MechNum, config_id) ) + { + adapterCnt++; + } + else + return; + } + } + + pACB = pACB0[unit]; + +/* + Now let the generic SCSI driver look for the SCSI devices on the bus +*/ + + flags = splbio(); + + scbus = scsi_alloc_bus(); + if(!scbus) + { + splx(flags); + return; + } + scbus->adapter_link = &pACB->ScsiLink; + scbus->maxtarg = pACB->max_id; + +#ifdef DC390_DEBUG + if(bootverbose) + printf("\nDC390: scanning for devices ...\n\n"); +#endif + + scsi_attachdevs (scbus); + scbus = NULL; /* Upper-level SCSI code owns this now */ + +#ifdef DC390_DEBUG + if(bootverbose) + printf("\n\nDC390: Attach devices return\n"); +#endif + + splx(flags); +} + + +static char* +trmamd_probe (pcici_t tag, pcidi_t type) +{ + if( type == PCI_DEVICE_ID_AMD53C974 ) + return ("Tekram DC390(T) Adapter Driver v1.01 Aug-20-1996"); + else + return (NULL); +} + diff --git a/sys/pci/tek390.h b/sys/pci/tek390.h new file mode 100644 index 0000000..ec52863 --- /dev/null +++ b/sys/pci/tek390.h @@ -0,0 +1,667 @@ +/*********************************************************************** +;* File Name : TEK390.H * +;* TEKRAM DC-390 PCI SCSI Bus Master Host Adapter * +;* Device Driver * +;***********************************************************************/ + +#ifndef TEK390_H +#define TEK390_H + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned long ULONG; +typedef unsigned int UINT; + +typedef UCHAR *PUCHAR; +typedef USHORT *PUSHORT; +typedef ULONG *PULONG; +typedef struct scsi_link *PSCLINK, SCSILINK; +typedef struct scsi_xfer *PSCSICMD, SCSICMD; +typedef void *PVOID; + + +/*;-----------------------------------------------------------------------*/ +typedef struct _SyncMsg +{ +UCHAR ExtendMsg; +UCHAR ExtMsgLen; +UCHAR SyncXferReq; +UCHAR Period; +UCHAR ReqOffset; +} SyncMsg; +/*;-----------------------------------------------------------------------*/ +typedef struct _Capacity +{ +ULONG BlockCount; +ULONG BlockLength; +} Capacity; +/*;-----------------------------------------------------------------------*/ +typedef struct _SGentry +{ +ULONG SGXLen; +ULONG SGXPtr; +} SGentry, *PSEG; + +typedef struct _SGentry1 +{ +ULONG SGXPtr1; +ULONG SGXLen1; +} SGentry1, *PSEG1; + + +#define MAX_ADAPTER_NUM 4 +#define MAX_SCSI_ID 8 +#define MAX_SG_ENTRY 33 +#define MAX_DEVICES 10 +#define MAX_CMD_QUEUE 20 +#define MAX_CMD_PER_LUN 6 +#define MAX_SRB_CNT MAX_CMD_PER_LUN*4 +#define PAGELEN 4096 + +/* +;----------------------------------------------------------------------- +; SCSI Request Block +;----------------------------------------------------------------------- +*/ +struct _SRB +{ +UCHAR CmdBlock[12]; + +struct _SRB *pNextSRB; +struct _DCB *pSRBDCB; +PSCSICMD pcmd; +PSEG pSegmentList; + +ULONG PhysSRB; +ULONG TotalXferredLen; +ULONG SGPhysAddr; /*;a segment starting address */ +ULONG SGToBeXferLen; /*; to be xfer length */ +ULONG Segment0[2]; +ULONG Segment1[2]; + +SGentry SGsegment[MAX_SG_ENTRY]; +SGentry Segmentx; /* make a one entry of S/G list table */ + +PUCHAR pMsgPtr; +USHORT SRBState; +USHORT Revxx2; /* ??? */ + +UCHAR MsgInBuf[6]; +UCHAR MsgOutBuf[6]; + +UCHAR AdaptStatus; +UCHAR TargetStatus; +UCHAR MsgCnt; +UCHAR EndMessage; +UCHAR TagNumber; +UCHAR SGcount; +UCHAR SGIndex; +UCHAR IORBFlag; /*;81h-Reset, 2-retry */ + +UCHAR SRBStatus; +UCHAR RetryCnt; +UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ + /*; b4-settimeout,b5-Residual valid */ +UCHAR ScsiCmdLen; +UCHAR ScsiPhase; +UCHAR Reserved3[3]; /*;for dword alignment */ +}; + +typedef struct _SRB DC390_SRB, *PSRB; + +/* +;----------------------------------------------------------------------- +; Device Control Block +;----------------------------------------------------------------------- +*/ +struct _DCB +{ +struct _DCB *pNextDCB; +struct _ACB *pDCBACB; + +PSRB pWaitingSRB; +PSRB pWaitLast; +PSRB pGoingSRB; +PSRB pGoingLast; +PSRB pActiveSRB; +USHORT GoingSRBCnt; +USHORT WaitSRBCnt; /* ??? */ + +ULONG TagMask; + +USHORT MaxCommand; +USHORT AdaptIndex; /*; UnitInfo struc start */ +USHORT UnitIndex; /*; nth Unit on this card */ +UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ +UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ + +UCHAR IdentifyMsg; +UCHAR CtrlR1; +UCHAR CtrlR3; +UCHAR CtrlR4; + +UCHAR InqDataBuf[8]; +UCHAR CapacityBuf[8]; +UCHAR DevMode; +UCHAR AdpMode; +UCHAR SyncMode; /*; 0:async mode */ +UCHAR NegoPeriod; /*;for nego. */ +UCHAR SyncPeriod; /*;for reg. */ +UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ +UCHAR UnitCtrlFlag; +UCHAR DCBFlag; +UCHAR DevType; +UCHAR Reserved2[3]; /*;for dword alignment */ +}; + +typedef struct _DCB DC390_DCB, *PDCB; +/* +;----------------------------------------------------------------------- +; Adapter Control Block +;----------------------------------------------------------------------- +*/ +struct _ACB +{ +ULONG PhysACB; +struct _ACB *pNextACB; +USHORT IOPortBase; +USHORT Revxx1; /* ??? */ + +PDCB pLinkDCB; +PDCB pDCBRunRobin; +PDCB pActiveDCB; +PDCB pDCB_free; +PSRB pFreeSRB; +PSRB pTmpSRB; +USHORT SRBCount; +USHORT AdapterIndex; /*; nth Adapter this driver */ +USHORT max_id; +USHORT max_lun; +SCSILINK ScsiLink; + +UCHAR msgin123[4]; +UCHAR status; +UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */ +UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */ +UCHAR DeviceCnt; +UCHAR IRQLevel; +UCHAR TagMaxNum; +UCHAR ACBFlag; +UCHAR Gmode2; +UCHAR LUNchk; +UCHAR scan_devices; +UCHAR HostID_Bit; +UCHAR Reserved1[1]; /*;for dword alignment */ +UCHAR DCBmap[MAX_SCSI_ID]; +DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */ +DC390_SRB TmpSRB; +}; + +typedef struct _ACB DC390_ACB, *PACB; + +/*;-----------------------------------------------------------------------*/ + + +#define BIT31 0x80000000 +#define BIT30 0x40000000 +#define BIT29 0x20000000 +#define BIT28 0x10000000 +#define BIT27 0x08000000 +#define BIT26 0x04000000 +#define BIT25 0x02000000 +#define BIT24 0x01000000 +#define BIT23 0x00800000 +#define BIT22 0x00400000 +#define BIT21 0x00200000 +#define BIT20 0x00100000 +#define BIT19 0x00080000 +#define BIT18 0x00040000 +#define BIT17 0x00020000 +#define BIT16 0x00010000 +#define BIT15 0x00008000 +#define BIT14 0x00004000 +#define BIT13 0x00002000 +#define BIT12 0x00001000 +#define BIT11 0x00000800 +#define BIT10 0x00000400 +#define BIT9 0x00000200 +#define BIT8 0x00000100 +#define BIT7 0x00000080 +#define BIT6 0x00000040 +#define BIT5 0x00000020 +#define BIT4 0x00000010 +#define BIT3 0x00000008 +#define BIT2 0x00000004 +#define BIT1 0x00000002 +#define BIT0 0x00000001 + +/*;---UnitCtrlFlag */ +#define UNIT_ALLOCATED BIT0 +#define UNIT_INFO_CHANGED BIT1 +#define FORMATING_MEDIA BIT2 +#define UNIT_RETRY BIT3 + +/*;---UnitFlags */ +#define DASD_SUPPORT BIT0 +#define SCSI_SUPPORT BIT1 +#define ASPI_SUPPORT BIT2 + +/*;----SRBState machine definition */ +#define SRB_FREE 0 +#define SRB_WAIT BIT0 +#define SRB_READY BIT1 +#define SRB_MSGOUT BIT2 /*;arbitration+msg_out 1st byte*/ +#define SRB_MSGIN BIT3 +#define SRB_MSGIN_MULTI BIT4 +#define SRB_COMMAND BIT5 +#define SRB_START_ BIT6 /*;arbitration+msg_out+command_out*/ +#define SRB_DISCONNECT BIT7 +#define SRB_DATA_XFER BIT8 +#define SRB_XFERPAD BIT9 +#define SRB_STATUS BIT10 +#define SRB_COMPLETED BIT11 +#define SRB_ABORT_SENT BIT12 +#define DO_SYNC_NEGO BIT13 +#define SRB_UNEXPECT_RESEL BIT14 + +/*;---ACBFlag */ +#define RESET_DEV BIT0 +#define RESET_DETECT BIT1 +#define RESET_DONE BIT2 + +/*;---DCBFlag */ +#define ABORT_DEV_ BIT0 + +/*;---SRBstatus */ +#define SRB_OK BIT0 +#define ABORTION BIT1 +#define OVER_RUN BIT2 +#define UNDER_RUN BIT3 +#define PARITY_ERROR BIT4 +#define SRB_ERROR BIT5 + +/*;---SRBFlag */ +#define DATAOUT BIT7 +#define DATAIN BIT6 +#define RESIDUAL_VALID BIT5 +#define ENABLE_TIMER BIT4 +#define RESET_DEV0 BIT2 +#define ABORT_DEV BIT1 +#define AUTO_REQSENSE BIT0 + +/*;---Adapter status */ +#define H_STATUS_GOOD 0 +#define H_SEL_TIMEOUT 0x11 +#define H_OVER_UNDER_RUN 0x12 +#define H_UNEXP_BUS_FREE 0x13 +#define H_TARGET_PHASE_F 0x14 +#define H_INVALID_CCB_OP 0x16 +#define H_LINK_CCB_BAD 0x17 +#define H_BAD_TARGET_DIR 0x18 +#define H_DUPLICATE_CCB 0x19 +#define H_BAD_CCB_OR_SG 0x1A +#define H_ABORT 0x0FF + +/*; SCSI Status byte codes*/ +#define SCSI_STAT_GOOD 0x0 /*; Good status */ +#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ +#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ +#define SCSI_STAT_BUSY 0x08 /*; Target busy status */ +#define SCSI_STAT_INTER 0x10 /*; Intermediate status */ +#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */ +#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */ +#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */ +#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */ + +#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */ +#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */ +#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */ + +/*;---Sync_Mode */ +#define SYNC_DISABLE 0 +#define SYNC_ENABLE BIT0 +#define SYNC_NEGO_DONE BIT1 +#define WIDE_ENABLE BIT2 +#define WIDE_NEGO_DONE BIT3 +#define EN_TAG_QUEUING BIT4 +#define EN_ATN_STOP BIT5 + +#define SYNC_NEGO_OFFSET 15 + +/*;---SCSI bus phase*/ +#define SCSI_DATA_OUT_ 0 +#define SCSI_DATA_IN_ 1 +#define SCSI_COMMAND 2 +#define SCSI_STATUS_ 3 +#define SCSI_NOP0 4 +#define SCSI_NOP1 5 +#define SCSI_MSG_OUT 6 +#define SCSI_MSG_IN 7 + +/*;----SCSI MSG BYTE*/ +#define MSG_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_SAVE_PTR 0x02 +#define MSG_RESTORE_PTR 0x03 +#define MSG_DISCONNECT 0x04 +#define MSG_INITIATOR_ERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT_ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define MSG_LINK_CMD_COMPL 0x0A +#define MSG_LINK_CMD_COMPL_FLG 0x0B +#define MSG_BUS_RESET 0x0C +#define MSG_ABORT_TAG 0x0D +#define MSG_SIMPLE_QTAG 0x20 +#define MSG_HEAD_QTAG 0x21 +#define MSG_ORDER_QTAG 0x22 +#define MSG_IDENTIFY 0x80 +#define MSG_HOST_ID 0x0C0 + +/*;----SCSI STATUS BYTE*/ +#define STATUS_GOOD 0x00 +#define CHECK_CONDITION_ 0x02 +#define STATUS_BUSY 0x08 +#define STATUS_INTERMEDIATE 0x10 +#define RESERVE_CONFLICT 0x18 + +/* cmd->result */ +#define STATUS_MASK_ 0xFF +#define MSG_MASK 0xFF00 +#define RETURN_MASK 0xFF0000 + +/* +** Inquiry Data format +*/ + +typedef struct _SCSIInqData { /* INQ */ + + UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/ + UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */ + UCHAR Vers; /* ISO, ECMA, & ANSI versions */ + UCHAR RDF; /* AEN, TRMIOP, & response data format*/ + UCHAR AddLen; /* length of additional data */ + UCHAR Res1; /* reserved */ + UCHAR Res2; /* reserved */ + UCHAR Flags; /* RelADr,Wbus32,Wbus16,Sync,etc. */ + UCHAR VendorID[8]; /* Vendor Identification */ + UCHAR ProductID[16]; /* Product Identification */ + UCHAR ProductRev[4]; /* Product Revision */ + + +} SCSI_INQDATA, *PSCSI_INQDATA; + + +/* Inquiry byte 0 masks */ + + +#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ +#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ + + +/* Inquiry byte 1 mask */ + +#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */ + + +/* Peripheral Device Type definitions */ + +#define SCSI_DASD 0x00 /* Direct-access Device */ +#define SCSI_SEQACESS 0x01 /* Sequential-access device */ +#define SCSI_PRINTER 0x02 /* Printer device */ +#define SCSI_PROCESSOR 0x03 /* Processor device */ +#define SCSI_WRITEONCE 0x04 /* Write-once device */ +#define SCSI_CDROM 0x05 /* CD-ROM device */ +#define SCSI_SCANNER 0x06 /* Scanner device */ +#define SCSI_OPTICAL 0x07 /* Optical memory device */ +#define SCSI_MEDCHGR 0x08 /* Medium changer device */ +#define SCSI_COMM 0x09 /* Communications device */ +#define SCSI_NODEV 0x1F /* Unknown or no device type */ + +/* +** Inquiry flag definitions (Inq data byte 7) +*/ + +#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing*/ +#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */ +#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */ +#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */ +#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */ +#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */ +#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */ + + +/* +;========================================================== +; EEPROM byte offset +;========================================================== +*/ +typedef struct _EEprom +{ +UCHAR EE_MODE1; +UCHAR EE_SPEED; +UCHAR xx1; +UCHAR xx2; +} EEprom, *PEEprom; + +#define EE_ADAPT_SCSI_ID 64 +#define EE_MODE2 65 +#define EE_DELAY 66 +#define EE_TAG_CMD_NUM 67 + +/*; EE_MODE1 bits definition*/ +#define PARITY_CHK_ BIT0 +#define SYNC_NEGO_ BIT1 +#define EN_DISCONNECT_ BIT2 +#define SEND_START_ BIT3 +#define TAG_QUEUING_ BIT4 + +/*; EE_MODE2 bits definition*/ +#define MORE2_DRV BIT0 +#define GREATER_1G BIT1 +#define RST_SCSI_BUS BIT2 +#define ACTIVE_NEGATION BIT3 +#define NO_SEEK BIT4 +#define LUN_CHECK BIT5 + +#define ENABLE_CE 1 +#define DISABLE_CE 0 +#define EEPROM_READ 0x80 + +/* +;========================================================== +; AMD 53C974 Registers bit Definition +;========================================================== +*/ +/* +;==================== +; SCSI Register +;==================== +*/ + +/*; Command Reg.(+0CH) */ +#define DMA_COMMAND BIT7 +#define NOP_CMD 0 +#define CLEAR_FIFO_CMD 1 +#define RST_DEVICE_CMD 2 +#define RST_SCSI_BUS_CMD 3 +#define INFO_XFER_CMD 0x10 +#define INITIATOR_CMD_CMPLTE 0x11 +#define MSG_ACCEPTED_CMD 0x12 +#define XFER_PAD_BYTE 0x18 +#define SET_ATN_CMD 0x1A +#define RESET_ATN_CMD 0x1B +#define SELECT_W_ATN 0x42 +#define SEL_W_ATN_STOP 0x43 +#define EN_SEL_RESEL 0x44 +#define SEL_W_ATN2 0x46 +#define DATA_XFER_CMD INFO_XFER_CMD + + +/*; SCSI Status Reg.(+10H) */ +#define INTERRUPT BIT7 +#define ILLEGAL_OP_ERR BIT6 +#define PARITY_ERR BIT5 +#define COUNT_2_ZERO BIT4 +#define GROUP_CODE_VALID BIT3 +#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) + +/*; Interrupt Status Reg.(+14H) */ +#define SCSI_RESET_ BIT7 +#define INVALID_CMD BIT6 +#define DISCONNECTED BIT5 +#define SERVICE_REQUEST BIT4 +#define SUCCESSFUL_OP BIT3 +#define RESELECTED BIT2 +#define SEL_ATTENTION BIT1 +#define SELECTED BIT0 + +/*; Internal State Reg.(+18H) */ +#define SYNC_OFFSET_FLAG BIT3 +#define INTRN_STATE_MASK (BIT2+BIT1+BIT0) + +/*; Clock Factor Reg.(+24H) */ +#define CLK_FREQ_40MHZ 0 +#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0) +#define CLK_FREQ_30MHZ (BIT2+BIT1) +#define CLK_FREQ_25MHZ (BIT2+BIT0) +#define CLK_FREQ_20MHZ BIT2 +#define CLK_FREQ_15MHZ (BIT1+BIT0) +#define CLK_FREQ_10MHZ BIT1 + +/*; Control Reg. 1(+20H) */ +#define EXTENDED_TIMING BIT7 +#define DIS_INT_ON_SCSI_RST BIT6 +#define PARITY_ERR_REPO BIT4 +#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) + +/*; Control Reg. 2(+2CH) */ +#define EN_FEATURE BIT6 +#define EN_SCSI2_CMD BIT3 + +/*; Control Reg. 3(+30H) */ +#define ID_MSG_CHECK BIT7 +#define EN_QTAG_MSG BIT6 +#define EN_GRP2_CMD BIT5 +#define FAST_SCSI BIT4 /* ;10MB/SEC */ +#define FAST_CLK BIT3 /* ;25 - 40 MHZ */ + +/*; Control Reg. 4(+34H) */ +#define EATER_12NS 0 +#define EATER_25NS BIT7 +#define EATER_35NS BIT6 +#define EATER_0NS (BIT7+BIT6) +#define NEGATE_REQACKDATA BIT2 +#define NEGATE_REQACK BIT3 +/* +;==================== +; DMA Register +;==================== +*/ +/*; DMA Command Reg.(+40H) */ +#define READ_DIRECTION BIT7 +#define WRITE_DIRECTION 0 +#define EN_DMA_INT BIT6 +#define MAP_TO_MDL BIT5 +#define DIAGNOSTIC BIT4 +#define DMA_IDLE_CMD 0 +#define DMA_BLAST_CMD BIT0 +#define DMA_ABORT_CMD BIT1 +#define DMA_START_CMD (BIT1+BIT0) + +/*; DMA Status Reg.(+54H) */ +#define PCI_MS_ABORT BIT6 +#define BLAST_COMPLETE BIT5 +#define SCSI_INTERRUPT BIT4 +#define DMA_XFER_DONE BIT3 +#define DMA_XFER_ABORT BIT2 +#define DMA_XFER_ERROR BIT1 +#define POWER_DOWN BIT0 + +/* +; DMA SCSI Bus and Ctrl.(+70H) +;EN_INT_ON_PCI_ABORT +*/ + +/* +;========================================================== +; SCSI Chip register address offset +;========================================================== +*/ +#define CtcReg_Low 0x00 +#define CtcReg_Mid 0x04 +#define ScsiFifo 0x08 +#define ScsiCmd 0x0C +#define Scsi_Status 0x10 +#define INT_Status 0x14 +#define Sync_Period 0x18 +#define Sync_Offset 0x1C +#define CtrlReg1 0x20 +#define Clk_Factor 0x24 +#define CtrlReg2 0x2C +#define CtrlReg3 0x30 +#define CtrlReg4 0x34 +#define CtcReg_High 0x38 +#define DMA_Cmd 0x40 +#define DMA_XferCnt 0x44 +#define DMA_XferAddr 0x48 +#define DMA_Wk_ByteCntr 0x4C +#define DMA_Wk_AddrCntr 0x50 +#define DMA_Status 0x54 +#define DMA_MDL_Addr 0x58 +#define DMA_Wk_MDL_Cntr 0x5C +#define DMA_ScsiBusCtrl 0x70 + +#define StcReg_Low CtcReg_Low +#define StcReg_Mid CtcReg_Mid +#define Scsi_Dest_ID Scsi_Status +#define Scsi_TimeOut INT_Status +#define Intern_State Sync_Period +#define Current_Fifo Sync_Offset +#define StcReg_High CtcReg_High + +#define am_target Scsi_Status +#define am_timeout INT_Status +#define am_seq_step Sync_Period +#define am_fifo_count Sync_Offset + + +#define DC390_read8(address) \ + inb(DC390_ioport + (address))) + +#define DC390_read16(address) \ + inw(DC390_ioport + (address))) + +#define DC390_read32(address) \ + inl(DC390_ioport + (address))) + +#define DC390_write8(address,value) \ + outb((value), DC390_ioport + (address))) + +#define DC390_write16(address,value) \ + outw((value), DC390_ioport + (address))) + +#define DC390_write32(address,value) \ + outl((value), DC390_ioport + (address))) + + +/* Configuration method #1 */ +#define PCI_CFG1_ADDRESS_REG 0xcf8 +#define PCI_CFG1_DATA_REG 0xcfc +#define PCI_CFG1_ENABLE 0x80000000 +#define PCI_CFG1_TUPPLE(bus, device, function, register) \ + (PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | \ + (((device) << 11) & 0xf800) | (((function) << 8) & 0x700)| \ + (((register) << 2) & 0xfc)) + +/* Configuration method #2 */ +#define PCI_CFG2_ENABLE_REG 0xcf8 +#define PCI_CFG2_FORWARD_REG 0xcfa +#define PCI_CFG2_ENABLE 0x0f0 +#define PCI_CFG2_TUPPLE(function) \ + (PCI_CFG2_ENABLE | (((function) << 1) & 0xe)) + + +#endif /* TEK390_H */ |