All of lore.kernel.org
 help / color / mirror / Atom feed
From: Christoph Hellwig <hch@lst.de>
To: g.liakhovetski@gmx.de, jejb@steeleye.com
Cc: linux-scsi@vger.kernel.org
Subject: [PATCH] merge scsiiom.c into tmscsim.c
Date: Sun, 3 Oct 2004 15:47:14 +0200	[thread overview]
Message-ID: <20041003134714.GA1623@lst.de> (raw)

might be a good time to get rid of that clumsy include .c file into
another one thing.  (Also please bk rm scsiiom.c afterwards)


--- 1.56/drivers/scsi/tmscsim.c	2004-10-03 15:43:04 +02:00
+++ edited/drivers/scsi/tmscsim.c	2004-10-03 15:48:31 +02:00
@@ -252,7 +252,7 @@
 
 #include "tmscsim.h"
 
-static int dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB );
+
 static void dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
 static void dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
 static void dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
@@ -272,11 +272,10 @@
 static void dc390_Disconnect( struct dc390_acb* pACB );
 static void dc390_Reselect( struct dc390_acb* pACB );
 static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB );
-static void dc390_DoingSRB_Done( struct dc390_acb* pACB, struct scsi_cmnd * cmd);
 static void dc390_ScsiRstDetect( struct dc390_acb* pACB );
-static void dc390_ResetSCSIBus( struct dc390_acb* pACB );
 static void dc390_EnableMsgOut_Abort(struct dc390_acb*, struct dc390_srb*);
-static irqreturn_t do_DC390_Interrupt( int, void *, struct pt_regs *);
+static void dc390_dumpinfo(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB);
+static void dc390_ResetDevParam(struct dc390_acb* pACB);
 
 static u32	dc390_laststatus = 0;
 static u8	dc390_adapterCnt = 0;
@@ -482,6 +481,1500 @@
 	}
 }
 
+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 int
+dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB )
+{
+    struct scsi_device *sdev = pSRB->pcmd->device;
+    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) && sdev->sdtr &&
+	( ( ( (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)
+      {
+	s8 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;
+}
+#endif
+
+
+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(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct dc390_acb *pACB = (struct dc390_acb*)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;
+#if DMA_INT
+    u8  dstatus;
+#endif
+
+    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 void
+dc390_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 */
+	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    }	    
+}
+
+static void
+dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    u8   sstatus, residual, bval;
+    struct scatterlist *psgl;
+    u32    ResidCnt, i;
+    unsigned long   xferCnt;
+    u8      *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 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=%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 = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
+		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else	/* phase changed */
+	{
+	    residual = 0;
+	    bval = DC390_read8 (Current_Fifo);
+	    while( bval & 0x1f )
+	    {
+		DEBUG1(printk (KERN_DEBUG "Check for residuals,"));
+		if( (bval & 0x1f) == 1 )
+		{
+		    for(i=0; i < 0x100; i++)
+		    {
+			bval = DC390_read8 (Current_Fifo);
+			if( !(bval & 0x1f) )
+			    goto din_1;
+			else if( i == 0x0ff )
+			{
+			    residual = 1;   /* ;1 residual byte */
+			    goto din_1;
+			}
+		    }
+		}
+		else
+		    bval = DC390_read8 (Current_Fifo);
+	    }
+din_1:
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
+	    for (i = 0xa000; i; i--)
+	    {
+		bval = DC390_read8 (DMA_Status);
+		if (bval & BLAST_COMPLETE)
+		    break;
+	    }
+	    /* It seems a DMA Blast abort isn't that bad ... */
+	    if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
+	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
+
+	    DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
+	    ResidCnt = (u32) DC390_read8 (CtcReg_High);
+	    ResidCnt <<= 8;
+	    ResidCnt |= (u32) DC390_read8 (CtcReg_Mid);
+	    ResidCnt <<= 8;
+	    ResidCnt |= (u32) DC390_read8 (CtcReg_Low);
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGBusAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+
+	    if( residual )
+	    {
+		bval = DC390_read8 (ScsiFifo);	    /* get one residual byte */
+		ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr );
+		*ptr = bval;
+		pSRB->SGBusAddr++; xferCnt++;
+		pSRB->TotalXferredLen++;
+		pSRB->SGToBeXferLen--;
+	    }
+	    DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
+
+	}
+    }
+    if ((*psstatus & 7) != SCSI_DATA_IN)
+    {
+	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+    }
+}
+
+static void
+dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+}
+
+static void
+dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+
+    pSRB->TargetStatus = DC390_read8 (ScsiFifo);
+    //udelay (1);
+    pSRB->EndMessage = DC390_read8 (ScsiFifo);	/* get message */
+
+    *psstatus = SCSI_NOP0;
+    pSRB->SRBState = SRB_COMPLETED;
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+}
+
+static void
+dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
+	*psstatus = SCSI_NOP0;
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+
+static void __inline__
+dc390_reprog (struct dc390_acb* pACB, struct dc390_dcb* pDCB)
+{
+  DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+  DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+  DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+  DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+  dc390_SetXferRate (pACB, pDCB);
+}
+
+
+#ifdef DC390_DEBUG0
+static void
+dc390_printMsg (u8 *MsgBuf, u8 len)
+{
+  int i;
+  printk (" %02x", MsgBuf[0]);
+  for (i = 1; i < len; i++)
+    printk (" %02x", MsgBuf[i]);
+  printk ("\n");
+}
+#endif
+
+#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)
+
+/* reject_msg */
+static void __inline__
+dc390_MsgIn_reject (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+  pSRB->MsgOutBuf[0] = MESSAGE_REJECT;
+  pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+  DEBUG0 (printk (KERN_INFO "DC390: Reject message\n"));
+}
+
+/* abort command */
+static void
+dc390_EnableMsgOut_Abort ( struct dc390_acb* pACB, struct dc390_srb* pSRB )
+{
+    pSRB->MsgOutBuf[0] = ABORT; 
+    pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
+}
+
+static struct dc390_srb*
+dc390_MsgIn_QTag (struct dc390_acb* pACB, struct dc390_dcb* pDCB, s8 tag)
+{
+  struct dc390_srb* lastSRB = pDCB->pGoingLast;
+  struct dc390_srb* pSRB = pDCB->pGoingSRB;
+
+  if (pSRB)
+    {
+      for( ;pSRB ; )
+	{
+	  if (pSRB->TagNumber == tag) break;
+	  if (pSRB == lastSRB) goto mingx0;
+	  pSRB = pSRB->pNextSRB;
+	}
+
+      if( pDCB->DCBFlag & ABORT_DEV_ )
+	{
+	  pSRB->SRBState = SRB_ABORT_SENT;
+	  dc390_EnableMsgOut_Abort( pACB, pSRB );
+	}
+
+      if( !(pSRB->SRBState & SRB_DISCONNECT) )
+	goto  mingx0;
+
+      pDCB->pActiveSRB = pSRB;
+      pSRB->SRBState = SRB_DATA_XFER;
+    }
+  else
+    {
+    mingx0:
+      pSRB = pACB->pTmpSRB;
+      pSRB->SRBState = SRB_UNEXPECT_RESEL;
+      pDCB->pActiveSRB = pSRB;
+      pSRB->MsgOutBuf[0] = ABORT_TAG;
+      pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    }
+  return pSRB;
+}
+
+
+/* set async transfer mode */
+static void 
+dc390_MsgIn_set_async (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+  struct dc390_dcb* pDCB = pSRB->pSRBDCB;
+  if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+    printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID);
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+  pDCB->SyncPeriod = 0;
+  pDCB->SyncOffset = 0;
+  //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+  pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
+  pDCB->CtrlR4 &= 0x3f;
+  pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+  dc390_reprog (pACB, pDCB);
+}
+
+/* set sync transfer mode */
+static void
+dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+  u8 bval;
+  u16 wval, wval1;
+  struct dc390_dcb* pDCB = pSRB->pSRBDCB;
+  u8 oldsyncperiod = pDCB->SyncPeriod;
+  u8 oldsyncoffset = pDCB->SyncOffset;
+  
+  if (!(pSRB->SRBState & DO_SYNC_NEGO))
+    {
+      printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
+	      pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+
+      /* reject */
+      //dc390_MsgIn_reject (pACB, pSRB);
+      //return dc390_MsgIn_set_async (pACB, pSRB);
+
+      /* Reply with corrected SDTR Message */
+      if (pSRB->MsgInBuf[4] > 15)
+	{ 
+	  printk (KERN_INFO "DC390: Lower Sync Offset to 15\n");
+	  pSRB->MsgInBuf[4] = 15;
+	}
+      if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
+	{
+	  printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
+	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
+	}
+      memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
+      pSRB->MsgCnt = 5;
+      DC390_ENABLE_MSGOUT;
+    }
+
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+  pDCB->SyncOffset &= 0x0f0;
+  pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+  pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+
+  wval = (u16) pSRB->MsgInBuf[3];
+  wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
+  if( (wval1 * 25) != wval) wval1++;
+  bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
+
+  pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
+  if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+    pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+  else
+    pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+  if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+
+  if (wval1 >= 8)
+    {
+      wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
+      bval = FAST_CLK;		/* fast clock / normal scsi */
+      pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
+    }
+
+  pDCB->CtrlR3 = bval;
+  pDCB->SyncPeriod = (u8)wval1;
+  
+  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0)
+    {
+      if (! (bval & FAST_SCSI)) wval1++;
+      printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, 
+	      40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
+    }
+  
+  dc390_reprog (pACB, pDCB);
+}
+
+
+/* handle RESTORE_PTR */
+/* I presume, this command is already mapped, so, have to remap. */
+static void 
+dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+    struct scsi_cmnd *pcmd = pSRB->pcmd;
+    struct scatterlist *psgl;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGIndex = 0;
+    if (pcmd->use_sg) {
+	pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
+	psgl = pSRB->pSegmentList;
+	//dc390_pci_sync(pSRB);
+
+	while (pSRB->TotalXferredLen + (unsigned long) sg_dma_len(psgl) < pSRB->Saved_Ptr)
+	{
+	    pSRB->TotalXferredLen += (unsigned long) sg_dma_len(psgl);
+	    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;
+	}
+	pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+	pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+	printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
+		pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
+
+    } else if(pcmd->request_buffer) {
+	//dc390_pci_sync(pSRB);
+
+	sg_dma_len(&pSRB->Segmentx) = pcmd->request_bufflen - pSRB->Saved_Ptr;
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (struct scatterlist *) &pSRB->Segmentx;
+    } else {
+	 pSRB->SGcount = 0;
+	 printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
+    }
+
+  pSRB->TotalXferredLen = pSRB->Saved_Ptr;
+}
+
+
+/* According to the docs, the AM53C974 reads the message and 
+ * generates a Successful Operation IRQ before asserting ACK for
+ * the last byte (how does it know whether it's the last ?) */
+/* The old code handled it in another way, indicating, that on
+ * every message byte an IRQ is generated and every byte has to
+ * be manually ACKed. Hmmm ?  (KG, 98/11/28) */
+/* The old implementation was correct. Sigh! */
+
+/* Check if the message is complete */
+static u8 __inline__
+dc390_MsgIn_complete (u8 *msgbuf, u32 len)
+{ 
+  if (*msgbuf == EXTENDED_MESSAGE)
+  {
+	if (len < 2) return 0;
+	if (len < msgbuf[1] + 2) return 0;
+  }
+  else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
+	if (len < 2) return 0;
+  return 1;
+}
+
+
+
+/* read and eval received messages */
+static void
+dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    struct dc390_dcb*   pDCB = pACB->pActiveDCB;
+
+    /* Read the msg */
+
+    pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo);
+    //pSRB->SRBState = 0;
+
+    /* Msg complete ? */
+    if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
+      {
+	DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen));
+	/* Now eval the msg */
+	switch (pSRB->MsgInBuf[0]) 
+	  {
+	  case DISCONNECT: 
+	    pSRB->SRBState = SRB_DISCONNECT; break;
+	    
+	  case SIMPLE_QUEUE_TAG:
+	  case HEAD_OF_QUEUE_TAG:
+	  case ORDERED_QUEUE_TAG:
+	    pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
+	    break;
+	    
+	  case MESSAGE_REJECT: 
+	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+	    pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+	    if( pSRB->SRBState & DO_SYNC_NEGO)
+	      dc390_MsgIn_set_async (pACB, pSRB);
+	    break;
+	    
+	  case EXTENDED_MESSAGE:
+	    /* reject every extended msg but SDTR */
+	    if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
+	      dc390_MsgIn_reject (pACB, pSRB);
+	    else
+	      {
+		if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
+		  dc390_MsgIn_set_async (pACB, pSRB);
+		else
+		  dc390_MsgIn_set_sync (pACB, pSRB);
+	      }
+	    
+	    // nothing has to be done
+	  case COMMAND_COMPLETE: break;
+	    
+	    // SAVE POINTER may be ignored as we have the struct dc390_srb* associated with the
+	    // scsi command. Thanks, Gerard, for pointing it out.
+	  case SAVE_POINTERS: 
+	    pSRB->Saved_Ptr = pSRB->TotalXferredLen;
+	    break;
+	    // The device might want to restart transfer with a RESTORE
+	  case RESTORE_POINTERS:
+	    DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n"));
+	    dc390_restore_ptr (pACB, pSRB);
+	    break;
+
+	    // reject unknown messages
+	  default: dc390_MsgIn_reject (pACB, pSRB);
+	  }
+	
+	/* Clear counter and MsgIn state */
+	pSRB->SRBState &= ~SRB_MSGIN;
+	pACB->MsgLen = 0;
+      }
+
+    *psstatus = SCSI_NOP0;
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+
+static void
+dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
+{
+    struct scatterlist *psgl;
+    unsigned long  lval;
+    struct dc390_dcb*   pDCB = pACB->pActiveDCB;
+
+    if (pSRB == pACB->pTmpSRB)
+    {
+	if (pDCB)
+		printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN);
+	else
+		printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n");
+
+	/* Try to recover - some broken disks react badly to tagged INQUIRY */
+	if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) {
+		pSRB = pDCB->pGoingSRB;
+		pDCB->pActiveSRB = pSRB;
+	} else {
+		pSRB->pSRBDCB = pDCB;
+		dc390_EnableMsgOut_Abort(pACB, pSRB);
+		if (pDCB)
+			pDCB->DCBFlag |= ABORT_DEV;
+		return;
+	}
+    }
+
+    if( pSRB->SGIndex < pSRB->SGcount )
+    {
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
+	if( !pSRB->SGToBeXferLen )
+	{
+	    psgl = pSRB->pSegmentList;
+	    pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
+	    pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
+	}
+	lval = pSRB->SGToBeXferLen;
+	DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr));
+	DC390_write8 (CtcReg_Low, (u8) lval);
+	lval >>= 8;
+	DC390_write8 (CtcReg_Mid, (u8) lval);
+	lval >>= 8;
+	DC390_write8 (CtcReg_High, (u8) lval);
+
+	DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
+	DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
+
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+	pSRB->SRBState = SRB_DATA_XFER;
+
+	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
+
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
+	//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
+    }
+    else    /* xfer pad */
+    {
+	if( pSRB->SGcount )
+	{
+	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+	    pSRB->SRBStatus |= OVER_RUN;
+	    DEBUG0(printk (KERN_WARNING " DC390: Overrun -"));
+	}
+	DEBUG0(printk (KERN_WARNING " Clear transfer pad \n"));
+	DC390_write8 (CtcReg_Low, 0);
+	DC390_write8 (CtcReg_Mid, 0);
+	DC390_write8 (CtcReg_High, 0);
+
+	pSRB->SRBState |= SRB_XFERPAD;
+	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
+/*
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+*/
+    }
+}
+
+
+static void
+dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
+}
+
+static void
+dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
+}
+
+static void
+dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    struct dc390_dcb*   pDCB;
+    u8  i, cnt;
+    u8     *ptr;
+
+    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
+    {
+	cnt = (u8) pSRB->pcmd->cmd_len;
+	ptr = (u8 *) pSRB->pcmd->cmnd;
+	for(i=0; i < cnt; i++)
+	    DC390_write8 (ScsiFifo, *(ptr++));
+    }
+    else
+    {
+	u8 bval = 0;
+	DC390_write8 (ScsiFifo, REQUEST_SENSE);
+	pDCB = pACB->pActiveDCB;
+	DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
+	DC390_write8 (ScsiFifo, bval);
+	DC390_write8 (ScsiFifo, bval);
+	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+	DC390_write8 (ScsiFifo, bval);
+	DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
+    }
+    pSRB->SRBState = SRB_COMMAND;
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+}
+
+static void
+dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pSRB->SRBState = SRB_STATUS;
+    DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+static void
+dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    u8   bval, i, cnt;
+    u8     *ptr;
+    struct dc390_dcb*    pDCB;
+
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pDCB = pACB->pActiveDCB;
+    if( !(pSRB->SRBState & SRB_MSGOUT) )
+    {
+	cnt = pSRB->MsgCnt;
+	if( cnt )
+	{
+	    ptr = (u8 *) pSRB->MsgOutBuf;
+	    for(i=0; i < cnt; i++)
+		DC390_write8 (ScsiFifo, *(ptr++));
+	    pSRB->MsgCnt = 0;
+	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
+		(pSRB->MsgOutBuf[0] == ABORT) )
+		pSRB->SRBState = SRB_ABORT_SENT;
+	}
+	else
+	{
+	    bval = ABORT;	/* ??? MSG_NOP */
+	    if( (pSRB->pcmd->cmnd[0] == INQUIRY ) ||
+		(pSRB->pcmd->cmnd[0] == REQUEST_SENSE) ||
+		(pSRB->SRBFlag & AUTO_REQSENSE) )
+	    {
+		if( pDCB->SyncMode & SYNC_ENABLE )
+		    goto  mop1;
+	    }
+	    DC390_write8 (ScsiFifo, bval);
+	}
+	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    }
+    else
+    {
+mop1:
+        printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);
+	DC390_write8 (ScsiFifo, EXTENDED_MESSAGE);
+	DC390_write8 (ScsiFifo, 3);	/*    ;length of extended msg */
+	DC390_write8 (ScsiFifo, EXTENDED_SDTR);	/*    ; sync nego */
+	DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
+	if (pDCB->SyncOffset & 0x0f)
+		    DC390_write8 (ScsiFifo, pDCB->SyncOffset);
+	else
+		    DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);		    
+	pSRB->SRBState |= DO_SYNC_NEGO;
+	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    }
+}
+
+static void
+dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    if( !(pSRB->SRBState & SRB_MSGIN) )
+    {
+	pSRB->SRBState &= ~SRB_DISCONNECT;
+	pSRB->SRBState |= SRB_MSGIN;
+    }
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+static void
+dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+}
+
+static void
+dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+}
+
+
+static void
+dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB )
+{
+    u8  bval, i, cnt;
+    struct dc390_dcb*   ptr;
+
+    if( !(pDCB->TargetLUN) )
+    {
+	if( !pACB->scan_devices )
+	{
+	    ptr = pACB->pLinkDCB;
+	    cnt = pACB->DCBCnt;
+	    bval = pDCB->TargetID;
+	    for(i=0; i<cnt; i++)
+	    {
+		if( ptr->TargetID == bval )
+		{
+		    ptr->SyncPeriod = pDCB->SyncPeriod;
+		    ptr->SyncOffset = pDCB->SyncOffset;
+		    ptr->CtrlR3 = pDCB->CtrlR3;
+		    ptr->CtrlR4 = pDCB->CtrlR4;
+		    ptr->SyncMode = pDCB->SyncMode;
+		}
+		ptr = ptr->pNextDCB;
+	    }
+	}
+    }
+    return;
+}
+
+
+static void
+dc390_Disconnect( struct dc390_acb* pACB )
+{
+    struct dc390_dcb *pDCB;
+    struct dc390_srb *pSRB, *psrb;
+    u8  i, cnt;
+
+    DEBUG0(printk(KERN_INFO "DISC,"));
+
+    if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n");
+    pACB->Connected = 0;
+    pDCB = pACB->pActiveDCB;
+    if (!pDCB)
+     {
+	DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\
+	       pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel));
+	mdelay(400);
+	DC390_read8 (INT_Status);	/* Reset Pending INT */
+	DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+	return;
+     }
+    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+    pSRB = pDCB->pActiveSRB;
+    pACB->pActiveDCB = 0;
+    pSRB->ScsiPhase = SCSI_NOP0;
+    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
+	pSRB->SRBState = 0;
+    else if( pSRB->SRBState & SRB_ABORT_SENT )
+    {
+	pDCB->TagMask = 0;
+	pDCB->DCBFlag = 0;
+	cnt = pDCB->GoingSRBCnt;
+	pDCB->GoingSRBCnt = 0;
+	pSRB = pDCB->pGoingSRB;
+	for( i=0; i < cnt; i++)
+	{
+	    psrb = pSRB->pNextSRB;
+	    dc390_Free_insert (pACB, pSRB);
+	    pSRB = psrb;
+	}
+	pDCB->pGoingSRB = 0;
+    }
+    else
+    {
+	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
+	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
+	{	/* Selection time out */
+		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+		goto  disc1;
+	}
+	else if (!(pSRB->SRBState & SRB_DISCONNECT) && (pSRB->SRBState & SRB_COMPLETED))
+	{
+disc1:
+	    dc390_freetag (pDCB, pSRB);
+	    pDCB->pActiveSRB = 0;
+	    pSRB->SRBState = SRB_FREE;
+	    dc390_SRBdone( pACB, pDCB, pSRB);
+	}
+    }
+    pACB->MsgLen = 0;
+}
+
+
+static void
+dc390_Reselect( struct dc390_acb* pACB )
+{
+    struct dc390_dcb*   pDCB;
+    struct dc390_srb*   pSRB;
+    u8  id, lun;
+
+    DEBUG0(printk(KERN_INFO "RSEL,"));
+    pACB->Connected = 1;
+    pDCB = pACB->pActiveDCB;
+    if( pDCB )
+    {	/* Arbitration lost but Reselection won */
+	DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n"));
+	pSRB = pDCB->pActiveSRB;
+	if( !( pACB->scan_devices ) )
+	{
+	    struct scsi_cmnd *pcmd = pSRB->pcmd;
+	    pcmd->resid = pcmd->request_bufflen;
+	    SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	    dc390_Going_remove(pDCB, pSRB);
+	    dc390_Free_insert(pACB, pSRB);
+	    pcmd->scsi_done (pcmd);
+	    DEBUG0(printk(KERN_DEBUG"DC390: Return SRB %p to free\n", pSRB));
+	}
+    }
+    /* Get ID */
+    lun = DC390_read8 (ScsiFifo);
+    DEBUG0(printk ("Dev %02x,", lun));
+    if (!(lun & (1 << pACB->pScsiHost->this_id)))
+      printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun);
+    else
+      lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
+    id = 0; while (lun >>= 1) id++;
+    /* Get LUN */
+    lun = DC390_read8 (ScsiFifo);
+    if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n");
+    lun &= 7;
+    DEBUG0(printk ("(%02i-%i),", id, lun));
+    pDCB = dc390_findDCB (pACB, id, lun);
+    if (!pDCB)
+    {
+	printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n",
+		    id, lun);
+	return;
+    }
+    pACB->pActiveDCB = pDCB;
+    /* TagQ: We expect a message soon, so never mind the exact SRB */
+    if( pDCB->SyncMode & EN_TAG_QUEUEING )
+    {
+	pSRB = pACB->pTmpSRB;
+	pDCB->pActiveSRB = pSRB;
+    }
+    else
+    {
+	pSRB = pDCB->pActiveSRB;
+	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
+	{
+	    pSRB= pACB->pTmpSRB;
+	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n",
+		    id, lun);
+	    pDCB->pActiveSRB = pSRB;
+	    dc390_EnableMsgOut_Abort ( pACB, pSRB );
+	}
+	else
+	{
+	    if( pDCB->DCBFlag & ABORT_DEV_ )
+	    {
+		pSRB->SRBState = SRB_ABORT_SENT;
+		printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n",
+			id, lun);
+		dc390_EnableMsgOut_Abort( pACB, pSRB );
+	    }
+	    else
+		pSRB->SRBState = SRB_DATA_XFER;
+	}
+    }
+
+    DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber));
+    pSRB->ScsiPhase = SCSI_NOP0;
+    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);	/* ; Glitch eater */
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);	/* ;to release the /ACK signal */
+}
+
+static int __inline__
+dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
+{
+	struct scsi_cmnd *pcmd;
+
+	pcmd = pSRB->pcmd;
+
+	REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense(Cmd %02x, Id %02x, LUN %02x)\n",\
+			      pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN));
+
+	pSRB->SRBFlag |= AUTO_REQSENSE;
+	pSRB->SavedSGCount = pcmd->use_sg;
+	pSRB->SavedTotXLen = pSRB->TotalXferredLen;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */
+
+	/* We are called from SRBdone, original PCI mapping has been removed
+	 * already, new one is set up from StartSCSI */
+	pSRB->SGIndex = 0;
+
+	pSRB->TotalXferredLen = 0;
+	pSRB->SGToBeXferLen = 0;
+	return dc390_StartSCSI(pACB, pDCB, pSRB);
+}
+
+
+static void
+dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB )
+{
+    u8  bval, status;
+    struct scsi_cmnd *pcmd;
+
+    pcmd = pSRB->pcmd;
+    /* KG: Moved pci_unmap here */
+    dc390_pci_unmap(pSRB);
+
+    status = pSRB->TargetStatus;
+
+    DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
+		pSRB, pcmd->pid));
+    if(pSRB->SRBFlag & AUTO_REQSENSE)
+    {	/* Last command was a Request Sense */
+	pSRB->SRBFlag &= ~AUTO_REQSENSE;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = CHECK_CONDITION << 1;
+
+	//pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status);
+	if (status == (CHECK_CONDITION << 1))
+	    pcmd->result = MK_RES_LNX(0, DID_BAD_TARGET, 0, /*CHECK_CONDITION*/0);
+	else /* Retry */
+	{
+	    if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */)
+	    {
+		/* Don't retry on TEST_UNIT_READY */
+		pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION);
+		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\
+		       (u32) pcmd->result, (u32) pSRB->TotalXferredLen));
+	    } else {
+		SET_RES_DRV(pcmd->result, DRIVER_SENSE);
+		pcmd->use_sg = pSRB->SavedSGCount;
+		//pSRB->ScsiCmdLen	 = (u8) (pSRB->Segment1[0] >> 8);
+		DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+		pSRB->TotalXferredLen = 0;
+		SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	    }
+	}
+	goto cmd_done;
+    }
+    if( status )
+    {
+	if( status_byte(status) == CHECK_CONDITION )
+	{
+	    if (dc390_RequestSense(pACB, pDCB, pSRB)) {
+		SET_RES_DID(pcmd->result, DID_ERROR);
+		goto cmd_done;
+	    }
+	    return;
+	}
+	else if( status_byte(status) == QUEUE_FULL )
+	{
+	    bval = (u8) pDCB->GoingSRBCnt;
+	    bval--;
+	    pDCB->MaxCommand = bval;
+	    pcmd->use_sg = pSRB->SavedSGCount;
+	    DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+	    pSRB->TotalXferredLen = 0;
+	    SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	}
+	else if(status == SCSI_STAT_SEL_TIMEOUT)
+	{
+	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
+	    pSRB->TargetStatus = 0;
+	    pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0);
+	    /* Devices are removed below ... */
+	}
+	else if (status_byte(status) == BUSY && 
+		 (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
+		 pACB->scan_devices)
+	{
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = status;
+	    pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0);
+	}
+	else
+	{   /* Another error */
+	    pSRB->TotalXferredLen = 0;
+	    SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	    goto cmd_done;
+	}
+    }
+    else
+    {	/*  Target status == 0 */
+	status = pSRB->AdaptStatus;
+	if(status & H_OVER_UNDER_RUN)
+	{
+	    pSRB->TargetStatus = 0;
+	    SET_RES_DID(pcmd->result,DID_OK);
+	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
+	}
+	else if( pSRB->SRBStatus & PARITY_ERROR)
+	{
+	    //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0);
+	    SET_RES_DID(pcmd->result,DID_PARITY);
+	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
+	}
+	else		       /* No error */
+	{
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    SET_RES_DID(pcmd->result,DID_OK);
+	}
+    }
+
+cmd_done:
+    pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
+
+    dc390_Going_remove (pDCB, pSRB);
+    /* Add to free list */
+    dc390_Free_insert (pACB, pSRB);
+
+    DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid));
+    pcmd->scsi_done (pcmd);
+
+    return;
+}
+
+
+/* Remove all SRBs from Going list and inform midlevel */
+static void
+dc390_DoingSRB_Done(struct dc390_acb* pACB, struct scsi_cmnd *cmd)
+{
+    struct dc390_dcb *pDCB, *pdcb;
+    struct dc390_srb *psrb, *psrb2;
+    u8  i;
+    struct scsi_cmnd *pcmd;
+
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    if (! pdcb) return;
+    do
+    {
+	psrb = pdcb->pGoingSRB;
+	for( i=0; i<pdcb->GoingSRBCnt; i++)
+	{
+	    psrb2 = psrb->pNextSRB;
+	    pcmd = psrb->pcmd;
+	    dc390_Free_insert (pACB, psrb);
+	    psrb  = psrb2;
+	}
+	pdcb->GoingSRBCnt = 0;
+	pdcb->pGoingSRB = NULL;
+	pdcb->TagMask = 0;
+	pdcb = pdcb->pNextDCB;
+    } while( pdcb != pDCB );
+}
+
+
+static void
+dc390_ResetSCSIBus( struct dc390_acb* pACB )
+{
+    //DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+    //udelay (250);
+    //DC390_write8 (ScsiCmd, NOP_CMD);
+
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
+    pACB->Connected = 0;
+
+    return;
+}
+
+static void
+dc390_ScsiRstDetect( struct dc390_acb* pACB )
+{
+    printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus);
+    //DEBUG0(printk(KERN_INFO "RST_DETECT,"));
+
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    /* Unlock before ? */
+    /* delay half a second */
+    udelay (1000);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pACB->pScsiHost->last_reset = jiffies + 5*HZ/2
+		    + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+    pACB->Connected = 0;
+
+    if( pACB->ACBFlag & RESET_DEV )
+	pACB->ACBFlag |= RESET_DONE;
+    else
+    {   /* Reset was issued by sb else */
+	pACB->ACBFlag |= RESET_DETECT;
+
+	dc390_ResetDevParam( pACB );
+	dc390_DoingSRB_Done( pACB, 0 );
+	//dc390_RecoverSRB( pACB );
+	pACB->pActiveDCB = NULL;
+	pACB->ACBFlag = 0;
+    }
+    return;
+}
+
 static int DC390_queuecommand(struct scsi_cmnd *cmd,
 		void (*done)(struct scsi_cmnd *))
 {
@@ -660,9 +2153,6 @@
 
 	return SUCCESS;
 }
-
-#include "scsiiom.c"
-
 
 /**
  * dc390_slave_alloc - Called by the scsi mid layer to tell us about a new

             reply	other threads:[~2004-10-03 13:47 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-10-03 13:47 Christoph Hellwig [this message]
2004-10-03 20:42 ` [PATCH] merge scsiiom.c into tmscsim.c Guennadi Liakhovetski
2004-10-09 12:29 ` Christoph Hellwig
2004-10-09 13:02   ` James Bottomley
2004-10-09 19:18     ` Guennadi Liakhovetski
2007-06-17 15:09 ` Guennadi Liakhovetski
2007-06-17 16:25   ` Boaz Harrosh
2007-06-17 18:09     ` Guennadi Liakhovetski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20041003134714.GA1623@lst.de \
    --to=hch@lst.de \
    --cc=g.liakhovetski@gmx.de \
    --cc=jejb@steeleye.com \
    --cc=linux-scsi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.