Commit 1d4cf376 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

merge scsiiom.c into tmscsim.c

From: Christoph Hellwig <hch@lst.de>

Also reapplied sparse fixes on top of the initial
patch.
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 3902f5c8
/***********************************************************************
* 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 != 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 = NULL;
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 = NULL;
}
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 = NULL;
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, NULL );
//dc390_RecoverSRB( pACB );
pACB->pActiveDCB = NULL;
pACB->ACBFlag = 0;
}
return;
}
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
#include "tmscsim.h" #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_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_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); static void dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
...@@ -272,11 +272,10 @@ static void dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB ); ...@@ -272,11 +272,10 @@ static void dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB );
static void dc390_Disconnect( struct dc390_acb* pACB ); static void dc390_Disconnect( struct dc390_acb* pACB );
static void dc390_Reselect( 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_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_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 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 u32 dc390_laststatus = 0;
static u8 dc390_adapterCnt = 0; static u8 dc390_adapterCnt = 0;
...@@ -482,6 +481,1500 @@ static void dc390_pci_unmap (struct dc390_srb* pSRB) ...@@ -482,6 +481,1500 @@ static void dc390_pci_unmap (struct dc390_srb* pSRB)
} }
} }
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 = NULL;
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 = NULL;
}
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 = NULL;
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, NULL);
//dc390_RecoverSRB( pACB );
pACB->pActiveDCB = NULL;
pACB->ACBFlag = 0;
}
return;
}
static int DC390_queuecommand(struct scsi_cmnd *cmd, static int DC390_queuecommand(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *)) void (*done)(struct scsi_cmnd *))
{ {
...@@ -661,9 +2154,6 @@ static int DC390_bus_reset (struct scsi_cmnd *cmd) ...@@ -661,9 +2154,6 @@ static int DC390_bus_reset (struct scsi_cmnd *cmd)
return SUCCESS; return SUCCESS;
} }
#include "scsiiom.c"
/** /**
* dc390_slave_alloc - Called by the scsi mid layer to tell us about a new * dc390_slave_alloc - Called by the scsi mid layer to tell us about a new
* scsi device that we need to deal with. * scsi device that we need to deal with.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment