📄 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 * ***********************************************************************//* $Id: scsiiom.c,v 2.55.2.17 2000/12/20 00:39:37 garloff Exp $ */static void __inline__dc390_freetag (PDCB pDCB, PSRB pSRB){ if (pSRB->TagNumber < 255) { pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */ pSRB->TagNumber = 255; }};UCHARdc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ){ UCHAR cmd; UCHAR disc_allowed, try_sync_nego; pSRB->ScsiPhase = SCSI_NOP0; if (pACB->Connected) { // Should not happen normally printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n", pSRB->SRBState, pSRB->SRBFlag); pSRB->SRBState = SRB_READY; pACB->SelConn++; return 1; } if (time_before (jiffies, pACB->pScsiHost->last_reset)) { DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n");) return 1; } DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); DC390_write8 (Sync_Period, pDCB->SyncPeriod); DC390_write8 (Sync_Offset, pDCB->SyncOffset); DC390_write8 (CtrlReg1, pDCB->CtrlR1); DC390_write8 (CtrlReg3, pDCB->CtrlR3); DC390_write8 (CtrlReg4, pDCB->CtrlR4); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ pSRB->pcmd->cmnd[0], pDCB->SyncMode);) disc_allowed = pDCB->DevMode & EN_DISCONNECT_; try_sync_nego = 0; /* Don't disconnect on AUTO_REQSENSE, cause it might be an * Contingent Allegiance Condition (6.6), where no tags should be used. * All other have to be allowed to disconnect to prevent Incorrect * Initiator Connection (6.8.2/6.5.2) */ /* Changed KG, 99/06/06 */ if( /*(((pSRB->pcmd->cmnd[0] == INQUIRY) || (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || * (pSRB->pcmd->cmnd[0] == TEST_UNIT_READY)) && pACB->scan_devices) ||*/ (pSRB->SRBFlag & AUTO_REQSENSE) ) disc_allowed = 0; if ( (pDCB->SyncMode & SYNC_ENABLE) && (pDCB->TargetLUN == 0) && (pDCB->Inquiry7 & 0x10) && ( ( ( (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) && !(pDCB->SyncMode & SYNC_NEGO_DONE) ) || (pSRB->pcmd->cmnd[0] == INQUIRY) ) ) try_sync_nego = 1; pSRB->MsgCnt = 0; cmd = SEL_W_ATN; DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN)); /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */ if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed) { UCHAR tag_no = 0; while ((1 << tag_no) & pDCB->TagMask) tag_no++; if (tag_no >= sizeof (pDCB->TagMask)*8 || tag_no >= pDCB->MaxCommand) { printk (KERN_WARNING "DC390: Out of tags for Dev. %02x %02x\n", pDCB->TargetID, pDCB->TargetLUN); return 1; //goto no_tag; }; DC390_write8 (ScsiFifo, SIMPLE_QUEUE_TAG); pDCB->TagMask |= (1 << tag_no); pSRB->TagNumber = tag_no; DC390_write8 (ScsiFifo, tag_no); DEBUG1(printk (KERN_DEBUG "DC390: Select w/DisCn for Cmd %li (SRB %p), Using Tag %02x\n", pSRB->pcmd->pid, pSRB, tag_no);) cmd = SEL_W_ATN3; } else /* No TagQ */ {// no_tag: DEBUG1(printk (KERN_DEBUG "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", (disc_allowed?"":"o"), pSRB->pcmd->pid, pSRB);) }; pSRB->SRBState = SRB_START_; if (try_sync_nego) { UCHAR Sync_Off = pDCB->SyncOffset; DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);) pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE; pSRB->MsgOutBuf[1] = 3; pSRB->MsgOutBuf[2] = EXTENDED_SDTR; pSRB->MsgOutBuf[3] = pDCB->NegoPeriod; if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET; pSRB->MsgOutBuf[4] = Sync_Off; pSRB->MsgCnt = 5; //pSRB->SRBState = SRB_MSGOUT_; pSRB->SRBState |= DO_SYNC_NEGO; cmd = SEL_W_ATN_STOP; }; /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ if (cmd != SEL_W_ATN_STOP) { if( pSRB->SRBFlag & AUTO_REQSENSE ) { DC390_write8 (ScsiFifo, REQUEST_SENSE); DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); DC390_write8 (ScsiFifo, 0); DC390_write8 (ScsiFifo, 0); DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); DC390_write8 (ScsiFifo, 0); DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");) } else /* write cmnd to bus */ { PUCHAR ptr; UCHAR i; ptr = (PUCHAR) pSRB->pcmd->cmnd; for (i=0; i<pSRB->pcmd->cmd_len; i++) DC390_write8 (ScsiFifo, *(ptr++)); }; } DEBUG0(if (pACB->pActiveDCB) \ printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) DEBUG0(if (pDCB->pActiveSRB) \ printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); if (DC390_read8 (Scsi_Status) & INTERRUPT) { dc390_freetag (pDCB, pSRB); DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);) pSRB->SRBState = SRB_READY; //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pACB->SelLost++; return 1; }; DC390_write8 (ScsiCmd, cmd); pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; pACB->Connected = 1; pSRB->ScsiPhase = SCSI_NOP1; return 0;}//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/#define DMA_INT 0#if DMA_INT/* This is similar to AM53C974.c ... */static UCHAR dc390_dma_intr (PACB pACB){ PSRB pSRB; UCHAR dstate; DEBUG0(USHORT pstate;PDEVDECL1;) DEBUG0(PDEVSET1;) DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);) DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\ { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \ PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};) dstate = DC390_read8 (DMA_Status); if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate; else pSRB = pACB->pActiveDCB->pActiveSRB; if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) { printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate); return dstate; }; if (dstate & DMA_XFER_DONE) { UINT residual, xferCnt; int ctr = 6000000; if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) { do { DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");) dstate = DC390_read8 (DMA_Status); residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 | DC390_read8 (CtcReg_High) << 16; residual += DC390_read8 (Current_Fifo) & 0x1f; } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr); if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); /* residual = ... */ } else residual = 0; /* ??? */ xferCnt = pSRB->SGToBeXferLen - residual; pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = residual;# ifdef DC390_DEBUG0 printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", (unsigned int)residual, (unsigned int)xferCnt);# endif DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; return dstate;};#endifvoid __inline__DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs){ PACB pACB, pACB2; PDCB pDCB; PSRB pSRB; UCHAR sstatus=0; UCHAR phase; void (*stateV)( PACB, PSRB, PUCHAR ); UCHAR istate, istatus;#if DMA_INT UCHAR dstatus;#endif DC390_AFLAGS DC390_IFLAGS //DC390_DFLAGS pACB = (PACB)dev_id; for (pACB2 = dc390_pACB_start; (pACB2 && pACB2 != pACB); pACB2 = pACB2->pNextACB); if (!pACB2) { printk ("DC390: IRQ called with foreign dev_id %p!\n", pACB); return; } //DC390_LOCK_DRV; sstatus = DC390_read8 (Scsi_Status); if( !(sstatus & INTERRUPT) ) { /*DC390_UNLOCK_DRV;*/ return; }; DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)#if DMA_INT DC390_LOCK_IO; DC390_LOCK_ACB; dstatus = dc390_dma_intr (pACB); DC390_UNLOCK_ACB; DC390_UNLOCK_IO; DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus);) if (! (dstatus & SCSI_INTERRUPT)) { DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");) //DC390_UNLOCK_DRV; return; };#else //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); //dstatus = DC390_read8 (DMA_Status); //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);#endif DC390_LOCK_IO; DC390_LOCK_ACB; //DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ istate = DC390_read8 (Intern_State); istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);) dc390_laststatus &= ~0x00ffffff; dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus; if (sstatus & ILLEGAL_OP_ERR) { printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus); dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); } else if (istatus & INVALID_CMD) { printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus); dc390_InvalidCmd( pACB ); goto unlock; } if (istatus & SCSI_RESET) { dc390_ScsiRstDetect( pACB ); goto unlock; } if (istatus & DISCONNECTED) { dc390_Disconnect( pACB ); goto unlock; } if (istatus & RESELECTED) { dc390_Reselect( pACB ); goto unlock; } else if (istatus & (SELECTED | SEL_ATTENTION)) { printk (KERN_ERR "DC390: Target mode not supported!\n"); goto unlock; } if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) { pDCB = pACB->pActiveDCB; if (!pDCB) { printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); goto unlock; }; pSRB = pDCB->pActiveSRB; if( pDCB->DCBFlag & ABORT_DEV_ ) dc390_EnableMsgOut_Abort (pACB, pSRB); phase = pSRB->ScsiPhase; DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);) stateV = (void *) dc390_phase0[phase]; ( *stateV )( pACB, pSRB, &sstatus ); pSRB->ScsiPhase = sstatus & 7; phase = (UCHAR) sstatus & 7; DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);) stateV = (void *) dc390_phase1[phase]; ( *stateV )( pACB, pSRB, &sstatus ); goto unlock; } unlock: //DC390_LOCK_DRV_NI; DC390_UNLOCK_ACB; DC390_UNLOCK_IO; //DC390_UNLOCK_DRV; /* Restore initial flags */}voiddo_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs){ DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);) /* Locking is done in DC390_Interrupt */ DC390_Interrupt(irq, dev_id, regs); DEBUG1(printk (".. IRQ returned\n");)}voiddc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ UCHAR sstatus; PSGL psgl; UINT ResidCnt, xferCnt; UCHAR dstate = 0; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) ) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { int ctr = 6000000; /* only try for about a second */ while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; pSRB->TotalXferredLen += pSRB->SGToBeXferLen; 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; } else { ResidCnt = (UINT) DC390_read8 (Current_Fifo) & 0x1f; ResidCnt |= (UINT) DC390_read8 (CtcReg_High) << 16; ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid) << 8; ResidCnt += (UINT) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = ResidCnt; } } if ((*psstatus & 7) != SCSI_DATA_OUT) { DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); } }voiddc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus){ UCHAR sstatus, residual, bval; PSGL psgl; UINT ResidCnt, i; ULONG xferCnt; PUCHAR ptr; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { int ctr = 6000000; /* only try for about a second */ int dstate = 0; while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ + ((ULONG) DC390_read8 (CtcReg_Low));) DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; if( pSRB->SGIndex < pSRB->SGcount ) { pSRB->pSegmentList++; psgl = pSRB->pSegmentList; pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -