📄 scsiio.c
字号:
/*********************************************************************** * FILE NAME : SCSIIO.C * * BY : C.L. Huang * * Description: Device Driver for Tekram DC-390W/U/F (T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/static voidPrepareSG( PACB pACB, PDCB pDCB, PSRB pSRB ){ ULONG retAddr,wlval; USHORT wval,i; PSGL psgl; PSGE psge; retAddr = pACB->jmp_table8; if(pDCB->DCBscntl3 & EN_WIDE_SCSI) retAddr += jmp_table16; wval = (USHORT)(pSRB->SGcount); wval <<= 4; /* 16 bytes per entry, datain=8, dataout=8 */ /* (4 bytes for count, 4 bytes for addr) */ retAddr -= (ULONG)wval; pSRB->ReturnAddr = retAddr; /* return address for SCRIPT */ if(wval) { wval >>= 1; wlval = (ULONG) pSRB->SegmentPad; wlval -= (ULONG)wval; wval >>= 3; psge = (PSGE) wlval; psgl = pSRB->pSegmentList; for(i=0; i<wval; i++) {#ifndef VERSION_ELF_1_2_13 psge->SGXPtr = virt_to_phys( psgl->address );#else psge->SGXPtr = (ULONG) psgl->address;#endif psge->SGXLen = psgl->length; psge++; psgl++; } }}static voidDC390W_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ){ USHORT ioport; UCHAR bval; pSRB->TagNumber = 31; ioport = pACB->IOPortBase; bval = SIGNAL_PROC; outb(bval,ioport+ISTAT); pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; return;}#ifndef VERSION_ELF_1_2_13static voidDC390W_Interrupt( int irq, void *dev_id, struct pt_regs *regs)#elsestatic voidDC390W_Interrupt( int irq, struct pt_regs *regs)#endif{ PACB pACB; PDCB pDCB; ULONG wlval; USHORT ioport = 0; USHORT wval, i; void (*stateV)( PACB ); UCHAR istat = 0; UCHAR bval; pACB = pACB_start; if( pACB == NULL ) return; for( i=0; i < adapterCnt; i++ ) { if( pACB->IRQLevel == (UCHAR) irq ) { ioport = pACB->IOPortBase; istat = inb( ioport+ISTAT ); if( istat & (ABORT_OP+SCSI_INT_PENDING+DMA_INT_PENDING) ) break; else pACB = pACB->pNextACB; } else { pACB = pACB->pNextACB; } } if( pACB == (PACB )-1 ) { printk("DC390W_intr: Spurious interrupt detected!\n"); return; }#ifdef DC390W_DEBUG1 printk("Istate=%2x,",istat);#endif /* if Abort operation occurred, reset abort bit before reading DMA status to prevent further aborted interrupt. */ if(istat & ABORT_OP) { istat &= ~ABORT_OP; outb(istat,ioport+ISTAT); } pDCB = pACB->pActiveDCB; bval = inb(ioport+CTEST2); /* Clear Signal Bit */ /* If Scsi Interrupt, then clear Interrupt Status by reading Scsi interrupt status register 0. */ wlval = 0; if(istat & SCSI_INT_PENDING) { wlval = (ULONG)inw( ioport+SIST0 ); wlval <<= 8; } /* If DMA Interrupt, then read the DMA status register to see what happen */ if(istat & DMA_INT_PENDING) { bval = inb(ioport+DSTAT); wlval |= (ULONG) bval; }#ifdef DC390W_DEBUG1 printk("IDstate=%8x,",(UINT) wlval);#endif if(wlval & ( (SEL_TIMEOUT << 16)+ ((SCSI_GERROR+UNEXPECT_DISC+SCSI_RESET) << 8)+ ILLEGAL_INSTRUC+ABORT_) ) { ExceptionHandler( wlval, pACB, pDCB ); } else if( wlval & SCRIPTS_INT ) { wval = inw( ioport+DSPS ); stateV = (void *) IntVector[wval]; stateV( pACB ); } else if( wlval & ( PARITY_ERROR << 8) ) ParityError( pACB, pDCB ); else if( wlval & ( PHASE_MISMATCH << 8) ) PhaseMismatch( pACB ); return;}static voidExceptionHandler(ULONG wlval, PACB pACB, PDCB pDCB){ PSRB pSRB; UCHAR bval; USHORT ioport;/* disconnect/scsi reset/illegal instruction */ ioport = pACB->IOPortBase; if(wlval & ( (SCSI_RESET+SCSI_GERROR) << 8) ) DC390W_ScsiRstDetect( pACB ); else if(wlval & ABORT_) {#ifdef DC390W_DEBUG0 printk("AboRst,");#endif if( !InitialTime ) DC390W_ResetSCSIBus2( pACB ); } else if(wlval & (SEL_TIMEOUT << 16) ) { pACB->status = SCSI_STAT_SEL_TIMEOUT;#ifdef DC390W_DEBUG1 printk("Selto,");#endif DC390W_CmdCompleted( pACB ); } else if(wlval & (UNEXPECT_DISC << 8) ) { bval = inb(ioport+STEST3); bval |= CLR_SCSI_FIFO; outb(bval,ioport+STEST3); bval = CLR_DMA_FIFO; outb(bval,ioport+CTEST3); pSRB = pDCB->pActiveSRB; if( pSRB->SRBState & DO_SYNC_NEGO ) { pDCB->DevMode &= ~SYNC_NEGO_; pACB->status = SCSI_STAT_CHECKCOND; DC390W_CmdCompleted( pACB ); } else if( pSRB->SRBState & DO_WIDE_NEGO ) { pDCB->DevMode &= ~WIDE_NEGO_; pACB->status = SCSI_STAT_CHECKCOND; DC390W_CmdCompleted( pACB ); } else { pACB->status = SCSI_STAT_UNEXP_BUS_F; DC390W_CmdCompleted( pACB ); }#ifdef DC390W_DEBUG0 printk("Uxpbf,");#endif } else {#ifdef DC390W_DEBUG0 printk("Except,");#endif DC390W_ResetSCSIBus( pACB ); }}static voidParityError( PACB pACB, PDCB pDCB ){ ULONG ioport; UCHAR bval,msg; ULONG wlval; PSRB pSRB; ioport = pACB->IOPortBase; bval = inb(ioport+SCRATCHA); if(bval & RE_SELECTED_) {#ifdef DC390W_DEBUG0 printk("ParityErr,");#endif DC390W_ResetSCSIBus( pACB ); return; } else { pSRB = pDCB->pActiveSRB; bval = inb(ioport+STEST3); bval |= CLR_SCSI_FIFO; outb(bval,ioport+STEST3); bval = CLR_DMA_FIFO; outb(bval,ioport+CTEST3); bval = inb(ioport+DCMD); bval &= 0x07; /* get phase bits */ if(bval == 0x07) /* message in phase */ { msg = MSG_PARITY_ERROR; wlval = pACB->jmp_clear_ack; } else { msg = MSG_INITIATOR_ERROR; wlval = pACB->jmp_next; } pSRB->__msgout0[0] = 1; pSRB->MsgOutBuf[0] = msg; outl(wlval,(ioport+DSP)); return; }}static voidDC390W_Signal( PACB pACB ){ PDCB pDCB; PSRB pSRB; USHORT ioport; ULONG wlval, flags; UCHAR bval,msgcnt,tagnum; save_flags(flags); cli(); ioport = pACB->IOPortBase; pDCB = pACB->pActiveDCB; pSRB = pDCB->pActiveSRB;#ifdef DC390W_DEBUG0 printk("Signal,Cmd=%2x", pSRB->CmdBlock[0]);#endif wlval = pSRB->PhysSRB; outl(wlval,(ioport+DSA)); wlval = pSRB->ReturnAddr; outl(wlval,(ioport+TEMP)); msgcnt = 1; bval = pDCB->IdentifyMsg; pSRB->MsgOutBuf[0] = bval; if( (pSRB->CmdBlock[0] != INQUIRY) && (pSRB->CmdBlock[0] != REQUEST_SENSE) ) { if(pDCB->MaxCommand > 1) { wlval = 1; tagnum = 0; while( wlval & pDCB->TagMask ) { wlval = wlval << 1; tagnum++; } pDCB->TagMask |= wlval; pSRB->TagNumber = tagnum; pSRB->MsgOutBuf[1] = MSG_SIMPLE_QTAG; pSRB->MsgOutBuf[2] = tagnum; msgcnt = 3; } } else { pSRB->MsgOutBuf[0] &= 0xBF; /* Diable Disconnected */ if(pSRB->CmdBlock[0] == INQUIRY) { if(bval & 0x07) goto type_6_3; } if(pDCB->DevMode & WIDE_NEGO_) { msgcnt = 5; *((PULONG) &(pSRB->MsgOutBuf[1])) = 0x01030201; pSRB->SRBState |= DO_WIDE_NEGO; } else if(pDCB->DevMode & SYNC_NEGO_) { msgcnt = 6; *((PULONG) &(pSRB->MsgOutBuf[1])) = 0x00010301; pSRB->MsgOutBuf[4] = pDCB->NegoPeriod; pSRB->MsgOutBuf[5] = SYNC_NEGO_OFFSET; pSRB->SRBState |= DO_SYNC_NEGO; } }type_6_3: pSRB->__msgout0[0] = (ULONG) msgcnt; wlval = 0; outl(wlval,(ioport+SCRATCHA)); bval = pDCB->DCBscntl0; outb(bval,ioport+SCNTL0); pSRB->__select = *((PULONG) &(pDCB->DCBselect));#ifdef DC390W_DEBUG0 printk("__sel=%8x,", (UINT)(pSRB->__select));#endif wlval = pACB->jmp_select; outl(wlval,(ioport+DSP)); restore_flags(flags); return;}static voidDC390W_MessageWide( PACB pACB ){ PDCB pDCB; PSRB pSRB; PUCHAR msgoutPtr; USHORT ioport; ULONG wlval; UCHAR bval,msgcnt;#ifdef DC390W_DEBUG0 printk("MsgWide,");#endif ioport = pACB->IOPortBase; pDCB = pACB->pActiveDCB; pSRB = pDCB->pActiveSRB; msgcnt = 0; pDCB->DCBscntl3 &= ~EN_WIDE_SCSI; msgoutPtr = pSRB->MsgOutBuf; if( pSRB->SRBState & DO_WIDE_NEGO ) { pSRB->SRBState &= ~DO_WIDE_NEGO; if( pACB->msgin123[0] == 3 ) { bval = pACB->msgin123[1]; if(bval == 1) { pDCB->DCBscntl3 |= EN_WIDE_SCSI; goto x5; } if(bval < 1) goto x5; } }/*type_11_1:*/ msgcnt = 1; *msgoutPtr = MSG_REJECT_; msgoutPtr++;x5: bval = pDCB->DCBscntl3; outb(bval,ioport+SCNTL3); AdjustTemp(pACB,pDCB,pSRB); SetXferRate(pACB,pDCB); if( pDCB->DevMode & SYNC_NEGO_ ) { *((PULONG)msgoutPtr) = 0x00010301; *(msgoutPtr + 3) = pDCB->NegoPeriod; *(msgoutPtr + 4) = SYNC_NEGO_OFFSET; msgcnt += 5; pSRB->SRBState |= DO_SYNC_NEGO; } pSRB->__msgout0[0] = (ULONG) msgcnt; wlval = pACB->jmp_clear_ack; if(msgcnt) wlval = pACB->jmp_set_atn; outl(wlval,(ioport+DSP)); return;}static voidDC390W_MessageSync( PACB pACB ){ PDCB pDCB; PSRB pSRB; USHORT ioport; ULONG wlval; USHORT wval,wval1; UCHAR bval,bval1;#ifdef DC390W_DEBUG0 printk("MsgSync,");#endif ioport = pACB->IOPortBase; pDCB = pACB->pActiveDCB; pSRB = pDCB->pActiveSRB; if( !(pSRB->SRBState & DO_SYNC_NEGO) ) goto MessageExtnd; pSRB->SRBState &= ~DO_SYNC_NEGO; if(pACB->msgin123[0] != 1) {MessageExtnd: pSRB->__msgout0[0] = 1; pSRB->MsgOutBuf[0] = MSG_REJECT_; wlval = pACB->jmp_set_atn; outl(wlval,(ioport+DSP)); return; } bval = pACB->msgin123[2]; /* offset */asyncx: pDCB->DCBsxfer = bval; if(bval == 0) /* if offset or period == 0, async */ { if( pACB->AdaptType == DC390W ) bval = SYNC_CLK_F2+ASYNC_CLK_F2; else bval = SYNC_CLK_F4+ASYNC_CLK_F4; pDCB->DCBscntl3 = bval; } else { bval = pACB->msgin123[1]; if(bval == 0) goto asyncx; pDCB->SyncPeriod = bval; wval = (USHORT)bval; wval <<= 3; bval = pDCB->DCBscntl3; bval &= 0x0f; if(wval < 200) /* < 100 ns ==> Fast-20 */ { bval |= 0x90; /* Fast-20 and div 1 */ bval1 = 25; /* 12.5 ns */ } else if(wval < 400) { bval |= 0x30; /* 1 cycle = 25ns */ bval1 = 50; } else /* Non Fast */ { bval |= 0x50; /* 1 cycle = 50ns */ bval1 = 100; } if( pACB->AdaptType == DC390W ) bval -= 0x20; /* turn down to 40Mhz scsi clock */ /* assume 390W will not receive fast-20 */ wval1 = wval; wval /= bval1; if(wval * bval1 < wval1) wval++; /* XFERP TP2 TP1 TP0 */ wval -= 4; /* 4 0 0 0 */ /* 5 0 0 1 */ wval <<= 5; pDCB->DCBsxfer |= (UCHAR)wval; pDCB->DCBscntl3 = bval; }/*sync_2:*/ SetXferRate( pACB,pDCB ); wlval = pACB->jmp_clear_ack;/*sync_3:*/ bval = pDCB->DCBscntl3; outb(bval,ioport+SCNTL3); bval = pDCB->DCBsxfer; outb(bval,ioport+SXFER); outl(wlval,(ioport+DSP)); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -