📄 scsiiom.c
字号:
/*********************************************************************** * 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 USHORTDC390_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(pSRB->pcmd->sense_buffer); 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 );}#ifndef VERSION_ELF_1_2_13static voidDC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)#elsestatic voidDC390_Interrupt( int irq, struct pt_regs *regs)#endif{ PACB pACB; PDCB pDCB; PSRB pSRB; USHORT ioport = 0; USHORT phase, i; void (*stateV)( PACB, PSRB, PUCHAR ); UCHAR istate = 0; UCHAR sstatus=0, istatus; pACB = pACB_start; if( pACB == NULL ) return; for( i=0; i < adapterCnt; i++ ) { if( pACB->IRQLevel == (UCHAR) irq ) { ioport = pACB->IOPortBase; sstatus = inb( ioport+Scsi_Status ); if( sstatus & INTERRUPT ) break; else pACB = pACB->pNextACB; } else { pACB = pACB->pNextACB; } }#ifdef DC390_DEBUG1 printk("sstatus=%2x,",sstatus);#endif if( pACB == (PACB )-1 ) { printk("DC390: Spurious interrupt detected!\n"); return; } istate = inb( ioport+Intern_State ); istatus = inb( ioport+INT_Status );#ifdef DC390_DEBUG1 printk("Istatus=%2x,",istatus);#endif if(istatus & DISCONNECTED) { DC390_Disconnect( pACB ); return; } if(istatus & RESELECTED) { DC390_Reselect( pACB ); return; } if(istatus & INVALID_CMD) { DC390_InvalidCmd( pACB ); return; } if(istatus & SCSI_RESET) { DC390_ScsiRstDetect( pACB ); return; } 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 ); }}static voidDC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ UCHAR sstatus, bval; USHORT ioport; PSGL 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;#ifndef VERSION_ELF_1_2_13 pSRB->SGPhysAddr = virt_to_phys( psgl->address );#else pSRB->SGPhysAddr = (ULONG) psgl->address;#endif pSRB->SGToBeXferLen = (ULONG) psgl->length; } 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 voidDC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ UCHAR sstatus, bval; USHORT i, ioport, residual; PSGL 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;#ifndef VERSION_ELF_1_2_13 pSRB->SGPhysAddr = virt_to_phys( psgl->address );#else pSRB->SGPhysAddr = (ULONG) psgl->address;#endif pSRB->SGToBeXferLen = (ULONG) psgl->length; } 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 */#ifndef VERSION_ELF_1_2_13 ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );#else ptr = (PUCHAR) pSRB->SGPhysAddr;#endif *ptr = bval; pSRB->SGPhysAddr++; pSRB->TotalXferredLen++; pSRB->SGToBeXferLen--; } } }}static voidDC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){}static voidDC390_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 voidDC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) *psstatus = SCSI_NOP0;}static voidDC390_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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -