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 + -
显示快捷键?