1996-12-15 23:40:48 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* FILE NAME : TEK390.C *
|
|
|
|
* BY : C.L. Huang (ching@tekram.com.tw) *
|
|
|
|
* Description: Device Driver for Tekram DC-390(T) PCI SCSI *
|
|
|
|
* Bus Master Host Adapter *
|
|
|
|
* (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
|
|
|
|
***********************************************************************/
|
|
|
|
/***********************************************************************
|
|
|
|
* HISTORY: *
|
|
|
|
* *
|
|
|
|
* REV# DATE NAME DESCRIPTION *
|
|
|
|
* 1.00 07/02/96 CLH First release for RELEASE-2.1.0 *
|
|
|
|
* 1.01 08/20/96 CLH Update for RELEASE-2.1.5 *
|
|
|
|
* *
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
1996-12-18 01:08:05 +00:00
|
|
|
/**************************************************************************/
|
|
|
|
/* Imported into FreeBSD source repository, and updated to compile under */
|
|
|
|
/* FreeBSD-3.0-DEVELOPMENT, by Stefan Esser <se@FreeBSD.Org>, 1996-12-17 */
|
|
|
|
/**************************************************************************/
|
|
|
|
|
1996-12-15 23:40:48 +00:00
|
|
|
/* #define REL_2_1_0 */
|
|
|
|
#define REL_2_1_5
|
|
|
|
|
|
|
|
#define DC390_DEBUG
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
|
1996-12-18 11:41:28 +00:00
|
|
|
/* XXX this doesn't actually compile unless KERNEL is defined. */
|
1996-12-15 23:40:48 +00:00
|
|
|
#ifdef KERNEL
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
|
|
|
|
#include <vm/vm.h>
|
1996-12-18 11:41:28 +00:00
|
|
|
#include <vm/pmap.h>
|
1996-12-15 23:40:48 +00:00
|
|
|
#endif /* KERNEL */
|
|
|
|
|
|
|
|
#include <pci/pcivar.h>
|
|
|
|
#include <pci/pcireg.h>
|
|
|
|
|
|
|
|
#include <scsi/scsiconf.h>
|
|
|
|
|
|
|
|
#include <machine/clock.h>
|
|
|
|
|
1996-12-18 11:41:28 +00:00
|
|
|
#include <pci/tek390.h>
|
1996-12-15 23:40:48 +00:00
|
|
|
|
|
|
|
#define INT32 int32
|
|
|
|
#define U_INT32 u_int32
|
|
|
|
|
|
|
|
|
|
|
|
#define OutB(val, port) outb(port, val)
|
|
|
|
#define OutW(val, port) outw(port, val)
|
|
|
|
#define OutL(val, port) outl(port, val)
|
|
|
|
|
|
|
|
#define PCI_DEVICE_ID_AMD53C974 0x20201022ul
|
|
|
|
#define PCI_BASE_ADDR0 0x10
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef REL_2_1_0
|
|
|
|
static int DC390_Interrupt (PACB pACB);
|
|
|
|
#endif
|
|
|
|
#ifdef REL_2_1_5
|
|
|
|
static void DC390_Interrupt (PACB pACB);
|
|
|
|
#endif
|
|
|
|
static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
|
|
|
|
static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
|
|
|
|
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 );
|
|
|
|
static void DC390_Disconnect( PACB pACB );
|
|
|
|
static void DC390_Reselect( PACB pACB );
|
|
|
|
static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
|
|
|
|
static void DoingSRB_Done( PACB pACB );
|
|
|
|
static void DC390_ScsiRstDetect( PACB pACB );
|
|
|
|
static void DC390_ResetSCSIBus( PACB pACB );
|
|
|
|
static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
|
|
|
|
static void EnableMsgOut2( PACB pACB, PSRB pSRB );
|
|
|
|
static void EnableMsgOut( PACB pACB, PSRB pSRB );
|
|
|
|
static void DC390_InvalidCmd( PACB pACB );
|
|
|
|
|
1997-09-21 22:02:25 +00:00
|
|
|
/*
|
|
|
|
* XXX No timeouts are scheduled in this driver as the timeout handler
|
|
|
|
* doesn't do anything yet!!!
|
|
|
|
*/
|
1996-12-15 23:40:48 +00:00
|
|
|
static void DC390_reset (PACB pACB);
|
|
|
|
static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt );
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
|
|
|
|
static void DC390_initSRB( PSRB psrb );
|
|
|
|
static void DC390_linkSRB( PACB pACB );
|
|
|
|
static void DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq,
|
|
|
|
USHORT index );
|
|
|
|
static int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq,
|
|
|
|
USHORT index, pcici_t config_id );
|
1996-12-15 23:40:48 +00:00
|
|
|
void DC390_EnableCfg( USHORT mechnum, UCHAR regval );
|
|
|
|
void DC390_DisableCfg( USHORT mechnum );
|
|
|
|
UCHAR DC390_inByte( USHORT mechnum, UCHAR regval );
|
|
|
|
USHORT DC390_inWord( USHORT mechnum, UCHAR regval );
|
|
|
|
ULONG DC390_inDword(USHORT mechnum, UCHAR regval );
|
|
|
|
void DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval );
|
1998-02-09 06:11:36 +00:00
|
|
|
static void DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval );
|
|
|
|
static void DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry );
|
|
|
|
static UCHAR DC390_EEpromInDO( USHORT mechnum );
|
|
|
|
static USHORT EEpromGetData1( USHORT mechnum );
|
|
|
|
static void DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd );
|
|
|
|
static void DC390_ReadEEprom( USHORT mechnum, USHORT index );
|
|
|
|
static USHORT DC390_DefaultEEprom( USHORT mechnum, USHORT index );
|
|
|
|
static USHORT DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index );
|
|
|
|
static USHORT DC390_ToMech( USHORT Mechnum, pcici_t config_id );
|
1996-12-15 23:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef KERNEL
|
|
|
|
|
|
|
|
static char* trmamd_probe( pcici_t tag, pcidi_t type);
|
|
|
|
static void trmamd_attach( pcici_t tag, int unit);
|
|
|
|
|
|
|
|
#ifdef REL_2_1_0
|
|
|
|
static int32 trmamd_scsi_cmd( struct scsi_xfer *sx);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef REL_2_1_5
|
|
|
|
static int32_t trmamd_scsi_cmd( struct scsi_xfer *sx);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void trmamd_min_phys( struct buf *pbuf);
|
|
|
|
|
|
|
|
#ifdef REL_2_1_0
|
|
|
|
static u_int32 trmamd_info( int unit );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* KERNEL */
|
|
|
|
|
|
|
|
|
|
|
|
static u_long trmamd_count;
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static struct pci_device trmamd_device = {
|
1996-12-20 21:52:11 +00:00
|
|
|
"amd",
|
1996-12-15 23:40:48 +00:00
|
|
|
trmamd_probe,
|
|
|
|
trmamd_attach,
|
|
|
|
&trmamd_count,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
DATA_SET (pcidevice_set, trmamd_device);
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static struct scsi_adapter trmamd_switch =
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
trmamd_scsi_cmd,
|
|
|
|
trmamd_min_phys,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
#ifdef REL_2_1_0
|
|
|
|
trmamd_info,
|
|
|
|
#endif
|
|
|
|
#ifdef REL_2_1_5
|
|
|
|
0,
|
|
|
|
#endif
|
1996-12-20 21:52:11 +00:00
|
|
|
"amd",
|
1996-12-15 23:40:48 +00:00
|
|
|
};
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static struct scsi_device trmamd_dev =
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
NULL, /* Use default error handler */
|
|
|
|
NULL, /* have a queue, served by this */
|
|
|
|
NULL, /* have no async handler */
|
|
|
|
NULL, /* Use default 'done' routine */
|
1996-12-20 21:52:11 +00:00
|
|
|
"amd",
|
1996-12-15 23:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PACB pACB0[MAX_ADAPTER_NUM]={0};
|
|
|
|
static PACB pACB_start= NULL;
|
|
|
|
static PACB pACB_current = NULL;
|
|
|
|
static PDCB pPrevDCB = NULL;
|
|
|
|
static USHORT adapterCnt = 0;
|
|
|
|
static USHORT CurrSyncOffset = 0;
|
1997-11-07 08:53:44 +00:00
|
|
|
static UCHAR CurrentID, CurrentLUN;
|
1996-12-15 23:40:48 +00:00
|
|
|
|
|
|
|
static PVOID DC390_phase0[]={
|
|
|
|
DC390_DataOut_0,
|
|
|
|
DC390_DataIn_0,
|
|
|
|
DC390_Command_0,
|
|
|
|
DC390_Status_0,
|
|
|
|
DC390_Nop_0,
|
|
|
|
DC390_Nop_0,
|
|
|
|
DC390_MsgOut_0,
|
|
|
|
DC390_MsgIn_0,
|
|
|
|
DC390_Nop_1
|
|
|
|
};
|
|
|
|
|
|
|
|
static PVOID DC390_phase1[]={
|
|
|
|
DC390_DataOutPhase,
|
|
|
|
DC390_DataInPhase,
|
|
|
|
DC390_CommandPhase,
|
|
|
|
DC390_StatusPhase,
|
|
|
|
DC390_Nop_0,
|
|
|
|
DC390_Nop_0,
|
|
|
|
DC390_MsgOutPhase,
|
|
|
|
DC390_MsgInPhase,
|
|
|
|
DC390_Nop_1,
|
|
|
|
};
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
|
1996-12-15 23:40:48 +00:00
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static UCHAR clock_period1[] = {4, 5, 6, 7 ,8, 10, 13, 20};
|
1996-12-15 23:40:48 +00:00
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static UCHAR baddevname1[2][28] ={
|
1996-12-15 23:40:48 +00:00
|
|
|
"SEAGATE ST3390N ??? 9546",
|
|
|
|
"HP C3323-300 4269"};
|
|
|
|
|
|
|
|
#define BADDEVCNT 2
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**********************************************************************/
|
|
|
|
static PSRB
|
|
|
|
GetSRB( PACB pACB )
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
PSRB pSRB;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
pSRB = pACB->pFreeSRB;
|
|
|
|
if( pSRB )
|
|
|
|
{
|
|
|
|
pACB->pFreeSRB = pSRB->pNextSRB;
|
|
|
|
pSRB->pNextSRB = NULL;
|
|
|
|
}
|
|
|
|
splx(flags);
|
|
|
|
return( pSRB );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
RewaitSRB0( PDCB pDCB, PSRB pSRB )
|
|
|
|
{
|
|
|
|
PSRB psrb1;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
if( (psrb1 = pDCB->pWaitingSRB) )
|
|
|
|
{
|
|
|
|
pSRB->pNextSRB = psrb1;
|
|
|
|
pDCB->pWaitingSRB = pSRB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pSRB->pNextSRB = NULL;
|
|
|
|
pDCB->pWaitingSRB = pSRB;
|
|
|
|
pDCB->pWaitLast = pSRB;
|
|
|
|
}
|
|
|
|
splx(flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
RewaitSRB( PDCB pDCB, PSRB pSRB )
|
|
|
|
{
|
|
|
|
PSRB psrb1;
|
|
|
|
int flags;
|
|
|
|
UCHAR bval;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
pDCB->GoingSRBCnt--;
|
|
|
|
psrb1 = pDCB->pGoingSRB;
|
|
|
|
if( pSRB == psrb1 )
|
|
|
|
{
|
|
|
|
pDCB->pGoingSRB = psrb1->pNextSRB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while( pSRB != psrb1->pNextSRB )
|
|
|
|
psrb1 = psrb1->pNextSRB;
|
|
|
|
psrb1->pNextSRB = pSRB->pNextSRB;
|
|
|
|
if( pSRB == pDCB->pGoingLast )
|
|
|
|
pDCB->pGoingLast = psrb1;
|
|
|
|
}
|
|
|
|
if( (psrb1 = pDCB->pWaitingSRB) )
|
|
|
|
{
|
|
|
|
pSRB->pNextSRB = psrb1;
|
|
|
|
pDCB->pWaitingSRB = pSRB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pSRB->pNextSRB = NULL;
|
|
|
|
pDCB->pWaitingSRB = pSRB;
|
|
|
|
pDCB->pWaitLast = pSRB;
|
|
|
|
}
|
|
|
|
|
|
|
|
bval = pSRB->TagNumber;
|
|
|
|
pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */
|
|
|
|
splx(flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
DoWaitingSRB( PACB pACB )
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
PDCB ptr, ptr1;
|
|
|
|
PSRB pSRB;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
|
|
|
|
{
|
|
|
|
ptr = pACB->pDCBRunRobin;
|
|
|
|
if( !ptr )
|
|
|
|
{
|
|
|
|
ptr = pACB->pLinkDCB;
|
|
|
|
pACB->pDCBRunRobin = ptr;
|
|
|
|
}
|
|
|
|
ptr1 = ptr;
|
|
|
|
for( ;ptr1; )
|
|
|
|
{
|
|
|
|
pACB->pDCBRunRobin = ptr1->pNextDCB;
|
|
|
|
if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) ||
|
|
|
|
!( pSRB = ptr1->pWaitingSRB ) )
|
|
|
|
{
|
|
|
|
if(pACB->pDCBRunRobin == ptr)
|
|
|
|
break;
|
|
|
|
ptr1 = ptr1->pNextDCB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
|
|
|
|
{
|
|
|
|
ptr1->GoingSRBCnt++;
|
|
|
|
if( ptr1->pWaitLast == pSRB )
|
|
|
|
{
|
|
|
|
ptr1->pWaitingSRB = NULL;
|
|
|
|
ptr1->pWaitLast = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr1->pWaitingSRB = pSRB->pNextSRB;
|
|
|
|
}
|
|
|
|
pSRB->pNextSRB = NULL;
|
|
|
|
|
|
|
|
if( ptr1->pGoingSRB )
|
|
|
|
ptr1->pGoingLast->pNextSRB = pSRB;
|
|
|
|
else
|
|
|
|
ptr1->pGoingSRB = pSRB;
|
|
|
|
ptr1->pGoingLast = pSRB;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
splx(flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
SRBwaiting( PDCB pDCB, PSRB pSRB)
|
|
|
|
{
|
|
|
|
if( pDCB->pWaitingSRB )
|
|
|
|
{
|
|
|
|
pDCB->pWaitLast->pNextSRB = pSRB;
|
|
|
|
pDCB->pWaitLast = pSRB;
|
|
|
|
pSRB->pNextSRB = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pDCB->pWaitingSRB = pSRB;
|
|
|
|
pDCB->pWaitLast = pSRB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
PDCB pDCB;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
pDCB = pSRB->pSRBDCB;
|
|
|
|
if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
|
|
|
|
(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
|
|
|
|
{
|
|
|
|
SRBwaiting(pDCB, pSRB);
|
|
|
|
goto SND_EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pDCB->pWaitingSRB )
|
|
|
|
{
|
|
|
|
SRBwaiting(pDCB, pSRB);
|
|
|
|
/* pSRB = GetWaitingSRB(pDCB); */
|
|
|
|
pSRB = pDCB->pWaitingSRB;
|
|
|
|
pDCB->pWaitingSRB = pSRB->pNextSRB;
|
|
|
|
pSRB->pNextSRB = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
|
|
|
|
{
|
|
|
|
pDCB->GoingSRBCnt++;
|
|
|
|
if( pDCB->pGoingSRB )
|
|
|
|
{
|
|
|
|
pDCB->pGoingLast->pNextSRB = pSRB;
|
|
|
|
pDCB->pGoingLast = pSRB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pDCB->pGoingSRB = pSRB;
|
|
|
|
pDCB->pGoingLast = pSRB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
RewaitSRB0( pDCB, pSRB );
|
|
|
|
|
|
|
|
SND_EXIT:
|
|
|
|
splx(flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : static int32 dc390_scsi_cmd (struct scsi_xfer *cmd)
|
|
|
|
* Purpose : enqueues a SCSI command
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
#ifdef REL_2_1_0
|
|
|
|
int32
|
|
|
|
#endif
|
|
|
|
#ifdef REL_2_1_5
|
|
|
|
int32_t
|
|
|
|
#endif
|
|
|
|
trmamd_scsi_cmd ( PSCSICMD cmd )
|
|
|
|
{
|
|
|
|
USHORT ioport, i;
|
|
|
|
PSCSICMD pcmd;
|
|
|
|
PSCLINK plink;
|
|
|
|
PACB pACB;
|
|
|
|
PDCB pDCB;
|
|
|
|
PSRB pSRB;
|
|
|
|
int flags, cflags, unit, CurrPgVaddr;
|
|
|
|
ULONG sglen, pglen, datalen, CurrPgPaddr, NextPgPaddr;
|
|
|
|
PUCHAR ptr,ptr1;
|
|
|
|
PSEG psg;
|
|
|
|
UCHAR sgc, sstatus;
|
|
|
|
|
|
|
|
plink = cmd->sc_link;
|
|
|
|
unit = plink->adapter_unit;
|
|
|
|
pACB = pACB0[unit];
|
|
|
|
ioport = pACB->IOPortBase;
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmd->opcode,
|
|
|
|
plink->target, plink->lun);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( pACB->scan_devices )
|
|
|
|
{
|
1996-12-20 21:52:11 +00:00
|
|
|
if( (plink->target > CurrentID) ||
|
|
|
|
(plink->target == CurrentID) && (plink->lun >= CurrentLUN) )
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
CurrentID = plink->target;
|
|
|
|
CurrentLUN = plink->lun;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pACB->scan_devices = 0;
|
|
|
|
pPrevDCB->pNextDCB = pACB->pLinkDCB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ( plink->target > pACB->max_id ) || ( plink->lun > pACB->max_lun ) )
|
|
|
|
{
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("DC390: Ignore target %d lun %d\n",
|
|
|
|
plink->target, plink->lun);
|
|
|
|
#endif
|
|
|
|
cmd->error = XS_DRIVER_STUFFUP;
|
|
|
|
return( COMPLETE );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( (pACB->scan_devices) && !(pACB->DCBmap[plink->target] & (1 << plink->lun)) )
|
|
|
|
{
|
|
|
|
if( pACB->DeviceCnt < MAX_DEVICES )
|
|
|
|
{
|
|
|
|
pACB->DCBmap[plink->target] |= (1 << plink->lun);
|
|
|
|
pDCB = pACB->pDCB_free;
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("pDCB=%8x,ID=%2x,", (UINT) pDCB, plink->target);
|
|
|
|
#endif
|
|
|
|
DC390_initDCB( pACB, pDCB, cmd );
|
|
|
|
}
|
|
|
|
else /* ???? */
|
|
|
|
{
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("DC390: Ignore target %d lun %d\n",
|
|
|
|
plink->target, plink->lun);
|
|
|
|
#endif
|
|
|
|
cmd->error = XS_DRIVER_STUFFUP;
|
|
|
|
return( COMPLETE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( !(pACB->scan_devices) && !(pACB->DCBmap[plink->target] & (1 << plink->lun)) )
|
|
|
|
{
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("DC390: Ignore target %d lun %d\n",
|
|
|
|
plink->target, plink->lun);
|
|
|
|
#endif
|
|
|
|
cmd->error = XS_DRIVER_STUFFUP;
|
|
|
|
return( COMPLETE );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pDCB = pACB->pLinkDCB;
|
|
|
|
while( (pDCB->UnitSCSIID != plink->target) ||
|
|
|
|
(pDCB->UnitSCSILUN != plink->lun) )
|
|
|
|
{
|
|
|
|
pDCB = pDCB->pNextDCB;
|
|
|
|
}
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("pDCB=%8x,ID=%2x,", (UINT) pDCB, plink->target);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
cflags = cmd->flags;
|
|
|
|
if(cflags & SCSI_RESET)
|
|
|
|
{
|
|
|
|
DC390_reset (pACB);
|
|
|
|
cmd->error = XS_NOERROR;
|
|
|
|
return(COMPLETE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cflags & ITSDONE )
|
|
|
|
{
|
|
|
|
printf("DC390: Is it done?\n");
|
|
|
|
cmd->flags &= ~ITSDONE;
|
|
|
|
}
|
|
|
|
if( !(cflags & INUSE) )
|
|
|
|
{
|
|
|
|
printf("DC390: In Use?\n");
|
|
|
|
cmd->flags |= INUSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd->error = 0;
|
|
|
|
cmd->resid = 0;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
pcmd = cmd;
|
|
|
|
|
|
|
|
pSRB = GetSRB( pACB );
|
|
|
|
|
|
|
|
if( !pSRB )
|
|
|
|
{
|
|
|
|
pcmd->error = XS_DRIVER_STUFFUP;
|
|
|
|
splx(flags);
|
|
|
|
return( TRY_AGAIN_LATER);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BuildSRB(pSRB); */
|
|
|
|
|
|
|
|
pSRB->pSRBDCB = pDCB;
|
|
|
|
pSRB->pcmd = pcmd;
|
|
|
|
ptr = (PUCHAR) pSRB->CmdBlock;
|
|
|
|
ptr1 = (PUCHAR) pcmd->cmd;
|
|
|
|
pSRB->ScsiCmdLen = pcmd->cmdlen;
|
|
|
|
for(i=0; i< pcmd->cmdlen; i++)
|
|
|
|
{
|
|
|
|
*ptr = *ptr1;
|
|
|
|
ptr++;
|
|
|
|
ptr1++;
|
|
|
|
}
|
|
|
|
if( pcmd->datalen )
|
|
|
|
{
|
|
|
|
psg = (PSEG) &pSRB->SGsegment[0];
|
|
|
|
pSRB->pSegmentList = psg;
|
|
|
|
sgc = 0;
|
|
|
|
|
|
|
|
/* Set up the scatter gather list */
|
|
|
|
datalen = pcmd->datalen;
|
|
|
|
CurrPgVaddr = (int) pcmd->data;
|
|
|
|
CurrPgPaddr = vtophys(CurrPgVaddr);
|
|
|
|
|
|
|
|
while ((datalen) && (sgc < MAX_SG_ENTRY))
|
|
|
|
{
|
|
|
|
sglen = 0;
|
|
|
|
psg->SGXPtr = CurrPgPaddr;
|
|
|
|
NextPgPaddr = CurrPgPaddr;
|
|
|
|
while ((datalen) && (CurrPgPaddr == NextPgPaddr))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This page is contiguous (physically) with the the last,
|
|
|
|
* just extend the length
|
|
|
|
*/
|
|
|
|
|
|
|
|
NextPgPaddr = (CurrPgPaddr & (~(PAGELEN - 1))) + PAGELEN;
|
|
|
|
pglen = NextPgPaddr - CurrPgPaddr;
|
|
|
|
|
|
|
|
if( datalen < pglen )
|
|
|
|
pglen = datalen;
|
|
|
|
sglen += pglen;
|
|
|
|
datalen -= pglen;
|
|
|
|
CurrPgVaddr = (CurrPgVaddr & (~(PAGELEN - 1))) + PAGELEN;
|
|
|
|
if( datalen )
|
|
|
|
CurrPgPaddr = vtophys(CurrPgVaddr);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
next page isn't contiguous, finish this segment
|
|
|
|
*/
|
|
|
|
psg->SGXLen = sglen;
|
|
|
|
psg++;
|
|
|
|
sgc++;
|
|
|
|
}
|
|
|
|
pSRB->SGcount = sgc;
|
|
|
|
|
|
|
|
if (datalen)
|
|
|
|
{
|
|
|
|
printf("DC390: Out Of Segment Buffer!\n");
|
|
|
|
pSRB->pNextSRB = pACB->pFreeSRB;
|
|
|
|
pACB->pFreeSRB = pSRB;
|
|
|
|
pcmd->error = XS_DRIVER_STUFFUP;
|
|
|
|
splx(flags);
|
|
|
|
return (HAD_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pSRB->SGcount = 0;
|
|
|
|
|
|
|
|
pSRB->SGIndex = 0;
|
|
|
|
pSRB->AdaptStatus = 0;
|
|
|
|
pSRB->TargetStatus = 0;
|
|
|
|
pSRB->MsgCnt = 0;
|
|
|
|
if( pDCB->DevType != SCSI_SEQACESS )
|
|
|
|
pSRB->RetryCnt = 1;
|
|
|
|
else
|
|
|
|
pSRB->RetryCnt = 0;
|
|
|
|
pSRB->SRBStatus = 0;
|
|
|
|
pSRB->SRBFlag = 0;
|
|
|
|
pSRB->SRBState = 0;
|
|
|
|
pSRB->TotalXferredLen = 0;
|
|
|
|
pSRB->SGPhysAddr = 0;
|
|
|
|
pSRB->SGToBeXferLen = 0;
|
|
|
|
pSRB->ScsiPhase = 0;
|
|
|
|
pSRB->EndMessage = 0;
|
|
|
|
splx(flags);
|
|
|
|
|
|
|
|
if( !(cflags & SCSI_NOMASK) )
|
|
|
|
{
|
|
|
|
flags = splbio();
|
|
|
|
SendSRB( pcmd, pACB, pSRB );
|
|
|
|
splx(flags);
|
|
|
|
return( SUCCESSFULLY_QUEUED);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SendSRB( pcmd, pACB, pSRB );
|
|
|
|
do
|
|
|
|
{
|
|
|
|
while(--pcmd->timeout)
|
|
|
|
{
|
|
|
|
DELAY(1000);
|
|
|
|
sstatus = inb( ioport+Scsi_Status );
|
|
|
|
if( sstatus & INTERRUPT )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( pcmd->timeout == 0 )
|
|
|
|
{
|
|
|
|
return(HAD_ERROR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DC390_Interrupt( pACB );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while( !(pcmd->flags & ITSDONE) );
|
|
|
|
if( pcmd->error == XS_TIMEOUT)
|
|
|
|
return(HAD_ERROR);
|
|
|
|
else
|
|
|
|
return(COMPLETE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
trmamd_min_phys( struct buf *bp )
|
|
|
|
{
|
|
|
|
if (bp->b_bcount > ((MAX_SG_ENTRY - 1) * PAGELEN))
|
|
|
|
bp->b_bcount = ((MAX_SG_ENTRY - 1) * PAGELEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef REL_2_1_0
|
|
|
|
u_int32
|
|
|
|
trmamd_info( int unit )
|
|
|
|
{
|
|
|
|
return (MAX_CMD_PER_LUN); /* outstanding requests at a time per device */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt )
|
|
|
|
{
|
|
|
|
int dataPtr;
|
|
|
|
PSCSICMD pcmd;
|
|
|
|
UCHAR i;
|
|
|
|
PSEG pseg;
|
|
|
|
|
|
|
|
pcmd = pSRB->pcmd;
|
|
|
|
dataPtr = (int) pcmd->data;
|
|
|
|
pseg = pSRB->SGsegment;
|
|
|
|
for(i=0; i < pSRB->SGIndex; i++)
|
|
|
|
{
|
|
|
|
dataPtr += (int) pseg->SGXLen;
|
|
|
|
pseg++;
|
|
|
|
}
|
|
|
|
dataPtr += (int) xferCnt;
|
|
|
|
return( (PUCHAR) dataPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : int DC390_abort (SCSICMD *cmd)
|
|
|
|
*
|
|
|
|
* Purpose : Abort an errant SCSI command
|
|
|
|
*
|
|
|
|
* Inputs : cmd - command to abort
|
|
|
|
*
|
|
|
|
* Returns : 0 on success, -1 on failure.
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
|
|
int
|
|
|
|
DC390_abort (SCSICMD *cmd)
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
PACB pACB;
|
|
|
|
PDCB pDCB, pdcb;
|
|
|
|
PSRB pSRB, psrb;
|
|
|
|
USHORT count, i;
|
|
|
|
PSCSICMD pcmd, pcmd1;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("DC390 : Abort Cmd.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
pACB = (PACB) cmd->host->hostdata;
|
|
|
|
pDCB = pACB->pLinkDCB;
|
|
|
|
pdcb = pDCB;
|
|
|
|
while( (pDCB->UnitSCSIID != cmd->sc_link->target) ||
|
|
|
|
(pDCB->UnitSCSILUN != cmd->sc_link->lun) )
|
|
|
|
{
|
|
|
|
pDCB = pDCB->pNextDCB;
|
|
|
|
if( pDCB == pdcb )
|
|
|
|
goto NOT_RUN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pSRB = pDCB->pWaitingSRB;
|
|
|
|
if( !pSRB )
|
|
|
|
goto ON_GOING;
|
|
|
|
if( pSRB->pcmd == cmd )
|
|
|
|
{
|
|
|
|
pDCB->pWaitingSRB = pSRB->pNextSRB;
|
|
|
|
goto IN_WAIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
psrb = pSRB;
|
|
|
|
while( psrb->pNextSRB->pcmd != cmd )
|
|
|
|
{
|
|
|
|
psrb = psrb->pNextSRB;
|
|
|
|
if( !psrb )
|
|
|
|
goto ON_GOING;
|
|
|
|
}
|
|
|
|
pSRB = psrb->pNextSRB;
|
|
|
|
psrb->pNextSRB = pSRB->pNextSRB;
|
|
|
|
if( pSRB == pDCB->pWaitLast )
|
|
|
|
pDCB->pWaitLast = psrb;
|
|
|
|
IN_WAIT:
|
|
|
|
pSRB->pNextSRB = pACB->pFreeSRB;
|
|
|
|
pACB->pFreeSRB = pSRB;
|
|
|
|
cmd->next = NULL;
|
|
|
|
status = SCSI_ABORT_SUCCESS;
|
|
|
|
goto ABO_X;
|
|
|
|
}
|
|
|
|
|
|
|
|
ON_GOING:
|
|
|
|
pSRB = pDCB->pGoingSRB;
|
|
|
|
for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
|
|
|
|
{
|
|
|
|
if( pSRB->pcmd != cmd )
|
|
|
|
pSRB = pSRB->pNextSRB;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
|
|
|
|
{
|
|
|
|
status = SCSI_ABORT_BUSY;
|
|
|
|
goto ABO_X;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = SCSI_ABORT_SNOOZE;
|
|
|
|
goto ABO_X;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NOT_RUN:
|
|
|
|
status = SCSI_ABORT_NOT_RUNNING;
|
|
|
|
|
|
|
|
ABO_X:
|
|
|
|
cmd->error = XS_NOERROR;
|
|
|
|
scsi_done(cmd);
|
|
|
|
splx(flags);
|
|
|
|
return( status );
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
ResetDevParam( PACB pACB )
|
|
|
|
{
|
|
|
|
PDCB pDCB, pdcb;
|
|
|
|
|
|
|
|
pDCB = pACB->pLinkDCB;
|
|
|
|
if( pDCB == NULL )
|
|
|
|
return;
|
|
|
|
pdcb = pDCB;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
pDCB->SyncMode &= ~SYNC_NEGO_DONE;
|
|
|
|
pDCB->SyncPeriod = 0;
|
|
|
|
pDCB->SyncOffset = 0;
|
|
|
|
pDCB->CtrlR3 = FAST_CLK;
|
|
|
|
pDCB->CtrlR4 &= NEGATE_REQACKDATA;
|
|
|
|
pDCB->CtrlR4 |= EATER_25NS;
|
|
|
|
pDCB = pDCB->pNextDCB;
|
|
|
|
}
|
|
|
|
while( pdcb != pDCB );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
RecoverSRB( PACB pACB )
|
|
|
|
{
|
|
|
|
PDCB pDCB, pdcb;
|
|
|
|
PSRB psrb, psrb2;
|
|
|
|
USHORT cnt, i;
|
|
|
|
|
|
|
|
pDCB = pACB->pLinkDCB;
|
|
|
|
if( pDCB == NULL )
|
|
|
|
return;
|
|
|
|
pdcb = pDCB;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
cnt = pdcb->GoingSRBCnt;
|
|
|
|
psrb = pdcb->pGoingSRB;
|
|
|
|
for (i=0; i<cnt; i++)
|
|
|
|
{
|
|
|
|
psrb2 = psrb;
|
|
|
|
psrb = psrb->pNextSRB;
|
|
|
|
/* RewaitSRB( pDCB, psrb ); */
|
|
|
|
if( pdcb->pWaitingSRB )
|
|
|
|
{
|
|
|
|
psrb2->pNextSRB = pdcb->pWaitingSRB;
|
|
|
|
pdcb->pWaitingSRB = psrb2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pdcb->pWaitingSRB = psrb2;
|
|
|
|
pdcb->pWaitLast = psrb2;
|
|
|
|
psrb2->pNextSRB = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pdcb->GoingSRBCnt = 0;
|
|
|
|
pdcb->pGoingSRB = NULL;
|
|
|
|
pdcb->TagMask = 0;
|
|
|
|
pdcb = pdcb->pNextDCB;
|
|
|
|
}
|
|
|
|
while( pdcb != pDCB );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : DC390_reset (PACB pACB)
|
|
|
|
*
|
|
|
|
* Purpose : perform a hard reset on the SCSI bus( and AMD chip).
|
|
|
|
*
|
|
|
|
* Inputs : cmd - command which caused the SCSI RESET
|
|
|
|
*
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
DC390_reset (PACB pACB)
|
|
|
|
{
|
|
|
|
USHORT ioport;
|
|
|
|
int flags;
|
|
|
|
UCHAR bval;
|
|
|
|
USHORT i;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("DC390: RESET,");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
ioport = pACB->IOPortBase;
|
|
|
|
bval = inb(ioport+CtrlReg1);
|
|
|
|
bval |= DIS_INT_ON_SCSI_RST;
|
|
|
|
OutB(bval,ioport+CtrlReg1); /* disable interrupt */
|
|
|
|
DC390_ResetSCSIBus( pACB );
|
|
|
|
for( i=0; i<500; i++ )
|
|
|
|
DELAY(1000);
|
|
|
|
bval = inb(ioport+CtrlReg1);
|
|
|
|
bval &= ~DIS_INT_ON_SCSI_RST;
|
|
|
|
OutB(bval,ioport+CtrlReg1); /* re-enable interrupt */
|
|
|
|
|
|
|
|
bval = DMA_IDLE_CMD;
|
|
|
|
OutB(bval,ioport+DMA_Cmd);
|
|
|
|
bval = CLEAR_FIFO_CMD;
|
|
|
|
OutB(bval,ioport+ScsiCmd);
|
|
|
|
|
|
|
|
ResetDevParam( pACB );
|
|
|
|
DoingSRB_Done( pACB );
|
|
|
|
pACB->pActiveDCB = NULL;
|
|
|
|
|
|
|
|
pACB->ACBFlag = 0;
|
|
|
|
DoWaitingSRB( pACB );
|
|
|
|
splx(flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-12-18 11:41:28 +00:00
|
|
|
#include <pci/scsiiom.c>
|
1996-12-15 23:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : static void DC390_initDCB
|
|
|
|
*
|
|
|
|
* Purpose : initialize the internal structures for a given DCB
|
|
|
|
*
|
|
|
|
* Inputs : cmd - pointer to this scsi cmd request block structure
|
|
|
|
*
|
|
|
|
***********************************************************************/
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
|
|
|
DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
PEEprom prom;
|
|
|
|
UCHAR bval;
|
|
|
|
USHORT index;
|
|
|
|
PSCLINK plink;
|
|
|
|
|
|
|
|
if( pACB->DeviceCnt == 0 )
|
|
|
|
{
|
|
|
|
pACB->pLinkDCB = pDCB;
|
|
|
|
pACB->pDCBRunRobin = pDCB;
|
|
|
|
pDCB->pNextDCB = pDCB;
|
|
|
|
pPrevDCB = pDCB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pPrevDCB->pNextDCB = pDCB;
|
|
|
|
|
|
|
|
plink = cmd->sc_link;
|
|
|
|
pDCB->pDCBACB = pACB;
|
|
|
|
pDCB->UnitSCSIID = plink->target;
|
|
|
|
pDCB->UnitSCSILUN = plink->lun;
|
|
|
|
pDCB->pWaitingSRB = NULL;
|
|
|
|
pDCB->pGoingSRB = NULL;
|
|
|
|
pDCB->GoingSRBCnt = 0;
|
|
|
|
pDCB->pActiveSRB = NULL;
|
|
|
|
pDCB->TagMask = 0;
|
|
|
|
pDCB->MaxCommand = 1;
|
|
|
|
pDCB->AdaptIndex = pACB->AdapterIndex;
|
|
|
|
index = pACB->AdapterIndex;
|
|
|
|
pDCB->DCBFlag = 0;
|
|
|
|
|
|
|
|
prom = (PEEprom) &eepromBuf[index][plink->target << 2];
|
|
|
|
pDCB->DevMode = prom->EE_MODE1;
|
|
|
|
pDCB->AdpMode = eepromBuf[index][EE_MODE2];
|
|
|
|
|
|
|
|
if( pDCB->DevMode & EN_DISCONNECT_ )
|
|
|
|
bval = 0xC0;
|
|
|
|
else
|
|
|
|
bval = 0x80;
|
|
|
|
bval |= plink->lun;
|
|
|
|
pDCB->IdentifyMsg = bval;
|
|
|
|
|
|
|
|
pDCB->SyncMode = 0;
|
|
|
|
if( pDCB->DevMode & SYNC_NEGO_ )
|
|
|
|
{
|
|
|
|
if( !(plink->lun) || CurrSyncOffset )
|
|
|
|
pDCB->SyncMode = SYNC_ENABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pDCB->SyncPeriod = 0;
|
|
|
|
pDCB->SyncOffset = 0;
|
|
|
|
pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
|
|
|
|
|
|
|
|
pDCB->CtrlR1 = pACB->AdaptSCSIID;
|
|
|
|
if( pDCB->DevMode & PARITY_CHK_ )
|
|
|
|
pDCB->CtrlR1 |= PARITY_ERR_REPO;
|
|
|
|
|
|
|
|
pDCB->CtrlR3 = FAST_CLK;
|
|
|
|
|
|
|
|
pDCB->CtrlR4 = EATER_25NS;
|
|
|
|
if( pDCB->AdpMode & ACTIVE_NEGATION)
|
|
|
|
pDCB->CtrlR4 |= NEGATE_REQACKDATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : static void DC390_initSRB
|
|
|
|
*
|
|
|
|
* Purpose : initialize the internal structures for a given SRB
|
|
|
|
*
|
|
|
|
* Inputs : psrb - pointer to this scsi request block structure
|
|
|
|
*
|
|
|
|
***********************************************************************/
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
|
|
|
DC390_initSRB( PSRB psrb )
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
psrb->PhysSRB = vtophys( psrb );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
|
|
|
DC390_linkSRB( PACB pACB )
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
USHORT count, i;
|
|
|
|
PSRB psrb;
|
|
|
|
|
|
|
|
count = pACB->SRBCount;
|
|
|
|
|
|
|
|
for( i=0; i< count; i++)
|
|
|
|
{
|
|
|
|
if( i != count - 1)
|
|
|
|
pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
|
|
|
|
else
|
|
|
|
pACB->SRB_array[i].pNextSRB = NULL;
|
|
|
|
psrb = (PSRB) &pACB->SRB_array[i];
|
|
|
|
DC390_initSRB( psrb );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : static void DC390_initACB
|
|
|
|
*
|
|
|
|
* Purpose : initialize the internal structures for a given SCSI host
|
|
|
|
*
|
|
|
|
* Inputs : psh - pointer to this host adapter's structure
|
|
|
|
*
|
|
|
|
***********************************************************************/
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
|
|
|
DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index )
|
1996-12-15 23:40:48 +00:00
|
|
|
{
|
|
|
|
USHORT i;
|
|
|
|
|
|
|
|
|
|
|
|
pACB->max_id = 7;
|
|
|
|
if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
|
|
|
|
pACB->max_id--;
|
|
|
|
if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
|
|
|
|
pACB->max_lun = 7;
|
|
|
|
else
|
|
|
|
pACB->max_lun = 0;
|
|
|
|
|
|
|
|
pACB->IOPortBase = (USHORT) io_port;
|
|
|
|
pACB->pLinkDCB = NULL;
|
|
|
|
pACB->pDCBRunRobin = NULL;
|
|
|
|
pACB->pActiveDCB = NULL;
|
|
|
|
pACB->pFreeSRB = pACB->SRB_array;
|
|
|
|
pACB->SRBCount = MAX_SRB_CNT;
|
|
|
|
pACB->AdapterIndex = index;
|
|
|
|
pACB->status = 0;
|
|
|
|
pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
|
|
|
|
pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
|
|
|
|
pACB->AdaptSCSILUN = 0;
|
|
|
|
pACB->DeviceCnt = 0;
|
|
|
|
pACB->IRQLevel = Irq;
|
|
|
|
pACB->TagMaxNum = (eepromBuf[index][EE_TAG_CMD_NUM]) << 2;
|
|
|
|
pACB->ACBFlag = 0;
|
|
|
|
pACB->scan_devices = 1;
|
|
|
|
pACB->Gmode2 = eepromBuf[index][EE_MODE2];
|
|
|
|
if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
|
|
|
|
pACB->LUNchk = 1;
|
|
|
|
pACB->pDCB_free = &pACB->DCB_array[0];
|
|
|
|
DC390_linkSRB( pACB );
|
|
|
|
pACB->pTmpSRB = &pACB->TmpSRB;
|
|
|
|
DC390_initSRB( pACB->pTmpSRB );
|
|
|
|
for(i=0; i<MAX_SCSI_ID; i++)
|
|
|
|
pACB->DCBmap[i] = 0;
|
|
|
|
|
|
|
|
pACB->ScsiLink.adapter_unit = index;
|
|
|
|
pACB->ScsiLink.adapter_targ = pACB->AdaptSCSIID;
|
|
|
|
pACB->ScsiLink.fordriver = 0;
|
|
|
|
pACB->ScsiLink.opennings = 2;
|
|
|
|
pACB->ScsiLink.adapter = &trmamd_switch;
|
|
|
|
pACB->ScsiLink.device = &trmamd_dev;
|
|
|
|
pACB->ScsiLink.flags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : static int DC390_initAdapter
|
|
|
|
*
|
|
|
|
* Purpose : initialize the SCSI chip ctrl registers
|
|
|
|
*
|
|
|
|
* Inputs : psh - pointer to this host adapter's structure
|
|
|
|
*
|
|
|
|
***********************************************************************/
|
1998-02-09 06:11:36 +00:00
|
|
|
static int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq,
|
|
|
|
USHORT index,
|
1996-12-15 23:40:48 +00:00
|
|
|
pcici_t config_id )
|
|
|
|
{
|
|
|
|
USHORT ioport;
|
|
|
|
UCHAR bval;
|
|
|
|
|
|
|
|
#ifdef CHECK_SHARE_INT
|
|
|
|
PACB pacb;
|
|
|
|
USHORT used_irq = 0;
|
|
|
|
|
|
|
|
pacb = pACB_start;
|
|
|
|
if( pacb != NULL )
|
|
|
|
{
|
|
|
|
for ( ; (pacb != (PACB) -1) ; )
|
|
|
|
{
|
|
|
|
if( pacb->IRQLevel == Irq )
|
|
|
|
{
|
|
|
|
used_irq = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pacb = pacb->pNextACB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !used_irq )
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
if( !pci_map_int (config_id, (PVOID)DC390_Interrupt, pACB, &bio_imask) )
|
|
|
|
{
|
|
|
|
if(bootverbose)
|
|
|
|
printf("DC390: register Interrupt handler error!\n");
|
|
|
|
return( -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CHECK_SHARE_INT
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ioport = (USHORT) io_port;
|
|
|
|
bval = 153; /* 250ms selection timeout */
|
|
|
|
OutB(bval,ioport+Scsi_TimeOut);
|
|
|
|
|
|
|
|
bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */
|
|
|
|
OutB(bval,ioport+Clk_Factor);
|
|
|
|
|
|
|
|
bval = NOP_CMD; /* NOP cmd - clear command register */
|
|
|
|
OutB(bval,ioport+ScsiCmd);
|
|
|
|
|
|
|
|
bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */
|
|
|
|
OutB(bval,ioport+CtrlReg2);
|
|
|
|
|
|
|
|
bval = FAST_CLK; /* fast clock */
|
|
|
|
OutB(bval,ioport+CtrlReg3);
|
|
|
|
|
|
|
|
bval = EATER_25NS;
|
|
|
|
if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
|
|
|
|
bval |= NEGATE_REQACKDATA;
|
|
|
|
OutB(bval,ioport+CtrlReg4);
|
|
|
|
|
|
|
|
bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */
|
|
|
|
OutB(bval,ioport+CtrlReg1);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Completely replace the PCI bus driver code to make it better reflect
reality. There will be a new call interface, but for now the file
pci_compat.c (which is to be deleted, after all drivers are converted)
provides an emulation of the old PCI bus driver functions. The only
change that might be visible to drivers is, that the type pcici_t
(which had been meant to be just a handle, whose exact definition
should not be relied on), has been converted into a pcicfgregs* .
The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t
and has been converted to just call the PCI drivers functions to access
configuration space register, instead of inventing its own ...
This code is by no means complete, but assumed to be fully operational,
and brings the official code base more in line with my development code.
A new generic device descriptor data type has to be agreed on. The PCI
code will then use that data type to provide new functionality:
1) userconfig support
2) "wired" PCI devices
3) conflicts checking against ISA/EISA
4) maps will depend on the command register enable bits
5) PCI to Anything bridges can be defined as devices,
and are probed like any "standard" PCI device.
The following features are currently missing, but will be added back,
soon:
1) unknown device probe message
2) suppression of "mirrored" devices caused by ancient, broken chip-sets
This code relies on generic shared interrupt support just commited to
kern_intr.c (plus the modifications of isa.c and isa_device.h).
1997-05-26 15:08:43 +00:00
|
|
|
#ifdef PCI_COMPAT
|
|
|
|
static pcicfgregs *cfg;
|
|
|
|
#define DC390_EnableCfg(a,b)
|
|
|
|
#define DC390_DisableCfg(a)
|
|
|
|
#define DC390_inByte(a,reg) pci_cfgread(cfg,reg,1)
|
|
|
|
#define DC390_inWord(a,reg) pci_cfgread(cfg,reg,2)
|
|
|
|
#define DC390_inDword(a,reg) pci_cfgread(cfg,reg,4)
|
|
|
|
#define DC390_OutB(a,reg,val) pci_cfgwrite(cfg,reg,val,1)
|
|
|
|
#else
|
|
|
|
|
1996-12-15 23:40:48 +00:00
|
|
|
void
|
|
|
|
DC390_EnableCfg( USHORT mechnum, UCHAR regval )
|
|
|
|
{
|
|
|
|
ULONG wlval;
|
|
|
|
|
|
|
|
if(mechnum == 2)
|
|
|
|
{
|
|
|
|
OutB(mech2bus, PCI_CFG2_FORWARD_REG);
|
|
|
|
OutB(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
regval &= 0xFC;
|
|
|
|
wlval = mech1addr;
|
|
|
|
wlval |= (((ULONG)regval) & 0xff);
|
|
|
|
OutL(wlval, PCI_CFG1_ADDRESS_REG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
DC390_DisableCfg( USHORT mechnum )
|
|
|
|
{
|
|
|
|
|
|
|
|
if(mechnum == 2)
|
|
|
|
OutB(0, PCI_CFG2_ENABLE_REG);
|
|
|
|
else
|
|
|
|
OutL(0, PCI_CFG1_ADDRESS_REG);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR
|
|
|
|
DC390_inByte( USHORT mechnum, UCHAR regval )
|
|
|
|
{
|
|
|
|
UCHAR bval;
|
|
|
|
USHORT wval;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
DC390_EnableCfg( mechnum, regval );
|
|
|
|
if(mechnum == 2)
|
|
|
|
{
|
|
|
|
wval = mech2Agent;
|
|
|
|
wval <<= 8;
|
|
|
|
wval |= ((USHORT) regval) & 0xff;
|
|
|
|
bval = inb(wval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
regval &= 3;
|
|
|
|
bval = inb(PCI_CFG1_DATA_REG | regval);
|
|
|
|
}
|
|
|
|
DC390_DisableCfg(mechnum);
|
|
|
|
splx(flags);
|
|
|
|
return(bval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
USHORT
|
|
|
|
DC390_inWord( USHORT mechnum, UCHAR regval )
|
|
|
|
{
|
|
|
|
USHORT wval;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
DC390_EnableCfg(mechnum,regval);
|
|
|
|
if(mechnum == 2)
|
|
|
|
{
|
|
|
|
wval = mech2Agent;
|
|
|
|
wval <<= 8;
|
|
|
|
wval |= regval;
|
|
|
|
wval = inw(wval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
regval &= 3;
|
|
|
|
wval = inw(PCI_CFG1_DATA_REG | regval);
|
|
|
|
}
|
|
|
|
DC390_DisableCfg(mechnum);
|
|
|
|
splx(flags);
|
|
|
|
return(wval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
|
|
DC390_inDword(USHORT mechnum, UCHAR regval )
|
|
|
|
{
|
|
|
|
ULONG wlval;
|
|
|
|
int flags;
|
|
|
|
USHORT wval;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
DC390_EnableCfg(mechnum,regval);
|
|
|
|
if(mechnum == 2)
|
|
|
|
{
|
|
|
|
wval = mech2Agent;
|
|
|
|
wval <<= 8;
|
|
|
|
wval |= regval;
|
|
|
|
wlval = inl(wval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wlval = inl(PCI_CFG1_DATA_REG);
|
|
|
|
}
|
|
|
|
DC390_DisableCfg(mechnum);
|
|
|
|
splx(flags);
|
|
|
|
return(wlval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
|
|
|
|
{
|
|
|
|
|
|
|
|
USHORT wval;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
DC390_EnableCfg(mechnum,regval);
|
|
|
|
if(mechnum == 2)
|
|
|
|
{
|
|
|
|
wval = mech2Agent;
|
|
|
|
wval <<= 8;
|
|
|
|
wval |= regval;
|
|
|
|
OutB(bval, wval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
regval &= 3;
|
|
|
|
OutB(bval, PCI_CFG1_DATA_REG | regval);
|
|
|
|
}
|
|
|
|
DC390_DisableCfg(mechnum);
|
|
|
|
splx(flags);
|
|
|
|
}
|
|
|
|
|
Completely replace the PCI bus driver code to make it better reflect
reality. There will be a new call interface, but for now the file
pci_compat.c (which is to be deleted, after all drivers are converted)
provides an emulation of the old PCI bus driver functions. The only
change that might be visible to drivers is, that the type pcici_t
(which had been meant to be just a handle, whose exact definition
should not be relied on), has been converted into a pcicfgregs* .
The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t
and has been converted to just call the PCI drivers functions to access
configuration space register, instead of inventing its own ...
This code is by no means complete, but assumed to be fully operational,
and brings the official code base more in line with my development code.
A new generic device descriptor data type has to be agreed on. The PCI
code will then use that data type to provide new functionality:
1) userconfig support
2) "wired" PCI devices
3) conflicts checking against ISA/EISA
4) maps will depend on the command register enable bits
5) PCI to Anything bridges can be defined as devices,
and are probed like any "standard" PCI device.
The following features are currently missing, but will be added back,
soon:
1) unknown device probe message
2) suppression of "mirrored" devices caused by ancient, broken chip-sets
This code relies on generic shared interrupt support just commited to
kern_intr.c (plus the modifications of isa.c and isa_device.h).
1997-05-26 15:08:43 +00:00
|
|
|
#endif /PCI_COMPAT */
|
1996-12-15 23:40:48 +00:00
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
|
|
|
|
{
|
|
|
|
|
|
|
|
UCHAR bval;
|
|
|
|
|
|
|
|
bval = 0;
|
|
|
|
if(mode == ENABLE_CE)
|
|
|
|
*regval = 0xc0;
|
|
|
|
else
|
|
|
|
*regval = 0x80;
|
|
|
|
DC390_OutB(mechnum,*regval,bval);
|
|
|
|
if(mode == DISABLE_CE)
|
|
|
|
DC390_OutB(mechnum,*regval,bval);
|
|
|
|
DELAY(160);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
|
|
|
|
{
|
|
|
|
UCHAR bval;
|
|
|
|
|
|
|
|
bval = 0;
|
|
|
|
if(Carry)
|
|
|
|
{
|
|
|
|
bval = 0x40;
|
|
|
|
*regval = 0x80;
|
|
|
|
DC390_OutB(mechnum,*regval,bval);
|
|
|
|
}
|
|
|
|
DELAY(160);
|
|
|
|
bval |= 0x80;
|
|
|
|
DC390_OutB(mechnum,*regval,bval);
|
|
|
|
DELAY(160);
|
|
|
|
bval = 0;
|
|
|
|
DC390_OutB(mechnum,*regval,bval);
|
|
|
|
DELAY(160);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static UCHAR
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_EEpromInDO( USHORT mechnum )
|
|
|
|
{
|
|
|
|
UCHAR bval,regval;
|
|
|
|
|
|
|
|
regval = 0x80;
|
|
|
|
bval = 0x80;
|
|
|
|
DC390_OutB(mechnum,regval,bval);
|
|
|
|
DELAY(160);
|
|
|
|
bval = 0x40;
|
|
|
|
DC390_OutB(mechnum,regval,bval);
|
|
|
|
DELAY(160);
|
|
|
|
regval = 0x0;
|
|
|
|
bval = DC390_inByte(mechnum,regval);
|
|
|
|
if(bval == 0x22)
|
|
|
|
return(1);
|
|
|
|
else
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static USHORT
|
1996-12-15 23:40:48 +00:00
|
|
|
EEpromGetData1( USHORT mechnum )
|
|
|
|
{
|
|
|
|
UCHAR i;
|
|
|
|
UCHAR carryFlag;
|
|
|
|
USHORT wval;
|
|
|
|
|
|
|
|
wval = 0;
|
|
|
|
for(i=0; i<16; i++)
|
|
|
|
{
|
|
|
|
wval <<= 1;
|
|
|
|
carryFlag = DC390_EEpromInDO(mechnum);
|
|
|
|
wval |= carryFlag;
|
|
|
|
}
|
|
|
|
return(wval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
|
|
|
|
{
|
|
|
|
UCHAR i,j;
|
|
|
|
USHORT carryFlag;
|
|
|
|
|
|
|
|
carryFlag = 1;
|
|
|
|
j = 0x80;
|
|
|
|
for(i=0; i<9; i++)
|
|
|
|
{
|
|
|
|
DC390_EEpromOutDI(mechnum,regval,carryFlag);
|
|
|
|
carryFlag = (EEpromCmd & j) ? 1 : 0;
|
|
|
|
j >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static void
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_ReadEEprom( USHORT mechnum, USHORT index )
|
|
|
|
{
|
|
|
|
UCHAR regval,cmd;
|
|
|
|
PUSHORT ptr;
|
|
|
|
USHORT i;
|
|
|
|
|
|
|
|
ptr = (PUSHORT) &eepromBuf[index][0];
|
|
|
|
cmd = EEPROM_READ;
|
|
|
|
for(i=0; i<0x40; i++)
|
|
|
|
{
|
|
|
|
DC390_EnDisableCE(ENABLE_CE, mechnum, ®val);
|
|
|
|
DC390_Prepare(mechnum, ®val, cmd);
|
|
|
|
*ptr = EEpromGetData1(mechnum);
|
|
|
|
ptr++;
|
|
|
|
cmd++;
|
|
|
|
DC390_EnDisableCE(DISABLE_CE,mechnum,®val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static USHORT
|
1996-12-18 01:20:32 +00:00
|
|
|
DC390_DefaultEEprom( USHORT mechnum, USHORT index )
|
|
|
|
{
|
|
|
|
PUCHAR ptr;
|
|
|
|
USHORT i;
|
|
|
|
|
|
|
|
ptr = (PUCHAR) &eepromBuf[index][0];
|
|
|
|
bzero (ptr, sizeof eepromBuf[index]);
|
|
|
|
for(i=0; i<0x40; i++)
|
|
|
|
{
|
|
|
|
*ptr = (TAG_QUEUING_|EN_DISCONNECT_|SYNC_NEGO_|PARITY_CHK_);
|
|
|
|
ptr += 4;
|
|
|
|
}
|
1997-08-11 08:49:08 +00:00
|
|
|
eepromBuf[index][EE_ADAPT_SCSI_ID] = 7;
|
|
|
|
eepromBuf[index][EE_MODE2] = (LUN_CHECK|ACTIVE_NEGATION);
|
|
|
|
eepromBuf[index][EE_TAG_CMD_NUM] = 4;
|
1996-12-18 01:20:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static USHORT
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
|
|
|
|
{
|
|
|
|
USHORT wval, rc, *ptr;
|
|
|
|
UCHAR i;
|
|
|
|
|
|
|
|
DC390_ReadEEprom( MechNum, index );
|
|
|
|
wval = 0;
|
|
|
|
ptr = (PUSHORT) &eepromBuf[index][0];
|
|
|
|
for(i=0; i<128 ;i+=2, ptr++)
|
|
|
|
wval += *ptr;
|
|
|
|
if( wval == 0x1234 )
|
|
|
|
rc = 0;
|
|
|
|
else
|
1996-12-18 01:20:32 +00:00
|
|
|
rc = DC390_DefaultEEprom( MechNum, index);
|
1996-12-15 23:40:48 +00:00
|
|
|
return( rc );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-09 06:11:36 +00:00
|
|
|
static USHORT
|
1996-12-15 23:40:48 +00:00
|
|
|
DC390_ToMech( USHORT Mechnum, pcici_t config_id )
|
|
|
|
{
|
|
|
|
|
Completely replace the PCI bus driver code to make it better reflect
reality. There will be a new call interface, but for now the file
pci_compat.c (which is to be deleted, after all drivers are converted)
provides an emulation of the old PCI bus driver functions. The only
change that might be visible to drivers is, that the type pcici_t
(which had been meant to be just a handle, whose exact definition
should not be relied on), has been converted into a pcicfgregs* .
The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t
and has been converted to just call the PCI drivers functions to access
configuration space register, instead of inventing its own ...
This code is by no means complete, but assumed to be fully operational,
and brings the official code base more in line with my development code.
A new generic device descriptor data type has to be agreed on. The PCI
code will then use that data type to provide new functionality:
1) userconfig support
2) "wired" PCI devices
3) conflicts checking against ISA/EISA
4) maps will depend on the command register enable bits
5) PCI to Anything bridges can be defined as devices,
and are probed like any "standard" PCI device.
The following features are currently missing, but will be added back,
soon:
1) unknown device probe message
2) suppression of "mirrored" devices caused by ancient, broken chip-sets
This code relies on generic shared interrupt support just commited to
kern_intr.c (plus the modifications of isa.c and isa_device.h).
1997-05-26 15:08:43 +00:00
|
|
|
#ifdef PCI_COMPAT
|
|
|
|
cfg = config_id;
|
|
|
|
#else
|
1996-12-15 23:40:48 +00:00
|
|
|
if(Mechnum == 2)
|
|
|
|
{
|
|
|
|
mech2bus = config_id.cfg2.forward; /* Bus num */
|
|
|
|
mech2Agent = config_id.cfg2.port >> 8; /* Dev num */
|
|
|
|
mech2CfgSPenR = config_id.cfg2.enable; /* Fun num */
|
|
|
|
}
|
|
|
|
else /* use mech #1 method */
|
|
|
|
{
|
|
|
|
mech1addr = config_id.cfg1;
|
|
|
|
}
|
Completely replace the PCI bus driver code to make it better reflect
reality. There will be a new call interface, but for now the file
pci_compat.c (which is to be deleted, after all drivers are converted)
provides an emulation of the old PCI bus driver functions. The only
change that might be visible to drivers is, that the type pcici_t
(which had been meant to be just a handle, whose exact definition
should not be relied on), has been converted into a pcicfgregs* .
The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t
and has been converted to just call the PCI drivers functions to access
configuration space register, instead of inventing its own ...
This code is by no means complete, but assumed to be fully operational,
and brings the official code base more in line with my development code.
A new generic device descriptor data type has to be agreed on. The PCI
code will then use that data type to provide new functionality:
1) userconfig support
2) "wired" PCI devices
3) conflicts checking against ISA/EISA
4) maps will depend on the command register enable bits
5) PCI to Anything bridges can be defined as devices,
and are probed like any "standard" PCI device.
The following features are currently missing, but will be added back,
soon:
1) unknown device probe message
2) suppression of "mirrored" devices caused by ancient, broken chip-sets
This code relies on generic shared interrupt support just commited to
kern_intr.c (plus the modifications of isa.c and isa_device.h).
1997-05-26 15:08:43 +00:00
|
|
|
#endif /* PCI_COMPAT */
|
1996-12-15 23:40:48 +00:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Function : static int DC390_init (struct Scsi_Host *host)
|
|
|
|
*
|
|
|
|
* Purpose : initialize the internal structures for a given SCSI host
|
|
|
|
*
|
|
|
|
* Inputs : host - pointer to this host adapter's structure/
|
|
|
|
*
|
|
|
|
* Preconditions : when this function is called, the chip_type
|
|
|
|
* field of the pACB structure MUST have been set.
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
static int
|
|
|
|
DC390_init( ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum,
|
|
|
|
pcici_t config_id)
|
|
|
|
{
|
|
|
|
PACB pACB;
|
|
|
|
|
|
|
|
if( !DC390_CheckEEpromCheckSum( MechNum, index) )
|
|
|
|
{
|
|
|
|
pACB = (PACB) malloc (sizeof (struct _ACB), M_DEVBUF, M_WAITOK);
|
|
|
|
if( !pACB )
|
|
|
|
{
|
|
|
|
printf("DC390%d: cannot allocate ACB !\n", index);
|
|
|
|
return( -1 );
|
|
|
|
}
|
|
|
|
bzero (pACB, sizeof (struct _ACB));
|
|
|
|
DC390_initACB( pACB, io_port, Irq, index );
|
|
|
|
if( !DC390_initAdapter( pACB, io_port, Irq, index, config_id) )
|
|
|
|
{
|
|
|
|
if( !pACB_start )
|
|
|
|
{
|
|
|
|
pACB_start = pACB;
|
|
|
|
pACB_current = pACB;
|
|
|
|
pACB->pNextACB = (PACB) -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pACB_current->pNextACB = pACB;
|
|
|
|
pACB_current = pACB;
|
|
|
|
pACB->pNextACB = (PACB) -1;
|
|
|
|
}
|
|
|
|
pACB0[index] = pACB;
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
printf("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
|
|
|
|
(UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
|
|
|
|
printf("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
|
|
|
|
sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return( 0 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free( pACB, M_DEVBUF);
|
|
|
|
return( -1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("DC390_init: EEPROM reading error!\n");
|
|
|
|
return( -1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
trmamd_attach (pcici_t config_id, int unit)
|
|
|
|
{
|
|
|
|
struct scsibus_data *scbus;
|
|
|
|
UCHAR irq;
|
|
|
|
USHORT MechNum;
|
|
|
|
ULONG io_port, wlval;
|
|
|
|
PACB pACB = 0;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
if( unit >= MAX_ADAPTER_NUM )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( pACB0[unit] )
|
|
|
|
return;
|
|
|
|
|
|
|
|
CurrentID = 0;
|
|
|
|
CurrentLUN = 0;
|
|
|
|
MechNum = pci_mechanism;
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
if(bootverbose)
|
|
|
|
printf("DC390: Mech=%2x,\n",(UCHAR) MechNum);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( !DC390_ToMech( MechNum, config_id ) )
|
|
|
|
{
|
|
|
|
wlval = DC390_inDword( MechNum, PCI_ID_REG);
|
|
|
|
if(wlval == PCI_DEVICE_ID_AMD53C974 )
|
|
|
|
{
|
|
|
|
io_port =DC390_inDword(MechNum,PCI_BASE_ADDR0) & 0xFFFE;
|
|
|
|
irq = DC390_inByte( MechNum, PCI_INTERRUPT_REG);
|
|
|
|
#ifdef DC390_DEBUG0
|
|
|
|
if(bootverbose)
|
|
|
|
printf("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
|
|
|
|
#endif
|
|
|
|
if( !DC390_init( io_port, irq, (USHORT) unit, MechNum, config_id) )
|
|
|
|
{
|
|
|
|
adapterCnt++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pACB = pACB0[unit];
|
|
|
|
|
|
|
|
/*
|
|
|
|
Now let the generic SCSI driver look for the SCSI devices on the bus
|
|
|
|
*/
|
|
|
|
|
|
|
|
flags = splbio();
|
|
|
|
|
|
|
|
scbus = scsi_alloc_bus();
|
|
|
|
if(!scbus)
|
|
|
|
{
|
|
|
|
splx(flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
scbus->adapter_link = &pACB->ScsiLink;
|
|
|
|
scbus->maxtarg = pACB->max_id;
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG
|
|
|
|
if(bootverbose)
|
|
|
|
printf("\nDC390: scanning for devices ...\n\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
scsi_attachdevs (scbus);
|
|
|
|
scbus = NULL; /* Upper-level SCSI code owns this now */
|
|
|
|
|
|
|
|
#ifdef DC390_DEBUG
|
|
|
|
if(bootverbose)
|
|
|
|
printf("\n\nDC390: Attach devices return\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
splx(flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char*
|
|
|
|
trmamd_probe (pcici_t tag, pcidi_t type)
|
|
|
|
{
|
|
|
|
if( type == PCI_DEVICE_ID_AMD53C974 )
|
1996-12-20 21:52:11 +00:00
|
|
|
return ("amd 53c974 scsi");
|
1996-12-15 23:40:48 +00:00
|
|
|
else
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|