📄 scsiiom.c
字号:
else pSRB->SGToBeXferLen = 0; } else /* phase changed */ { residual = 0; bval = DC390_read8 (Current_Fifo); while( bval & 0x1f ) { DEBUG1(printk (KERN_DEBUG "Check for residuals,");) if( (bval & 0x1f) == 1 ) { for(i=0; i < 0x100; i++) { bval = DC390_read8 (Current_Fifo); if( !(bval & 0x1f) ) goto din_1; else if( i == 0x0ff ) { residual = 1; /* ;1 residual byte */ goto din_1; } } } else bval = DC390_read8 (Current_Fifo); }din_1: DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD); for (i = 0xa000; i; i--) { bval = DC390_read8 (DMA_Status); if (bval & BLAST_COMPLETE) break; } /* It seems a DMA Blast abort isn't that bad ... */ if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval);) ResidCnt = (UINT) DC390_read8 (CtcReg_High); ResidCnt <<= 8; ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid); ResidCnt <<= 8; ResidCnt |= (UINT) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = ResidCnt; if( residual ) { bval = DC390_read8 (ScsiFifo); /* get one residual byte */ ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr ); *ptr = bval; pSRB->SGBusAddr++; xferCnt++; pSRB->TotalXferredLen++; pSRB->SGToBeXferLen--; } DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\ pSRB->TotalXferredLen, pSRB->SGToBeXferLen);) } } if ((*psstatus & 7) != SCSI_DATA_IN) { DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ } }static voiddc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){}static voiddc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ pSRB->TargetStatus = DC390_read8 (ScsiFifo); //udelay (1); pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */ *psstatus = SCSI_NOP0; pSRB->SRBState = SRB_COMPLETED; DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);}static voiddc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) *psstatus = SCSI_NOP0; //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);}static void __inline__dc390_reprog (PACB pACB, PDCB pDCB){ DC390_write8 (Sync_Period, pDCB->SyncPeriod); DC390_write8 (Sync_Offset, pDCB->SyncOffset); DC390_write8 (CtrlReg3, pDCB->CtrlR3); DC390_write8 (CtrlReg4, pDCB->CtrlR4); dc390_SetXferRate (pACB, pDCB);};#ifdef DC390_DEBUG0static voiddc390_printMsg (UCHAR *MsgBuf, UCHAR len){ int i; printk (" %02x", MsgBuf[0]); for (i = 1; i < len; i++) printk (" %02x", MsgBuf[i]); printk ("\n");};#endif#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)/* reject_msg */static void __inline__dc390_MsgIn_reject (PACB pACB, PSRB pSRB){ pSRB->MsgOutBuf[0] = MESSAGE_REJECT; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");)}/* abort command */static void __inline__dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ){ pSRB->MsgOutBuf[0] = ABORT; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;}static PSRBdc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag){ PSRB lastSRB = pDCB->pGoingLast; PSRB pSRB = pDCB->pGoingSRB; if (pSRB) { for( ;pSRB ; ) { if (pSRB->TagNumber == tag) break; if (pSRB == lastSRB) goto mingx0; pSRB = pSRB->pNextSRB; } if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; dc390_EnableMsgOut_Abort( 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] = ABORT_TAG; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; } return pSRB;}/* set async transfer mode */static void dc390_MsgIn_set_async (PACB pACB, PSRB pSRB){ PDCB pDCB = pSRB->pSRBDCB; if (!(pSRB->SRBState & DO_SYNC_NEGO)) printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID); pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ pDCB->CtrlR4 &= 0x3f; pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ dc390_reprog (pACB, pDCB);}/* set sync transfer mode */static voiddc390_MsgIn_set_sync (PACB pACB, PSRB pSRB){ UCHAR bval; USHORT wval, wval1; PDCB pDCB = pSRB->pSRBDCB; UCHAR oldsyncperiod = pDCB->SyncPeriod; UCHAR oldsyncoffset = pDCB->SyncOffset; if (!(pSRB->SRBState & DO_SYNC_NEGO)) { printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); /* reject */ //dc390_MsgIn_reject (pACB, pSRB); //return dc390_MsgIn_set_async (pACB, pSRB); /* Reply with corrected SDTR Message */ if (pSRB->MsgInBuf[4] > 15) { printk (KERN_INFO "DC390: Lower Sync Offset to 15\n"); pSRB->MsgInBuf[4] = 15; } if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) { printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); pSRB->MsgInBuf[3] = pDCB->NegoPeriod; }; memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); pSRB->MsgCnt = 5; DC390_ENABLE_MSGOUT; }; pSRB->SRBState &= ~DO_SYNC_NEGO; 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 -= 3; wval1 = wval / 25; /* compute speed */ if( (wval1 * 25) != wval) wval1++; bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */ pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ if (pACB->glitch_cfg != NS_TO_GLITCH(0)) pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); else pDCB->CtrlR4 |= NS_TO_GLITCH(0); if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ if (wval1 >= 8) { wval1--; /* Timing computation differs by 1 from FAST_SCSI */ bval = FAST_CLK; /* fast clock / normal scsi */ pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ } pDCB->CtrlR3 = bval; pDCB->SyncPeriod = (UCHAR)wval1; if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0) { if (! (bval & FAST_SCSI)) wval1++; printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f); } dc390_reprog (pACB, pDCB);};/* handle RESTORE_PTR */static void dc390_restore_ptr (PACB pACB, PSRB pSRB){ PSGL psgl; pSRB->TotalXferredLen = 0; pSRB->SGIndex = 0; if( pSRB->pcmd->use_sg ) { pSRB->SGcount = (UCHAR) pSRB->pcmd->use_sg; pSRB->pSegmentList = (PSGL) pSRB->pcmd->request_buffer; psgl = pSRB->pSegmentList; while (pSRB->TotalXferredLen + (ULONG) psgl->length < pSRB->Saved_Ptr) { pSRB->TotalXferredLen += (ULONG) psgl->length; pSRB->SGIndex++; if( pSRB->SGIndex < pSRB->SGcount ) { pSRB->pSegmentList++; psgl = pSRB->pSegmentList; pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; } else pSRB->SGToBeXferLen = 0; } pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen); pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen); printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); } else if( pSRB->pcmd->request_buffer ) { pSRB->SGcount = 1; pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; pSRB->Segmentx.address = (PUCHAR) pSRB->pcmd->request_buffer + pSRB->Saved_Ptr; pSRB->Segmentx.length = pSRB->pcmd->request_bufflen - pSRB->Saved_Ptr; printk (KERN_INFO "DC390: Pointer restored. Total %li, Bus %p\n", pSRB->Saved_Ptr, pSRB->Segmentx.address); } else { pSRB->SGcount = 0; printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); }; pSRB->TotalXferredLen = pSRB->Saved_Ptr;};/* According to the docs, the AM53C974 reads the message and * generates a Succesful Operation IRQ before asserting ACK for * the last byte (how does it know whether it's the last ?) *//* The old code handled it in another way, indicating, that on * every message byte an IRQ is generated and every byte has to * be manually ACKed. Hmmm ? (KG, 98/11/28) *//* The old implementation was correct. Sigh! *//* Check if the message is complete */static UCHAR __inline__dc390_MsgIn_complete (UCHAR *msgbuf, UINT len){ if (*msgbuf == EXTENDED_MESSAGE) { if (len < 2) return 0; if (len < msgbuf[1] + 2) return 0; } else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages if (len < 2) return 0; return 1;}/* read and eval received messages */voiddc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ PDCB pDCB = pACB->pActiveDCB; /* Read the msg */ pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo); //pSRB->SRBState = 0; /* Msg complete ? */ if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen)) { DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen);) /* Now eval the msg */ switch (pSRB->MsgInBuf[0]) { case DISCONNECT: pSRB->SRBState = SRB_DISCONNECT; break; case SIMPLE_QUEUE_TAG: case HEAD_OF_QUEUE_TAG: case ORDERED_QUEUE_TAG: pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]); break; case MESSAGE_REJECT: DC390_write8 (ScsiCmd, RESET_ATN_CMD); pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ if( pSRB->SRBState & DO_SYNC_NEGO) dc390_MsgIn_set_async (pACB, pSRB); break; case EXTENDED_MESSAGE: /* reject every extended msg but SDTR */ if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) dc390_MsgIn_reject (pACB, pSRB); else { if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0) dc390_MsgIn_set_async (pACB, pSRB); else dc390_MsgIn_set_sync (pACB, pSRB); }; // nothing has to be done case COMMAND_COMPLETE: break; // SAVE POINTER may be ignored as we have the PSRB associated with the // scsi command. Thanks, Gerard, for pointing it out. case SAVE_POINTERS: pSRB->Saved_Ptr = pSRB->TotalXferredLen; break; // The device might want to restart transfer with a RESTORE case RESTORE_POINTERS: DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n");) dc390_restore_ptr (pACB, pSRB); break; // reject unknown messages default: dc390_MsgIn_reject (pACB, pSRB); } /* Clear counter and MsgIn state */ pSRB->SRBState &= ~SRB_MSGIN; pACB->MsgLen = 0; }; *psstatus = SCSI_NOP0; DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);}voiddc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir){ PSGL psgl; ULONG lval; PDCB pDCB = pACB->pActiveDCB; if (pSRB == pACB->pTmpSRB) { if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); dc390_EnableMsgOut_Abort (pACB, pSRB); if (pDCB) pDCB->DCBFlag |= ABORT_DEV; return; } if( pSRB->SGIndex < pSRB->SGcount ) { DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; pSRB->SGBusAddr = virt_to_bus( psgl->address );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -