01dae1c441
to spurious wites outside an alloccated array in the case of generic AMD SCSI cards. PR: kern/4217 Submitted by: Erik H. Moe <ehm@cris.com>
1713 lines
36 KiB
C
1713 lines
36 KiB
C
/***********************************************************************
|
|
* 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.
|
|
*
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************/
|
|
/* Imported into FreeBSD source repository, and updated to compile under */
|
|
/* FreeBSD-3.0-DEVELOPMENT, by Stefan Esser <se@FreeBSD.Org>, 1996-12-17 */
|
|
/**************************************************************************/
|
|
|
|
/* #define REL_2_1_0 */
|
|
#define REL_2_1_5
|
|
|
|
#define DC390_DEBUG
|
|
|
|
#include <sys/param.h>
|
|
|
|
/* XXX this doesn't actually compile unless KERNEL is defined. */
|
|
#ifdef KERNEL
|
|
#include <sys/systm.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/kernel.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/pmap.h>
|
|
#endif /* KERNEL */
|
|
|
|
#include <pci/pcivar.h>
|
|
#include <pci/pcireg.h>
|
|
|
|
#include <scsi/scsiconf.h>
|
|
|
|
#include <machine/clock.h>
|
|
|
|
#include <pci/tek390.h>
|
|
|
|
#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 );
|
|
|
|
static void DC390_timeout( void *arg1);
|
|
static void DC390_reset (PACB pACB);
|
|
static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt );
|
|
|
|
void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
|
|
void DC390_initSRB( PSRB psrb );
|
|
void DC390_linkSRB( PACB pACB );
|
|
void DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index );
|
|
int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index,
|
|
pcici_t config_id );
|
|
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 );
|
|
void DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval );
|
|
void DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry );
|
|
UCHAR DC390_EEpromInDO( USHORT mechnum );
|
|
USHORT EEpromGetData1( USHORT mechnum );
|
|
void DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd );
|
|
void DC390_ReadEEprom( USHORT mechnum, USHORT index );
|
|
USHORT DC390_DefaultEEprom( USHORT mechnum, USHORT index );
|
|
USHORT DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index );
|
|
USHORT DC390_ToMech( USHORT Mechnum, pcici_t config_id );
|
|
|
|
|
|
#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;
|
|
|
|
struct pci_device trmamd_device = {
|
|
"amd",
|
|
trmamd_probe,
|
|
trmamd_attach,
|
|
&trmamd_count,
|
|
NULL
|
|
};
|
|
|
|
DATA_SET (pcidevice_set, trmamd_device);
|
|
|
|
|
|
|
|
struct scsi_adapter trmamd_switch =
|
|
{
|
|
trmamd_scsi_cmd,
|
|
trmamd_min_phys,
|
|
0,
|
|
0,
|
|
#ifdef REL_2_1_0
|
|
trmamd_info,
|
|
#endif
|
|
#ifdef REL_2_1_5
|
|
0,
|
|
#endif
|
|
"amd",
|
|
};
|
|
|
|
struct scsi_device trmamd_dev =
|
|
{
|
|
NULL, /* Use default error handler */
|
|
NULL, /* have a queue, served by this */
|
|
NULL, /* have no async handler */
|
|
NULL, /* Use default 'done' routine */
|
|
"amd",
|
|
};
|
|
|
|
|
|
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;
|
|
static USHORT mech2Agent;
|
|
static ULONG mech1addr;
|
|
static UCHAR mech2bus, mech2CfgSPenR, CurrentID, CurrentLUN;
|
|
|
|
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,
|
|
};
|
|
|
|
UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
|
|
|
|
|
|
UCHAR clock_period1[] = {4, 5, 6, 7 ,8, 10, 13, 20};
|
|
|
|
UCHAR baddevname1[2][28] ={
|
|
"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 )
|
|
{
|
|
if( (plink->target > CurrentID) ||
|
|
(plink->target == CurrentID) && (plink->lun >= CurrentLUN) )
|
|
{
|
|
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 );
|
|
timeout(DC390_timeout, (caddr_t)pSRB, (pcmd->timeout * hz)/1000);
|
|
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;
|
|
}
|
|
|
|
|
|
void
|
|
DC390_timeout( void *arg1)
|
|
{
|
|
PSRB pSRB;
|
|
|
|
pSRB = (PSRB) arg1;
|
|
}
|
|
|
|
|
|
#include <pci/scsiiom.c>
|
|
|
|
|
|
/***********************************************************************
|
|
* Function : static void DC390_initDCB
|
|
*
|
|
* Purpose : initialize the internal structures for a given DCB
|
|
*
|
|
* Inputs : cmd - pointer to this scsi cmd request block structure
|
|
*
|
|
***********************************************************************/
|
|
void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
|
|
{
|
|
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
|
|
*
|
|
***********************************************************************/
|
|
void DC390_initSRB( PSRB psrb )
|
|
{
|
|
psrb->PhysSRB = vtophys( psrb );
|
|
}
|
|
|
|
|
|
void DC390_linkSRB( PACB pACB )
|
|
{
|
|
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
|
|
*
|
|
***********************************************************************/
|
|
void DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index )
|
|
{
|
|
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
|
|
*
|
|
***********************************************************************/
|
|
int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index,
|
|
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);
|
|
}
|
|
|
|
|
|
#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
|
|
|
|
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);
|
|
}
|
|
|
|
#endif /PCI_COMPAT */
|
|
|
|
void
|
|
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);
|
|
}
|
|
|
|
|
|
void
|
|
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);
|
|
}
|
|
|
|
|
|
UCHAR
|
|
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);
|
|
}
|
|
|
|
|
|
USHORT
|
|
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);
|
|
}
|
|
|
|
|
|
void
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
USHORT
|
|
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;
|
|
}
|
|
eepromBuf[index][EE_ADAPT_SCSI_ID] = 7;
|
|
eepromBuf[index][EE_MODE2] = (LUN_CHECK|ACTIVE_NEGATION);
|
|
eepromBuf[index][EE_TAG_CMD_NUM] = 4;
|
|
return 0;
|
|
}
|
|
|
|
|
|
USHORT
|
|
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
|
|
rc = DC390_DefaultEEprom( MechNum, index);
|
|
return( rc );
|
|
}
|
|
|
|
|
|
USHORT
|
|
DC390_ToMech( USHORT Mechnum, pcici_t config_id )
|
|
{
|
|
|
|
#ifdef PCI_COMPAT
|
|
cfg = config_id;
|
|
#else
|
|
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;
|
|
}
|
|
#endif /* PCI_COMPAT */
|
|
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 )
|
|
return ("amd 53c974 scsi");
|
|
else
|
|
return (NULL);
|
|
}
|
|
|