scsiiom.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,655 行 · 第 1/4 页

C
1,655
字号
/*********************************************************************** *	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 (struct dc390_dcb* pDCB, struct dc390_srb* pSRB){	if (pSRB->TagNumber < 255) {		pDCB->TagMask &= ~(1 << pSRB->TagNumber);   /* free tag mask */		pSRB->TagNumber = 255;	}}static u8dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ){    u8 cmd; u8  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;    }    /* 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",\	    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)      {	u8 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)      { 	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(pSRB->pcmd->sense_buffer));	    DC390_write8 (ScsiFifo, 0);	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));	  }	else	/* write cmnd to bus */ 	  {	    u8 *ptr; u8 i;	    ptr = (u8 *) 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->device->id, pSRB->pcmd->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;}//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/#define DMA_INT 0#if DMA_INT/* This is similar to AM53C974.c ... */static u8 dc390_dma_intr (struct dc390_acb* pACB){  struct dc390_srb* pSRB;  u8 dstate;  DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev);    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)    {	u32 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;}#endifstatic 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(int irq, void *dev_id, struct pt_regs *regs){    struct dc390_acb *pACB, *pACB2;    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;#if DMA_INT    u8  dstatus;#endif    pACB = (struct dc390_acb*)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 IRQ_NONE;    }        sstatus = DC390_read8 (Scsi_Status);    if( !(sstatus & INTERRUPT) )	return IRQ_NONE;    DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));#if DMA_INT    spin_lock_irq(pACB->pScsiHost->host_lock);    dstatus = dc390_dma_intr (pACB);    spin_unlock_irq(pACB->pScsiHost->host_lock);    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));    if (! (dstatus & SCSI_INTERRUPT))      {	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));	return IRQ_NONE;      }#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    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, struct pt_regs *regs){    irqreturn_t ret;    DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));    /* Locking is done in DC390_Interrupt */    ret = DC390_Interrupt(irq, dev_id, regs);    DEBUG1(printk (".. IRQ returned\n"));    return ret;}static voiddc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus){    u8   sstatus;    struct scatterlist *psgl;    u32    ResidCnt, xferCnt;    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++;		psgl = pSRB->pSegmentList;		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));	    }	    else		pSRB->SGToBeXferLen = 0;	}	else	{	    ResidCnt  = (u32) DC390_read8 (Current_Fifo) & 0x1f;	    ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16;	    ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; 	    ResidCnt += (u32) 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 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?