⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsiiom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*********************************************************************** *	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 + -