a09e7bdbce
after the first found, if multiple LUNs are tried. Change probe message to just the SCSI chip id, similar to what the NCR driver prints. Change the driver name to "amd" in all places. Thanks to Nick Sayer <nsayer@quack.kfu.com> for doing some debugging, for sending a boot message log that shows the driver is functional, and for pointing out there still were places that needed the driver name to be corrected.
1698 lines
36 KiB
C
1698 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);
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
ptr[EE_ADAPT_SCSI_ID] = 7;
|
|
ptr[EE_MODE2] = (LUN_CHECK|ACTIVE_NEGATION);
|
|
ptr[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 )
|
|
{
|
|
|
|
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;
|
|
}
|
|
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);
|
|
}
|
|
|