/***********************************************************************
 *	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			       *
 ***********************************************************************/


static USHORT
DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
{
    USHORT ioport, rc;
    UCHAR  bval, bval1, i, cnt;
    PUCHAR ptr;
    ULONG  wlval;

    pSRB->TagNumber = 31;
    ioport = pACB->IOPortBase;
    bval = pDCB->UnitSCSIID;
    outb(bval,ioport+Scsi_Dest_ID);
    bval = pDCB->SyncPeriod;
    outb(bval,ioport+Sync_Period);
    bval = pDCB->SyncOffset;
    outb(bval,ioport+Sync_Offset);
    bval = pDCB->CtrlR1;
    outb(bval,ioport+CtrlReg1);
    bval = pDCB->CtrlR3;
    outb(bval,ioport+CtrlReg3);
    bval = pDCB->CtrlR4;
    outb(bval,ioport+CtrlReg4);
    bval = CLEAR_FIFO_CMD;	   /* Flush FIFO */
    outb(bval,ioport+ScsiCmd);

    pSRB->ScsiPhase = SCSI_NOP0;
    bval = pDCB->IdentifyMsg;
    if( !(pDCB->SyncMode & EN_ATN_STOP) )
    {
	if( (pSRB->CmdBlock[0] == INQUIRY) ||
	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
	    (pSRB->SRBFlag & AUTO_REQSENSE) )
	{
	    bval &= 0xBF;	/* NO disconnection */
	    outb(bval,ioport+ScsiFifo);
	    bval1 = SELECT_W_ATN;
	    pSRB->SRBState = SRB_START_;
	    if( pDCB->SyncMode & SYNC_ENABLE )
	    {
		if( !(pDCB->IdentifyMsg & 7) ||
		    (pSRB->CmdBlock[0] != INQUIRY) )
		{
		    bval1 = SEL_W_ATN_STOP;
		    pSRB->SRBState = SRB_MSGOUT;
		}
	    }
	}
	else
	{
	    if(pDCB->SyncMode & EN_TAG_QUEUING)
	    {
		outb(bval,ioport+ScsiFifo);
		bval = MSG_SIMPLE_QTAG;
		outb(bval,ioport+ScsiFifo);
		wlval = 1;
		bval = 0;
		while( wlval & pDCB->TagMask )
		{
		    wlval = wlval << 1;
		    bval++;
		}
		outb(bval,ioport+ScsiFifo);
		pDCB->TagMask |= wlval;
		pSRB->TagNumber = bval;
		bval1 = SEL_W_ATN2;
		pSRB->SRBState = SRB_START_;
	    }
	    else
	    {
		outb(bval,ioport+ScsiFifo);
		bval1 = SELECT_W_ATN;
		pSRB->SRBState = SRB_START_;
	    }
	}

	if( pSRB->SRBFlag & AUTO_REQSENSE )
	{
	    bval = REQUEST_SENSE;
	    outb(bval,ioport+ScsiFifo);
	    bval = pDCB->IdentifyMsg << 5;
	    outb(bval,ioport+ScsiFifo);
	    bval = 0;
	    outb(bval,ioport+ScsiFifo);
	    outb(bval,ioport+ScsiFifo);
	    bval = sizeof(pSRB->pcmd->sense_buffer);
	    outb(bval,ioport+ScsiFifo);
	    bval = 0;
	    outb(bval,ioport+ScsiFifo);
	}
	else
	{
	    cnt = pSRB->ScsiCmdLen;
	    ptr = (PUCHAR) pSRB->CmdBlock;
	    for(i=0; i<cnt; i++)
	    {
		bval = *ptr++;
		outb(bval,ioport+ScsiFifo);
	    }
	}
    }
    else	/* ATN_STOP */
    {
	if( (pSRB->CmdBlock[0] == INQUIRY) ||
	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
	    (pSRB->SRBFlag & AUTO_REQSENSE) )
	{
	    bval &= 0xBF;
	    outb(bval,ioport+ScsiFifo);
	    bval1 = SELECT_W_ATN;
	    pSRB->SRBState = SRB_START_;
	    if( pDCB->SyncMode & SYNC_ENABLE )
	    {
		if( !(pDCB->IdentifyMsg & 7) ||
		    (pSRB->CmdBlock[0] != INQUIRY) )
		{
		    bval1 = SEL_W_ATN_STOP;
		    pSRB->SRBState = SRB_MSGOUT;
		}
	    }
	}
	else
	{
	    if(pDCB->SyncMode & EN_TAG_QUEUING)
	    {
		outb(bval,ioport+ScsiFifo);
		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
		wlval = 1;
		bval = 0;
		while( wlval & pDCB->TagMask )
		{
		    wlval = wlval << 1;
		    bval++;
		}
		pDCB->TagMask |= wlval;
		pSRB->TagNumber = bval;
		pSRB->MsgOutBuf[1] = bval;
		pSRB->MsgCnt = 2;
		bval1 = SEL_W_ATN_STOP;
		pSRB->SRBState = SRB_START_;
	    }
	    else
	    {
		outb(bval,ioport+ScsiFifo);
		pSRB->MsgOutBuf[0] = MSG_NOP;
		pSRB->MsgCnt = 1;
		pSRB->SRBState = SRB_START_;
		bval1 = SEL_W_ATN_STOP;
	    }
	}
    }
    bval = inb( ioport+Scsi_Status );
    if( bval & INTERRUPT )
    {
	pSRB->SRBState = SRB_READY;
	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
	rc = 1;
    }
    else
    {
	pSRB->ScsiPhase = SCSI_NOP1;
	pACB->pActiveDCB = pDCB;
	pDCB->pActiveSRB = pSRB;
	rc = 0;
	outb(bval1,ioport+ScsiCmd);
    }
    return( rc );
}


static void
DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
{
    PACB   pACB;
    PDCB   pDCB;
    PSRB   pSRB;
    USHORT ioport = 0;
    USHORT phase, i;
    void   (*stateV)( PACB, PSRB, PUCHAR );
    UCHAR  istate = 0;
    UCHAR  sstatus=0, istatus;

    pACB = pACB_start;
    if( pACB == NULL )
	return;
    for( i=0; i < adapterCnt; i++ )
    {
	if( pACB->IRQLevel == (UCHAR) irq )
	{
	     ioport = pACB->IOPortBase;
	     sstatus = inb( ioport+Scsi_Status );
	     if( sstatus & INTERRUPT )
		 break;
	     else
		pACB = pACB->pNextACB;
	}
	else
	{
	    pACB = pACB->pNextACB;
	}
    }

#ifdef DC390_DEBUG1
	printk("sstatus=%2x,",sstatus);
#endif

    if( pACB == (PACB )-1 )
    {
	printk("DC390: Spurious interrupt detected!\n");
	return;
    }

    istate = inb( ioport+Intern_State );
    istatus = inb( ioport+INT_Status );

#ifdef DC390_DEBUG1
	printk("Istatus=%2x,",istatus);
#endif

    if(istatus &  DISCONNECTED)
    {
	DC390_Disconnect( pACB );
	return;
    }

    if(istatus &  RESELECTED)
    {
	DC390_Reselect( pACB );
	return;
    }

    if(istatus &  INVALID_CMD)
    {
	DC390_InvalidCmd( pACB );
	return;
    }

    if(istatus &  SCSI_RESET)
    {
	DC390_ScsiRstDetect( pACB );
	return;
    }

    if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
    {
	pDCB = pACB->pActiveDCB;
	pSRB = pDCB->pActiveSRB;
	if( pDCB )
	{
	    if( pDCB->DCBFlag & ABORT_DEV_ )
		EnableMsgOut( pACB, pSRB );
	}

	phase = (USHORT) pSRB->ScsiPhase;
	stateV = (void *) DC390_phase0[phase];
	stateV( pACB, pSRB, &sstatus );

	pSRB->ScsiPhase = sstatus & 7;
	phase = (USHORT) sstatus & 7;
	stateV = (void *) DC390_phase1[phase];
	stateV( pACB, pSRB, &sstatus );
    }
}

static void
do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
{
    unsigned long flags;

    spin_lock_irqsave(&io_request_lock, flags);
    DC390_Interrupt(irq, dev_id, regs);
    spin_unlock_irqrestore(&io_request_lock, flags);
}

static void
DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR   sstatus, bval;
    USHORT  ioport;
    PSGL    psgl;
    ULONG   ResidCnt, xferCnt;

    ioport = pACB->IOPortBase;
    sstatus = *psstatus;

    if( !(pSRB->SRBState & SRB_XFERPAD) )
    {
	if( sstatus & PARITY_ERR )
	    pSRB->SRBStatus |= PARITY_ERROR;

	if( sstatus & COUNT_2_ZERO )
	{
	    bval = inb(ioport+DMA_Status);
	    while( !(bval & DMA_XFER_DONE) )
		bval = inb(ioport+DMA_Status);
	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
	    pSRB->SGIndex++;
	    if( pSRB->SGIndex < pSRB->SGcount )
	    {
		pSRB->pSegmentList++;
		psgl = pSRB->pSegmentList;

		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
		pSRB->SGToBeXferLen = (ULONG) psgl->length;
	    }
	    else
		pSRB->SGToBeXferLen = 0;
	}
	else
	{
	    bval = inb( ioport+Current_Fifo );
	    bval &= 0x1f;
	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
	    ResidCnt = ResidCnt << 8;
	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
	    ResidCnt = ResidCnt << 8;
	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
	    ResidCnt += (ULONG) bval;

	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
	    pSRB->SGPhysAddr += xferCnt;
	    pSRB->TotalXferredLen += xferCnt;
	    pSRB->SGToBeXferLen = ResidCnt;
	}
    }
    bval = WRITE_DIRECTION+DMA_IDLE_CMD;
    outb( bval, ioport+DMA_Cmd);
}

static void
DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR   sstatus, bval;
    USHORT  i, ioport, residual;
    PSGL    psgl;
    ULONG   ResidCnt, xferCnt;
    PUCHAR  ptr;


    ioport = pACB->IOPortBase;
    sstatus = *psstatus;

    if( !(pSRB->SRBState & SRB_XFERPAD) )
    {
	if( sstatus & PARITY_ERR )
	    pSRB->SRBStatus |= PARITY_ERROR;

	if( sstatus & COUNT_2_ZERO )
	{
	    bval = inb(ioport+DMA_Status);
	    while( !(bval & DMA_XFER_DONE) )
		bval = inb(ioport+DMA_Status);

	    bval = READ_DIRECTION+DMA_IDLE_CMD;
	    outb( bval, ioport+DMA_Cmd);

	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
	    pSRB->SGIndex++;
	    if( pSRB->SGIndex < pSRB->SGcount )
	    {
		pSRB->pSegmentList++;
		psgl = pSRB->pSegmentList;

		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
		pSRB->SGToBeXferLen = (ULONG) psgl->length;
	    }
	    else
		pSRB->SGToBeXferLen = 0;
	}
	else	/* phase changed */
	{
	    residual = 0;
	    bval = inb(ioport+Current_Fifo);
	    while( bval & 0x1f )
	    {
		if( (bval & 0x1f) == 1 )
		{
		    for(i=0; i< 0x100; i++)
		    {
			bval = inb(ioport+Current_Fifo);
			if( !(bval & 0x1f) )
			    goto din_1;
			else if( i == 0x0ff )
			{
			    residual = 1;   /* ;1 residual byte */
			    goto din_1;
			}
		    }
		}
		else
		    bval = inb(ioport+Current_Fifo);
	    }
din_1:
	    bval = READ_DIRECTION+DMA_BLAST_CMD;
	    outb(bval, ioport+DMA_Cmd);
	    for(i=0; i<0x8000; i++)
	    {
		bval = inb(ioport+DMA_Status);
		if(bval & BLAST_COMPLETE)
		    break;
	    }
	    bval = READ_DIRECTION+DMA_IDLE_CMD;
	    outb(bval, ioport+DMA_Cmd);

	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
	    ResidCnt = ResidCnt << 8;
	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
	    ResidCnt = ResidCnt << 8;
	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);

	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
	    pSRB->SGPhysAddr += xferCnt;
	    pSRB->TotalXferredLen += xferCnt;
	    pSRB->SGToBeXferLen = ResidCnt;

	    if( residual )
	    {
		bval = inb(ioport+ScsiFifo);	    /* get residual byte */
		ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
		*ptr = bval;
		pSRB->SGPhysAddr++;
		pSRB->TotalXferredLen++;
		pSRB->SGToBeXferLen--;
	    }
	}
    }
}

static void
DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
}

static void
DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR  bval;
    USHORT ioport;

    ioport = pACB->IOPortBase;
    bval = inb(ioport+ScsiFifo);
    pSRB->TargetStatus = bval;
    bval++;
    bval = inb(ioport+ScsiFifo);	/* get message */
    pSRB->EndMessage = bval;

    *psstatus = SCSI_NOP0;
    pSRB->SRBState = SRB_COMPLETED;
    bval = MSG_ACCEPTED_CMD;
    outb(bval, ioport+ScsiCmd);
}

static void
DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
	*psstatus = SCSI_NOP0;
}

static void
DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR  bval;
    USHORT ioport, wval, wval1;
    PDCB   pDCB;
    PSRB   psrb;

    ioport = pACB->IOPortBase;
    pDCB = pACB->pActiveDCB;

    bval = inb( ioport+ScsiFifo );
    if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
    {
	if(bval == MSG_DISCONNECT)
	{
	    pSRB->SRBState = SRB_DISCONNECT;
	}
	else if( bval == MSG_SAVE_PTR )
	    goto  min6;
	else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
					    (bval <= MSG_ORDER_QTAG)) )
	{
	    pSRB->SRBState |= SRB_MSGIN_MULTI;
	    pSRB->MsgInBuf[0] = bval;
	    pSRB->MsgCnt = 1;
	    pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
	}
	else if(bval == MSG_REJECT_)
	{
	    bval = RESET_ATN_CMD;
	    outb(bval, ioport+ScsiCmd);
	    if( pSRB->SRBState & DO_SYNC_NEGO)
		goto  set_async;
	}
	else if( bval == MSG_RESTORE_PTR)
	    goto  min6;
	else
	    goto  min6;
    }
    else
    {	/* minx: */

	*pSRB->pMsgPtr = bval;
	pSRB->MsgCnt++;
	pSRB->pMsgPtr++;
	if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
	    (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
	{
	    if( pSRB->MsgCnt == 2)
	    {
		pSRB->SRBState = 0;
		bval = pSRB->MsgInBuf[1];
		pSRB = pDCB->pGoingSRB;
		psrb = pDCB->pGoingLast;
		if( pSRB )
		{
		    for( ;; )
		    {
			if(pSRB->TagNumber != bval)
			{
			    if( pSRB == psrb )
				goto  mingx0;
			    pSRB = pSRB->pNextSRB;
			}
			else
			    break;
		    }
		    if( pDCB->DCBFlag & ABORT_DEV_ )
		    {
			pSRB->SRBState = SRB_ABORT_SENT;
			EnableMsgOut( 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] = MSG_ABORT_TAG;
		    EnableMsgOut2( pACB, pSRB );
		}
	    }
	}
	else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
	{
	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
	    {	/* reject_msg: */
		pSRB->MsgCnt = 1;
		pSRB->MsgInBuf[0] = MSG_REJECT_;
		bval = SET_ATN_CMD;
		outb(bval, ioport+ScsiCmd);
	    }
	    else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
	    {
set_async:
		pDCB = pSRB->pSRBDCB;
		pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
		pDCB->SyncPeriod = 0;
		pDCB->SyncOffset = 0;
		pDCB->CtrlR3 = FAST_CLK;     /* ;non_fast */
		pDCB->CtrlR4 &= 0x3f;
		pDCB->CtrlR4 |= EATER_25NS;  /* ; 25ns glitch eater */
		goto  re_prog;
	    }
	    else
	    {	/* set_sync: */

		pDCB = pSRB->pSRBDCB;
		pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
		pDCB->SyncOffset &= 0x0f0;
		pDCB->SyncOffset |= pSRB->MsgInBuf[4];
		pDCB->NegoPeriod = pSRB->MsgInBuf[3];
		wval = (USHORT) pSRB->MsgInBuf[3];
		wval = wval << 2;
		wval--;
		wval1 = wval / 25;
		if( (wval1 * 25) != wval)
		    wval1++;
		bval = FAST_CLK+FAST_SCSI;
		pDCB->CtrlR4 &= 0x3f;
		if(wval1 >= 8)
		{
		    wval1--;
		    bval = FAST_CLK;	    /* ;fast clock/normal scsi */
		    pDCB->CtrlR4 |= EATER_25NS;   /* ;25 ns glitch eater */
		}
		pDCB->CtrlR3 = bval;
		pDCB->SyncPeriod = (UCHAR)wval1;
re_prog:
		bval = pDCB->SyncPeriod;
		outb(bval, ioport+Sync_Period);
		bval = pDCB->SyncOffset;
		outb(bval, ioport+Sync_Offset);
		bval = pDCB->CtrlR3;
		outb(bval, ioport+CtrlReg3);
		bval = pDCB->CtrlR4;
		outb(bval, ioport+CtrlReg4);
		SetXferRate( pACB, pDCB);
	    }
	}
    }
min6:
    *psstatus = SCSI_NOP0;
    bval = MSG_ACCEPTED_CMD;
    outb(bval, ioport+ScsiCmd);
}

static void
DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
{
    PSGL   psgl;
    UCHAR  bval;
    USHORT ioport;
    ULONG  lval;


    ioport = pACB->IOPortBase;
    if( pSRB->SGIndex < pSRB->SGcount )
    {
	bval = DMA_IDLE_CMD | ioDir;   /* ;+EN_DMA_INT */
	outb( bval, ioport+DMA_Cmd);
	if( !pSRB->SGToBeXferLen )
	{
	    psgl = pSRB->pSegmentList;
	    pSRB->SGPhysAddr = virt_to_phys( psgl->address );
	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
	}
	lval = pSRB->SGToBeXferLen;
	bval = (UCHAR) lval;
	outb(bval,ioport+CtcReg_Low);
	lval = lval >> 8;
	bval = (UCHAR) lval;
	outb(bval,ioport+CtcReg_Mid);
	lval = lval >> 8;
	bval = (UCHAR) lval;
	outb(bval,ioport+CtcReg_High);

	lval = pSRB->SGToBeXferLen;
	outl(lval, ioport+DMA_XferCnt);

	lval = pSRB->SGPhysAddr;
	outl( lval, ioport+DMA_XferAddr);

	bval = DMA_COMMAND+INFO_XFER_CMD;
	outb(bval, ioport+ScsiCmd);

	pSRB->SRBState = SRB_DATA_XFER;

	bval = DMA_IDLE_CMD | ioDir;	/* ;+EN_DMA_INT */
	outb(bval, ioport+DMA_Cmd);

	bval = DMA_START_CMD | ioDir;	/* ;+EN_DMA_INT */
	outb(bval, ioport+DMA_Cmd);
    }
    else    /* xfer pad */
    {
	if( pSRB->SGcount )
	{
	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
	    pSRB->SRBStatus |= OVER_RUN;
	}
	bval = 0;
	outb(bval,ioport+CtcReg_Low);
	outb(bval,ioport+CtcReg_Mid);
	outb(bval,ioport+CtcReg_High);

	pSRB->SRBState |= SRB_XFERPAD;
	bval = DMA_COMMAND+XFER_PAD_BYTE;
	outb(bval, ioport+ScsiCmd);
/*
	bval = DMA_IDLE_CMD | ioDir;	;+EN_DMA_INT
	outb(bval, ioport+DMA_Cmd);
	bval = DMA_START_CMD | ioDir;	;+EN_DMA_INT
	outb(bval, ioport+DMA_Cmd);
*/
    }
}


static void
DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR  ioDir;

    ioDir = WRITE_DIRECTION;
    DataIO_Comm( pACB, pSRB, ioDir);
}

static void
DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR  ioDir;

    ioDir = READ_DIRECTION;
    DataIO_Comm( pACB, pSRB, ioDir);
}

static void
DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    PDCB   pDCB;
    UCHAR  bval;
    PUCHAR ptr;
    USHORT ioport, i,  cnt;


    ioport = pACB->IOPortBase;
    bval = RESET_ATN_CMD;
    outb(bval, ioport+ScsiCmd);
    bval = CLEAR_FIFO_CMD;
    outb(bval, ioport+ScsiCmd);
    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
    {
	cnt = (USHORT) pSRB->ScsiCmdLen;
	ptr = (PUCHAR) pSRB->CmdBlock;
	for(i=0; i < cnt; i++)
	{
	    outb(*ptr, ioport+ScsiFifo);
	    ptr++;
	}
    }
    else
    {
	bval = REQUEST_SENSE;
	outb(bval, ioport+ScsiFifo);
	pDCB = pACB->pActiveDCB;
	bval = pDCB->IdentifyMsg << 5;
	outb(bval, ioport+ScsiFifo);
	bval = 0;
	outb(bval, ioport+ScsiFifo);
	outb(bval, ioport+ScsiFifo);
	bval = sizeof(pSRB->pcmd->sense_buffer);
	outb(bval, ioport+ScsiFifo);
	bval = 0;
	outb(bval, ioport+ScsiFifo);
    }
    pSRB->SRBState = SRB_COMMAND;
    bval = INFO_XFER_CMD;
    outb(bval, ioport+ScsiCmd);
}

static void
DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR  bval;
    USHORT ioport;

    ioport = pACB->IOPortBase;
    bval = CLEAR_FIFO_CMD;
    outb(bval, ioport+ScsiCmd);
    pSRB->SRBState = SRB_STATUS;
    bval = INITIATOR_CMD_CMPLTE;
    outb(bval, ioport+ScsiCmd);
}

static void
DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR   bval;
    USHORT  ioport, i, cnt;
    PUCHAR  ptr;
    PDCB    pDCB;

    ioport = pACB->IOPortBase;
    bval = CLEAR_FIFO_CMD;
    outb(bval, ioport+ScsiCmd);
    pDCB = pACB->pActiveDCB;
    if( !(pSRB->SRBState & SRB_MSGOUT) )
    {
	cnt = pSRB->MsgCnt;
	if( cnt )
	{
	    ptr = (PUCHAR) pSRB->MsgOutBuf;
	    for(i=0; i < cnt; i++)
	    {
		outb(*ptr, ioport+ScsiFifo);
		ptr++;
	    }
	    pSRB->MsgCnt = 0;
	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
		(pSRB->MsgOutBuf[0] == MSG_ABORT) )
		pSRB->SRBState = SRB_ABORT_SENT;
	}
	else
	{
	    bval = MSG_ABORT;	/* ??? MSG_NOP */
	    if( (pSRB->CmdBlock[0] == INQUIRY ) ||
		(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
		(pSRB->SRBFlag & AUTO_REQSENSE) )
	    {
		if( pDCB->SyncMode & SYNC_ENABLE )
		    goto  mop1;
	    }
	    outb(bval, ioport+ScsiFifo);
	}
	bval = INFO_XFER_CMD;
	outb( bval, ioport+ScsiCmd);
    }
    else
    {
mop1:
	bval = MSG_EXTENDED;
	outb(bval, ioport+ScsiFifo);
	bval = 3;	/*    ;length of extended msg */
	outb(bval, ioport+ScsiFifo);
	bval = 1;	/*    ; sync nego */
	outb(bval, ioport+ScsiFifo);
	bval = pDCB->NegoPeriod;
	outb(bval, ioport+ScsiFifo);
	bval = SYNC_NEGO_OFFSET;
	outb(bval, ioport+ScsiFifo);
	pSRB->SRBState |= DO_SYNC_NEGO;
	bval = INFO_XFER_CMD;
	outb(bval, ioport+ScsiCmd);
    }
}

static void
DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
    UCHAR  bval;
    USHORT ioport;

    ioport = pACB->IOPortBase;
    bval = CLEAR_FIFO_CMD;
    outb(bval, ioport+ScsiCmd);
    if( !(pSRB->SRBState & SRB_MSGIN) )
    {
	pSRB->SRBState &= SRB_DISCONNECT;
	pSRB->SRBState |= SRB_MSGIN;
    }
    bval = INFO_XFER_CMD;
    outb(bval, ioport+ScsiCmd);
}

static void
DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
}

static void
DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
}


static void
SetXferRate( PACB pACB, PDCB pDCB )
{
    UCHAR  bval;
    USHORT cnt, i;
    PDCB   ptr;

    if( !(pDCB->IdentifyMsg & 0x07) )
    {
	if( pACB->scan_devices )
	{
	    CurrSyncOffset = pDCB->SyncOffset;
	}
	else
	{
	    ptr = pACB->pLinkDCB;
	    cnt = pACB->DeviceCnt;
	    bval = pDCB->UnitSCSIID;
	    for(i=0; i<cnt; i++)
	    {
		if( ptr->UnitSCSIID == 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( PACB pACB )
{
    PDCB   pDCB;
    PSRB   pSRB, psrb;
    ULONG  flags;
    USHORT ioport, i, cnt;
    UCHAR  bval;

#ifdef DC390_DEBUG0
    printk("DISC,");
#endif

    save_flags(flags);
    cli();
    ioport = pACB->IOPortBase;
    pDCB = pACB->pActiveDCB;
    if (!pDCB)
     {
#ifdef DC390_DEBUG0
	printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
#endif
	restore_flags(flags); return;
     }
    pSRB = pDCB->pActiveSRB;
    pACB->pActiveDCB = 0;
    pSRB->ScsiPhase = SCSI_NOP0;
    bval = EN_SEL_RESEL;
    outb(bval, ioport+ScsiCmd);
    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
    {
	pSRB->SRBState = 0;
	DoWaitingSRB( pACB );
    }
    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;
	    pSRB->pNextSRB = pACB->pFreeSRB;
	    pACB->pFreeSRB = pSRB;
	    pSRB = psrb;
	}
	pDCB->pGoingSRB = 0;
	DoWaitingSRB( pACB );
    }
    else
    {
	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
	{	/* Selection time out */
	    if( !(pACB->scan_devices) )
	    {
		pSRB->SRBState = SRB_READY;
		RewaitSRB( pDCB, pSRB);
	    }
	    else
	    {
		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
		goto  disc1;
	    }
	}
	else if( pSRB->SRBState & SRB_DISCONNECT )
	{
	    DoWaitingSRB( pACB );
	}
	else if( pSRB->SRBState & SRB_COMPLETED )
	{
disc1:
	    if(pDCB->MaxCommand > 1)
	    {
	       bval = pSRB->TagNumber;
	       pDCB->TagMask &= (~(1 << bval));   /* free tag mask */
	    }
	    pDCB->pActiveSRB = 0;
	    pSRB->SRBState = SRB_FREE;
	    SRBdone( pACB, pDCB, pSRB);
	}
    }
    restore_flags(flags);
    return;
}


static void
DC390_Reselect( PACB pACB )
{
    PDCB   pDCB, pdcb;
    PSRB   pSRB;
    USHORT ioport, wval;
    UCHAR  bval, bval1;


#ifdef DC390_DEBUG0
    printk("RSEL,");
#endif
    ioport = pACB->IOPortBase;
    pDCB = pACB->pActiveDCB;
    if( pDCB )
    {	/* Arbitration lost but Reselection win */
	pSRB = pDCB->pActiveSRB;
	if( !( pACB->scan_devices ) )
	{
	    pSRB->SRBState = SRB_READY;
	    RewaitSRB( pDCB, pSRB);
	}
    }
    bval = inb(ioport+ScsiFifo);	/* get ID */
    bval = bval ^ pACB->HostID_Bit;
    wval = 0;
    bval1 = 1;
    for(;;)
    {
	if( !(bval & bval1) )
	{
	    bval1 = bval1 << 1;
	    wval++;
	}
	else
	    break;
    }
    wval |=  ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8;  /* get LUN */
    pDCB = pACB->pLinkDCB;
    pdcb = pDCB;
    while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
    {
	pDCB = pDCB->pNextDCB;
	if( pDCB == pdcb )
	    return;
    }
    pACB->pActiveDCB = pDCB;
    if( pDCB->SyncMode & EN_TAG_QUEUING )
    {
	pSRB = pACB->pTmpSRB;
	pDCB->pActiveSRB = pSRB;
    }
    else
    {
	pSRB = pDCB->pActiveSRB;
	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
	{
	    pSRB= pACB->pTmpSRB;
	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
	    pDCB->pActiveSRB = pSRB;
	    EnableMsgOut( pACB, pSRB );
	}
	else
	{
	    if( pDCB->DCBFlag & ABORT_DEV_ )
	    {
		pSRB->SRBState = SRB_ABORT_SENT;
		EnableMsgOut( pACB, pSRB );
	    }
	    else
		pSRB->SRBState = SRB_DATA_XFER;
	}
    }
    pSRB->ScsiPhase = SCSI_NOP0;
    bval = pDCB->UnitSCSIID;
    outb( bval, ioport+Scsi_Dest_ID);
    bval = pDCB->SyncPeriod;
    outb(bval, ioport+Sync_Period);
    bval = pDCB->SyncOffset;
    outb( bval, ioport+Sync_Offset);
    bval = pDCB->CtrlR1;
    outb(bval, ioport+CtrlReg1);
    bval = pDCB->CtrlR3;
    outb(bval, ioport+CtrlReg3);
    bval = pDCB->CtrlR4;	/* ; Glitch eater */
    outb(bval, ioport+CtrlReg4);
    bval = MSG_ACCEPTED_CMD;	/* ;to rls the /ACK signal */
    outb(bval, ioport+ScsiCmd);
}


static void
SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
{
    PSRB   psrb;
    UCHAR  bval, bval1, i, j, status;
    PSCSICMD pcmd;
    PSCSI_INQDATA  ptr;
    USHORT disable_tag;
    ULONG  flags;
    PSGL   ptr2;
    ULONG  swlval;

    pcmd = pSRB->pcmd;
    status = pSRB->TargetStatus;
    if(pSRB->SRBFlag & AUTO_REQSENSE)
    {
	pSRB->SRBFlag &= ~AUTO_REQSENSE;
	pSRB->AdaptStatus = 0;
	pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
	if(status == SCSI_STAT_CHECKCOND)
	{
	    pcmd->result = DID_BAD_TARGET << 16;
	    goto ckc_e;
	}
	if(pSRB->RetryCnt == 0)
	{
	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
	    pSRB->TotalXferredLen = pSRB->Segment1[1];
	    if( (pSRB->TotalXferredLen) &&
		(pSRB->TotalXferredLen >= pcmd->underflow) )
		pcmd->result |= (DID_OK << 16);
	    else
		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
				SCSI_STAT_CHECKCOND;
#ifdef DC390_DEBUG0
	printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
#endif
	    goto ckc_e;
	}
	else
	{
	    pSRB->RetryCnt--;
	    pSRB->AdaptStatus = 0;
	    pSRB->TargetStatus = 0;
	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
	    *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
	    {
		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
				SCSI_STAT_CHECKCOND;
		goto ckc_e;
	    }
	    pcmd->result |= (DRIVER_SENSE << 24);
	    pSRB->SGcount		 = (UCHAR) pSRB->Segment1[0];
	    pSRB->ScsiCmdLen		 = (UCHAR) (pSRB->Segment1[0] >> 8);
	    pSRB->SGIndex = 0;
	    pSRB->TotalXferredLen = 0;
	    pSRB->SGToBeXferLen = 0;
	    if( pcmd->use_sg )
		pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
	    else if( pcmd->request_buffer )
	    {
		pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
		pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
		pSRB->Segmentx.length = pcmd->request_bufflen;
	    }
	    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
		RewaitSRB( pDCB, pSRB );
	    return;
	}
    }
    if( status )
    {
	if( status == SCSI_STAT_CHECKCOND)
	{
	    if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
	    {
		bval = pSRB->SGcount;
		swlval = 0;
		ptr2 = pSRB->pSegmentList;
		for( i=pSRB->SGIndex; i < bval; i++)
		{
		    swlval += ptr2->length;
		    ptr2++;
		}
#ifdef	DC390_DEBUG0
		printk("XferredLen=%8x,NotXferLen=%8x,",
			(UINT) pSRB->TotalXferredLen, (UINT) swlval);
#endif
	    }
	    RequestSense( pACB, pDCB, pSRB );
	    return;
	}
	else if( status == SCSI_STAT_QUEUEFULL )
	{
	    bval = (UCHAR) pDCB->GoingSRBCnt;
	    bval--;
	    pDCB->MaxCommand = bval;
	    RewaitSRB( pDCB, pSRB );
	    pSRB->AdaptStatus = 0;
	    pSRB->TargetStatus = 0;
	    return;
	}
	else if(status == SCSI_STAT_SEL_TIMEOUT)
	{
	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
	    pSRB->TargetStatus = 0;
	    pcmd->result = DID_BAD_TARGET << 16;
	}
	else
	{
	    pSRB->AdaptStatus = 0;
	    if( pSRB->RetryCnt )
	    {
		pSRB->RetryCnt--;
		pSRB->TargetStatus = 0;
		pSRB->SGIndex = 0;
		pSRB->TotalXferredLen = 0;
		pSRB->SGToBeXferLen = 0;
		if( pcmd->use_sg )
		    pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
		else if( pcmd->request_buffer )
		{
		    pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
		    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
		    pSRB->Segmentx.length = pcmd->request_bufflen;
		}
		if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
		    RewaitSRB( pDCB, pSRB );
		return;
	    }
	    else
	    {
		pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
			       (ULONG) status;
	    }
	}
    }
    else
    {
	status = pSRB->AdaptStatus;
	if(status & H_OVER_UNDER_RUN)
	{
	    pSRB->TargetStatus = 0;
	    pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
	}
	else if( pSRB->SRBStatus & PARITY_ERROR)
	{
	    pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
	}
	else		       /* No error */
	{
	    pSRB->AdaptStatus = 0;
	    pSRB->TargetStatus = 0;
	    pcmd->result |= (DID_OK << 16);
	}
    }

ckc_e:
    if( pACB->scan_devices )
    {
	if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
	{
	    if(pcmd->result != (DID_OK << 16))
	    {
		if( pcmd->result & SCSI_STAT_CHECKCOND )
		{
		    goto RTN_OK;
		}
		else
		{
		    pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
		    pPrevDCB->pNextDCB = pACB->pLinkDCB;
		    if( (pcmd->target == pACB->max_id) &&
		       ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
		    {
			pACB->scan_devices = 0;
		    }
		}
	    }
	    else
	    {
RTN_OK:
		pPrevDCB->pNextDCB = pDCB;
		pDCB->pNextDCB = pACB->pLinkDCB;
		if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
		    pACB->scan_devices = END_SCAN;
	    }
	}
	else if( pSRB->CmdBlock[0] == INQUIRY )
	{
	    if( (pcmd->target == pACB->max_id) &&
		(pcmd->lun == pACB->max_lun) )
	    {
		pACB->scan_devices = 0;
	    }
	    ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
	    if( pcmd->use_sg )
		ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
	    bval1 = ptr->DevType & SCSI_DEVTYPE;
	    if(bval1 == SCSI_NODEV)
	    {
		pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
		pPrevDCB->pNextDCB = pACB->pLinkDCB;
	    }
	    else
	    {
		pACB->DeviceCnt++;
		pPrevDCB = pDCB;
		pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
		pDCB->DevType = bval1;
		if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
		{
		    if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
			(ptr->Flags & SCSI_INQ_CMDQUEUE) &&
			(pDCB->DevMode & TAG_QUEUING_) &&
			(pDCB->DevMode & EN_DISCONNECT_) )
		    {
			disable_tag = 0;
			for(i=0; i<BADDEVCNT; i++)
			{
			    for(j=0; j<28; j++)
			    {
				if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
				    break;
			    }
			    if(j == 28)
			    {
				disable_tag = 1;
				break;
			    }
			}

			if( !disable_tag )
			{
			    pDCB->MaxCommand = pACB->TagMaxNum;
			    pDCB->SyncMode |= EN_TAG_QUEUING;
			    pDCB->TagMask = 0;
			}
			else
			{
			    pDCB->SyncMode |= EN_ATN_STOP;
			}
		    }
		}
	    }
	}
    }

    save_flags( flags );
    cli();
/*  ReleaseSRB( pDCB, pSRB ); */

    if(pSRB == pDCB->pGoingSRB )
    {
	pDCB->pGoingSRB = pSRB->pNextSRB;
    }
    else
    {
	psrb = pDCB->pGoingSRB;
	while( psrb->pNextSRB != pSRB )
	    psrb = psrb->pNextSRB;
	psrb->pNextSRB = pSRB->pNextSRB;
	if( pSRB == pDCB->pGoingLast )
	    pDCB->pGoingLast = psrb;
    }
    pSRB->pNextSRB = pACB->pFreeSRB;
    pACB->pFreeSRB = pSRB;
    pDCB->GoingSRBCnt--;

    DoWaitingSRB( pACB );
    restore_flags(flags);

/*  Notify cmd done */
    pcmd->scsi_done( pcmd );

    if( pDCB->QIORBCnt )
	DoNextCmd( pACB, pDCB );
    return;
}


static void
DoingSRB_Done( PACB pACB )
{
    PDCB  pDCB, pdcb;
    PSRB  psrb, psrb2;
    USHORT  cnt, i;
    PSCSICMD pcmd;

    pDCB = pACB->pLinkDCB;
    pdcb = pDCB;
    do
    {
	cnt = pdcb->GoingSRBCnt;
	psrb = pdcb->pGoingSRB;
	for( i=0; i<cnt; i++)
	{
	    psrb2 = psrb->pNextSRB;
	    pcmd = psrb->pcmd;
	    pcmd->result = DID_RESET << 16;

/*	    ReleaseSRB( pDCB, pSRB ); */

	    psrb->pNextSRB = pACB->pFreeSRB;
	    pACB->pFreeSRB = psrb;

	    pcmd->scsi_done( pcmd );
	    psrb  = psrb2;
	}
	pdcb->GoingSRBCnt = 0;;
	pdcb->pGoingSRB = NULL;
	pdcb->TagMask = 0;
	pdcb = pdcb->pNextDCB;
    }
    while( pdcb != pDCB );
}


static void
DC390_ResetSCSIBus( PACB pACB )
{
    USHORT ioport;
    UCHAR  bval;
    ULONG  flags;

    save_flags(flags);
    cli();
    pACB->ACBFlag |= RESET_DEV;
    ioport = pACB->IOPortBase;

    bval = DMA_IDLE_CMD;
    outb(bval,ioport+DMA_Cmd);

    bval = RST_SCSI_BUS_CMD;
    outb(bval,ioport+ScsiCmd);

    restore_flags(flags);
    return;
}


static void
DC390_ScsiRstDetect( PACB pACB )
{
    ULONG wlval, flags;
    USHORT ioport;
    UCHAR  bval;

#ifdef DC390_DEBUG0
    printk("RST_DETEC");
#endif

    /* delay a second */
    mdelay(1000);

    save_flags(flags);
    cli();

    ioport = pACB->IOPortBase;
    bval = DMA_IDLE_CMD;
    outb(bval,ioport+DMA_Cmd);
    bval = CLEAR_FIFO_CMD;
    outb(bval,ioport+ScsiCmd);

    if( pACB->ACBFlag & RESET_DEV )
	pACB->ACBFlag |= RESET_DONE;
    else
    {
	pACB->ACBFlag |= RESET_DETECT;

	ResetDevParam( pACB );
/*	DoingSRB_Done( pACB ); ???? */
	RecoverSRB( pACB );
	pACB->pActiveDCB = NULL;
	pACB->ACBFlag = 0;
	DoWaitingSRB( pACB );
    }
    restore_flags(flags);
    return;
}


static void
RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
{
    PSCSICMD  pcmd;

    pSRB->SRBFlag |= AUTO_REQSENSE;
    pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
    pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
    pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
    pSRB->Segment1[1] = pSRB->TotalXferredLen;
    pSRB->AdaptStatus = 0;
    pSRB->TargetStatus = 0;

    pcmd = pSRB->pcmd;

    pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer);
    pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
    pSRB->pSegmentList = &pSRB->Segmentx;
    pSRB->SGcount = 1;
    pSRB->SGIndex = 0;

    *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
    pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
    *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
    pSRB->ScsiCmdLen = 6;

    pSRB->TotalXferredLen = 0;
    pSRB->SGToBeXferLen = 0;
    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
	RewaitSRB( pDCB, pSRB );
}


static void
EnableMsgOut2( PACB pACB, PSRB pSRB )
{
    USHORT ioport;
    UCHAR  bval;

    ioport = pACB->IOPortBase;
    pSRB->MsgCnt = 1;
    bval = SET_ATN_CMD;
    outb(bval, ioport+ScsiCmd);
}


static void
EnableMsgOut( PACB pACB, PSRB pSRB )
{
    pSRB->MsgOutBuf[0] = MSG_ABORT;
    EnableMsgOut2( pACB, pSRB );
}


static void
DC390_InvalidCmd( PACB pACB )
{
   UCHAR bval;
   USHORT ioport;
   PSRB   pSRB;

    pSRB = pACB->pActiveDCB->pActiveSRB;
    if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
    {
	ioport = pACB->IOPortBase;
	bval = CLEAR_FIFO_CMD;
	outb(bval,(ioport+ScsiCmd));
    }
}

