tmscsim.c
来自「linux 内核源代码」· C语言 代码 · 共 2,146 行 · 第 1/5 页
C
2,146 行
static struct scatterlist* dc390_sg_build_single(struct scatterlist *sg, void *addr, unsigned int length){ sg_init_one(sg, addr, length); return sg;}/* Create pci mapping */static int dc390_pci_map (struct dc390_srb* pSRB){ int error = 0; struct scsi_cmnd *pcmd = pSRB->pcmd; struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev; dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp)); /* Map sense buffer */ if (pSRB->SRBFlag & AUTO_REQSENSE) { pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer)); pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, 1, DMA_FROM_DEVICE); cmdp->saved_dma_handle = sg_dma_address(pSRB->pSegmentList); /* TODO: error handling */ if (pSRB->SGcount != 1) error = 1; DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle)); /* Map SG list */ } else if (scsi_sg_count(pcmd)) { int nseg; nseg = scsi_dma_map(pcmd); pSRB->pSegmentList = scsi_sglist(pcmd); pSRB->SGcount = nseg; /* TODO: error handling */ if (nseg < 0) error = 1; DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\ __FUNCTION__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd))); /* Map single segment */ } else pSRB->SGcount = 0; return error;}/* Remove pci mapping */static void dc390_pci_unmap (struct dc390_srb* pSRB){ struct scsi_cmnd *pcmd = pSRB->pcmd; struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev; DEBUG1(dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp))); if (pSRB->SRBFlag) { pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE); DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle)); } else { scsi_dma_unmap(pcmd); DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", __FUNCTION__, scsi_sglist(pcmd), scsi_sg_count(pcmd))); }}static void __inline__dc390_freetag (struct dc390_dcb* pDCB, struct dc390_srb* pSRB){ if (pSRB->TagNumber != SCSI_NO_TAG) { pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */ pSRB->TagNumber = SCSI_NO_TAG; }}static intdc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ){ struct scsi_cmnd *scmd = pSRB->pcmd; struct scsi_device *sdev = scmd->device; u8 cmd, disc_allowed, try_sync_nego; char tag[2]; 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; } /* KG: Moved pci mapping here */ dc390_pci_map(pSRB); /* TODO: error handling */ 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",\ scmd->cmnd[0], pDCB->SyncMode)); /* 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->SRBFlag & AUTO_REQSENSE)) disc_allowed = pDCB->DevMode & EN_DISCONNECT_; else disc_allowed = 0; if ((pDCB->SyncMode & SYNC_ENABLE) && pDCB->TargetLUN == 0 && sdev->sdtr && (((scmd->cmnd[0] == REQUEST_SENSE || (pSRB->SRBFlag & AUTO_REQSENSE)) && !(pDCB->SyncMode & SYNC_NEGO_DONE)) || scmd->cmnd[0] == INQUIRY)) try_sync_nego = 1; else try_sync_nego = 0; 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 && scsi_populate_tag_msg(scmd, tag)) { DC390_write8(ScsiFifo, tag[0]); pDCB->TagMask |= 1 << tag[1]; pSRB->TagNumber = tag[1]; DC390_write8(ScsiFifo, tag[1]); DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1])); cmd = SEL_W_ATN3; } else { /* No TagQ *///no_tag: DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB)); } pSRB->SRBState = SRB_START_; if (try_sync_nego) { u8 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(scmd->sense_buffer)); DC390_write8 (ScsiFifo, 0); DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n")); } else /* write cmnd to bus */ { u8 *ptr; u8 i; ptr = (u8 *)scmd->cmnd; for (i = 0; i < scmd->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", scmd->serial_number, scmd->device->id, scmd->device->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;}static void __inline__dc390_InvalidCmd(struct dc390_acb* pACB){ if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ | SRB_MSGOUT)) DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);}static irqreturn_t __inline__DC390_Interrupt(void *dev_id){ struct dc390_acb *pACB = dev_id; struct dc390_dcb *pDCB; struct dc390_srb *pSRB; u8 sstatus=0; u8 phase; void (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *); u8 istate, istatus; sstatus = DC390_read8 (Scsi_Status); if( !(sstatus & INTERRUPT) ) return IRQ_NONE; DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus)); //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); spin_lock_irq(pACB->pScsiHost->host_lock); 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 = (u8) 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 ); } unlock: spin_unlock_irq(pACB->pScsiHost->host_lock); return IRQ_HANDLED;}static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id){ irqreturn_t ret; DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq)); /* Locking is done in DC390_Interrupt */ ret = DC390_Interrupt(dev_id); DEBUG1(printk (".. IRQ returned\n")); return ret;}static voiddc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus){ u8 sstatus; u32 ResidCnt; u8 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 ) { unsigned long timeout = jiffies + HZ; /* Function called from the ISR with the host_lock held and interrupts disabled */ if (pSRB->SGToBeXferLen) while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) { spin_unlock_irq(pACB->pScsiHost->host_lock); udelay(50); spin_lock_irq(pACB->pScsiHost->host_lock); } if (!time_before(jiffies, timeout)) 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++; dc390_start_segment(pSRB); } else pSRB->SGToBeXferLen = 0; } else { ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) + (((u32) DC390_read8 (CtcReg_High) << 16) | ((u32) DC390_read8 (CtcReg_Mid) << 8) | (u32) DC390_read8 (CtcReg_Low)); dc390_advance_segment(pSRB, ResidCnt); } } if ((*psstatus & 7) != SCSI_DATA_OUT) { DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); } }static voiddc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus){ u8 sstatus, residual, bval; u32 ResidCnt, i; unsigned long xferCnt; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { int dstate = 0; unsigned long timeout = jiffies + HZ; /* Function called from the ISR with the host_lock held and interrupts disabled */ if (pSRB->SGToBeXferLen) while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) { spin_unlock_irq(pACB->pScsiHost->host_lock); udelay(50); spin_lock_irq(pACB->pScsiHost->host_lock); } if (!time_before(jiffies, timeout)) { printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); } dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \ + ((unsigned long) DC390_read8 (CtcReg_Mid) << 8) \ + ((unsigned long) DC390_read8 (CtcReg_Low))); DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen)); DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; if( pSRB->SGIndex < pSRB->SGcount ) { pSRB->pSegmentList++; dc390_start_segment(pSRB); } else pSRB->SGToBeXferLen = 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?