|
|
GNU Mach 1.2
/***********************************************************************
* FILE NAME : TMSCSIW.C *
* BY : C.L. Huang ([email protected]) *
* Description: Device Driver for Tekram DC-390W/U/F (T) PCI SCSI *
* Bus Master Host Adapter *
* (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
***********************************************************************/
/* Minor enhancements and bugfixes by *
* Kurt Garloff <[email protected]> *
***********************************************************************/
/* HISTORY: *
* *
* REV# DATE NAME DESCRIPTION *
* 1.00 04/03/96 CLH First release *
* 1.01 04/11/96 CLH Maximum support up to 4 Adapters, *
* support KV 1_3_85 *
* 1.02 04/26/96 CLH fixed bug about EEpromBuf when >1 HA *
* 1.03 06/12/96 CLH fixed bug of Media Change for Removable *
* Device, scan all LUN. Support Pre2.0.10 *
* 1.04 06/18/96 CLH fixed bug of Command timeout .... *
* 1.05 10/04/96 CLH Updating for support KV 2.0.0, 2.0.20 *
* 1.06 10/30/96 KG Fixed bug in DC390W_abort(), module *
* support, added tmscsiw_proc_info() *
* 1.07 11/09/96 KG Fixed bug in tmscsiw_proc_info() *
* 1.08 11/18/96 CLH/KG ditto, null ptr in DC390W_Disconnect() *
* 1.09 11/30/96 KG Fixed bug in CheckEEpromCheckSum(), *
* add register the allocated IO space *
* 1.10 12/05/96 CLH Modify in tmscsiw_proc_info() and add *
* in DC390W_initAdapter() for 53C875 *
* Rev. F with double clock. *
* 1.11 02/04/97 CLH Fixed bug of Formatting a partition that*
* across 1GB boundary, with bad sector *
* checking. *
* 1.12 02/17/97 CLH Fixed bug in CheckEEpromCheckSum() *
***********************************************************************/
#define DC390W_DEBUG
/* #define CHK_UNDER_RUN */
#define SCSI_MALLOC
#ifdef MODULE
#include <linux/module.h>
#endif
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/config.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
#include "../block/blk.h"
#else
#include <linux/blk.h>
#endif
#include "scsi.h"
#include "hosts.h"
#include "tmscsiw.h"
#include "constants.h"
#include "sd.h"
#include "scripts.h"
#include <linux/stat.h>
#include "dc390w.h"
#ifndef VERSION_ELF_1_2_13
struct proc_dir_entry proc_scsi_tmscsiw ={
PROC_SCSI_DC390WUF, 7 ,"tmscsiw",
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
#endif
static void DC390W_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
static void PrepareSG( PACB pACB, PDCB pDCB, PSRB pSRB );
static void DoingSRB_Done( PACB pACB );
static void ExceptionHandler(ULONG wlval, PACB pACB, PDCB pDCB);
static void ParityError( PACB pACB, PDCB pDCB );
static void PhaseMismatch( PACB pACB );
static void DC390W_ScsiRstDetect( PACB pACB );
static void DC390W_ResetSCSIBus( PACB pACB );
static void DC390W_ResetSCSIBus2( PACB pACB );
static void AdjustTemp( PACB pACB, PDCB pDCB, PSRB pSRB );
static void SetXferRate( PACB pACB, PDCB pDCB );
static void DataIOcommon( PACB pACB, ULONG Swlval, ULONG Cwlval );
static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
static void DC390W_CmdCompleted( PACB pACB );
static void DC390W_Reselected( PACB pACB );
static void DC390W_Reselected1( PACB pACB );
static void DC390W_ReselectedT( PACB pACB );
static void DC390W_Disconnected( PACB pACB );
static void DC390W_MessageExtnd( PACB pACB );
static void DC390W_Signal( PACB pACB );
static void DC390W_UnknownMsg( PACB pACB );
static void DC390W_MessageOut( PACB pACB );
static void DC390W_FatalError( PACB pACB );
static void DC390W_MessageSync( PACB pACB );
static void DC390W_MessageWide( PACB pACB );
static void DC390W_RestorePtr( PACB pACB );
static void DC390W_MsgReject( PACB pACB );
static void DC390W_Debug( PACB pACB );
static void DC390W_download_script (struct Scsi_Host *host);
int DC390W_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index);
void DC390W_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
void MyDelay( void );
void EnDisableCE( UCHAR Flag, USHORT scsiIOPort );
void EEpromOutDI( USHORT Carry, USHORT scsiIOPort );
void EEpromPrepare( UCHAR EEpromCmd, USHORT scsiIOPort );
void ReadEEprom( PUCHAR EEpromBuf, USHORT scsiIOPort );
UCHAR EEpromInDo(USHORT scsiIOPort);
USHORT EEpromGetData(USHORT scsiIOPort);
USHORT CheckEEpromCheckSum( PUCHAR EEpromBuf, USHORT scsiIOPort);
#ifdef MODULE
static int DC390W_release(struct Scsi_Host *host);
static int DC390W_shutdown (struct Scsi_Host *host);
#endif
static ULONG jmp_table16;
static ULONG jmp_din16;
static ULONG jmp_dout16;
static PSHT pSHT_start = NULL;
static PSH pSH_start = NULL;
static PSH pSH_current = NULL;
static PACB pACB_start= NULL;
static PACB pACB_current = NULL;
static PDCB pPrevDCB = NULL;
static USHORT adapterCnt = 0;
static USHORT InitialTime = 0;
static USHORT CurrDCBscntl3 = 0;
static UCHAR pad_buffer[128];
static PVOID IntVector[]={
DC390W_CmdCompleted,
DC390W_Reselected,
DC390W_Reselected1,
DC390W_ReselectedT,
DC390W_Disconnected,
DC390W_MessageExtnd,
DC390W_Signal,
DC390W_UnknownMsg,
DC390W_MessageOut,
DC390W_FatalError,
DC390W_MessageSync,
DC390W_MessageWide,
DC390W_RestorePtr,
DC390W_MsgReject,
DC390W_Debug,
DC390W_FatalError
};
UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
UCHAR clock_period[12] = {25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21};
UCHAR baddevname[2][28] ={
"SEAGATE ST3390N 9546",
"SEAGATE ST3390N ??? 0399"};
#define BADDEVCNT 2
/***********************************************************************
*
*
*
**********************************************************************/
static void
QLinkcmd( PSCSICMD cmd, PDCB pDCB )
{
ULONG flags;
PSCSICMD pcmd;
save_flags(flags);
cli();
if( !pDCB->QIORBCnt )
{
pDCB->pQIORBhead = cmd;
pDCB->pQIORBtail = cmd;
pDCB->QIORBCnt++;
cmd->next = NULL;
}
else
{
pcmd = pDCB->pQIORBtail;
pcmd->next = cmd;
pDCB->pQIORBtail = cmd;
pDCB->QIORBCnt++;
cmd->next = NULL;
}
restore_flags(flags);
}
static PSCSICMD
Getcmd( PDCB pDCB )
{
ULONG flags;
PSCSICMD pcmd;
save_flags(flags);
cli();
pcmd = pDCB->pQIORBhead;
pDCB->pQIORBhead = pcmd->next;
pcmd->next = NULL;
pDCB->QIORBCnt--;
restore_flags(flags);
return( pcmd );
}
static PSRB
GetSRB( PACB pACB )
{
ULONG flags;
PSRB pSRB;
save_flags(flags);
cli();
pSRB = pACB->pFreeSRB;
if( pSRB )
{
pACB->pFreeSRB = pSRB->pNextSRB;
pSRB->pNextSRB = NULL;
}
restore_flags(flags);
return( pSRB );
}
static void
RewaitSRB( PDCB pDCB, PSRB pSRB )
{
PSRB psrb1;
ULONG flags;
UCHAR bval;
save_flags(flags);
cli();
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 */
restore_flags(flags);
}
static void
DoWaitingSRB( PACB pACB )
{
ULONG flags;
PDCB ptr, ptr1;
PSRB pSRB;
save_flags(flags);
cli();
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
{
DC390W_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;
}
}
}
restore_flags(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 )
{
ULONG flags;
PDCB pDCB;
save_flags(flags);
cli();
pDCB = pSRB->pSRBDCB;
PrepareSG( pACB, pDCB, pSRB );
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;
}
DC390W_StartSCSI(pACB, pDCB, pSRB);
pDCB->GoingSRBCnt++;
if( pDCB->pGoingSRB )
{
pDCB->pGoingLast->pNextSRB = pSRB;
pDCB->pGoingLast = pSRB;
}
else
{
pDCB->pGoingSRB = pSRB;
pDCB->pGoingLast = pSRB;
}
SND_EXIT:
restore_flags(flags);
return;
}
/***********************************************************************
* Function : static int DC390W_queue_command (Scsi_Cmnd *cmd,
* void (*done)(Scsi_Cmnd *))
*
* Purpose : enqueues a SCSI command
*
* Inputs : cmd - SCSI command, done - function called on completion, with
* a pointer to the command descriptor.
*
* Returns : 0
*
***********************************************************************/
int
DC390W_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
{
USHORT ioport, i;
Scsi_Cmnd *pcmd;
struct Scsi_Host *psh;
PACB pACB;
PDCB pDCB;
PSRB pSRB;
ULONG flags;
PUCHAR ptr,ptr1;
psh = cmd->host;
pACB = (PACB ) psh->hostdata;
ioport = pACB->IOPortBase;
#ifdef DC390W_DEBUG0
printk("Cmd=%x,",cmd->cmnd[0]);
#endif
if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
{
pACB->scan_devices = 0;
pPrevDCB->pNextDCB = pACB->pLinkDCB;
}
else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
{
pACB->scan_devices = 0;
pPrevDCB->pNextDCB = pACB->pLinkDCB;
}
if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
{
/* printk("DC390W: Ignore target %d lun %d\n",
cmd->target, cmd->lun); */
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
return( 0 );
}
if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
{
if( pACB->DeviceCnt < MAX_DEVICES )
{
pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
pDCB = pACB->pDCB_free;
#ifdef DC390W_DEBUG0
printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
#endif
DC390W_initDCB( pACB, pDCB, cmd );
}
else /* ???? */
{
/* printk("DC390W: Ignore target %d lun %d\n",
cmd->target, cmd->lun); */
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
return(0);
}
}
else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
{
/* printk("DC390W: Ignore target %d lun %d\n",
cmd->target, cmd->lun); */
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
return(0);
}
else
{
pDCB = pACB->pLinkDCB;
while( (pDCB->UnitSCSIID != cmd->target) ||
(pDCB->UnitSCSILUN != cmd->lun) )
{
pDCB = pDCB->pNextDCB;
}
#ifdef DC390W_DEBUG0
printk("pDCB=%8x,ID=%2x,Scan=%1x", (UINT) pDCB, cmd->target,
pACB->scan_devices);
#endif
}
cmd->scsi_done = done;
cmd->result = 0;
save_flags(flags);
cli();
if( pDCB->QIORBCnt )
{
QLinkcmd( cmd, pDCB );
pcmd = Getcmd( pDCB );
}
else
pcmd = cmd;
pSRB = GetSRB( pACB );
if( !pSRB )
{
QLinkcmd( pcmd, pDCB );
restore_flags(flags);
return(0);
}
/* BuildSRB(pSRB); */
pSRB->pSRBDCB = pDCB;
pSRB->pcmd = pcmd;
ptr = (PUCHAR) pSRB->CmdBlock;
ptr1 = (PUCHAR) pcmd->cmnd;
(UCHAR) pSRB->__command[0] = pcmd->cmd_len;
for(i=0; i< pcmd->cmd_len; i++)
{
*ptr = *ptr1;
ptr++;
ptr1++;
}
if( pcmd->use_sg )
{
pSRB->SGcount = (UCHAR) pcmd->use_sg;
pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
}
else if( pcmd->request_buffer )
{
pSRB->SGcount = 1;
pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
pSRB->Segmentx.length = pcmd->request_bufflen;
}
else
pSRB->SGcount = 0;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0;
pSRB->MsgCnt = 0;
if( pDCB->DevType != TYPE_TAPE )
pSRB->RetryCnt = 1;
else
pSRB->RetryCnt = 0;
pSRB->SRBStatus = 0;
pSRB->SRBFlag = 0;
pSRB->ScratchABuf = 0;
pSRB->SRBState = 0;
pSRB->RemainSegPtr = 0;
pSRB->XferredLen = 0;
SendSRB( pcmd, pACB, pSRB );
restore_flags(flags);
return(0);
}
static void
DoNextCmd( PACB pACB, PDCB pDCB )
{
Scsi_Cmnd *pcmd;
PSRB pSRB;
ULONG flags;
PUCHAR ptr,ptr1;
USHORT i;
if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
return;
save_flags(flags);
cli();
pcmd = Getcmd( pDCB );
pSRB = GetSRB( pACB );
if( !pSRB )
{
QLinkcmd( pcmd, pDCB );
restore_flags(flags);
return;
}
pSRB->pSRBDCB = pDCB;
pSRB->pcmd = pcmd;
ptr = (PUCHAR) pSRB->CmdBlock;
ptr1 = (PUCHAR) pcmd->cmnd;
(UCHAR) pSRB->__command[0] = pcmd->cmd_len;
for(i=0; i< pcmd->cmd_len; i++)
{
*ptr = *ptr1;
ptr++;
ptr1++;
}
if( pcmd->use_sg )
{
pSRB->SGcount = (UCHAR) pcmd->use_sg;
pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
}
else if( pcmd->request_buffer )
{
pSRB->SGcount = 1;
pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
pSRB->Segmentx.length = pcmd->request_bufflen;
}
else
pSRB->SGcount = 0;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0;
pSRB->MsgCnt = 0;
if( pDCB->DevType != TYPE_TAPE )
pSRB->RetryCnt = 1;
else
pSRB->RetryCnt = 0;
pSRB->SRBStatus = 0;
pSRB->SRBFlag = 0;
pSRB->ScratchABuf = 0;
pSRB->SRBState = 0;
SendSRB( pcmd, pACB, pSRB );
restore_flags(flags);
return;
}
/***********************************************************************
* Function:
* DC390W_bios_param
*
* Description:
* Return the disk geometry for the given SCSI device.
***********************************************************************/
#ifdef VERSION_ELF_1_2_13
int DC390W_bios_param(Disk *disk, int devno, int geom[])
#else
int DC390W_bios_param(Disk *disk, kdev_t devno, int geom[])
#endif
{
int heads, sectors, cylinders;
PACB pACB;
pACB = (PACB) disk->device->host->hostdata;
heads = 64;
sectors = 32;
cylinders = disk->capacity / (heads * sectors);
if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
{
heads = 255;
sectors = 63;
cylinders = disk->capacity / (heads * sectors);
}
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
return (0);
}
/***********************************************************************
* Function : int DC390W_abort (Scsi_Cmnd *cmd)
*
* Purpose : Abort an errant SCSI command
*
* Inputs : cmd - command to abort
*
* Returns : 0 on success, -1 on failure.
***********************************************************************/
int
DC390W_abort (Scsi_Cmnd *cmd)
{
ULONG flags;
PACB pACB;
PDCB pDCB, pdcb;
PSRB pSRB, psrb;
USHORT count, i;
PSCSICMD pcmd, pcmd1;
int status;
#ifdef DC390W_DEBUG0
printk("DC390W : Abort Cmd.");
#endif
save_flags(flags);
cli();
pACB = (PACB) cmd->host->hostdata;
pDCB = pACB->pLinkDCB;
pdcb = pDCB;
while( (pDCB->UnitSCSIID != cmd->target) ||
(pDCB->UnitSCSILUN != cmd->lun) )
{
pDCB = pDCB->pNextDCB;
if( pDCB == pdcb )
goto NOT_RUN;
}
if( pDCB->QIORBCnt )
{
pcmd = pDCB->pQIORBhead;
if( pcmd == cmd )
{
pDCB->pQIORBhead = pcmd->next;
pcmd->next = NULL;
pDCB->QIORBCnt--;
status = SCSI_ABORT_SUCCESS;
goto ABO_X;
}
for( count = pDCB->QIORBCnt, i=0; i<count-1; i++)
{
if( pcmd->next == cmd )
{
pcmd1 = pcmd->next;
pcmd->next = pcmd1->next;
pcmd1->next = NULL;
pDCB->QIORBCnt--;
status = SCSI_ABORT_SUCCESS;
goto ABO_X;
}
else
{
pcmd = pcmd->next;
}
}
}
pSRB = pDCB->pWaitingSRB;
if( !pSRB )
goto ON_GOING;
if( pSRB->pcmd == cmd )
{
pDCB->pWaitingSRB = pSRB->pNextSRB;
goto IN_WAIT;
}
else
{
psrb = pSRB;
if( !(psrb->pNextSRB) )
goto ON_GOING;
while( psrb->pNextSRB->pcmd != cmd )
{
psrb = psrb->pNextSRB;
if( !(psrb->pNextSRB) )
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->result = DID_ABORT << 16;
cmd->scsi_done(cmd);
restore_flags(flags);
return( status );
}
static void
ResetDevParam( PACB pACB )
{
PDCB pDCB, pdcb;
pDCB = pACB->pLinkDCB;
if( pDCB == NULL )
return;
pdcb = pDCB;
do
{
if( pACB->AdaptType == DC390W )
pdcb->DCBscntl3 = SYNC_CLK_F2+ASYNC_CLK_F2;
else
pdcb->DCBscntl3 = SYNC_CLK_F4+ASYNC_CLK_F4;
pdcb->DCBsxfer = 0;
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++)
{
PrepareSG( pACB, pdcb, psrb );
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 : int DC390W_reset (Scsi_Cmnd *cmd, ...)
*
* Purpose : perform a hard reset on the SCSI bus( and NCR chip).
*
* Inputs : cmd - command which caused the SCSI RESET
*
* Returns : 0 on success.
***********************************************************************/
#ifdef VERSION_2_0_0
int DC390W_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
#else
int DC390W_reset (Scsi_Cmnd *cmd)
#endif
{
USHORT ioport;
unsigned long flags;
PACB pACB;
ULONG wlval;
UCHAR bval;
USHORT wval;
USHORT i;
#ifdef DC390W_DEBUG0
printk("DC390W : Reset Cmd0,");
#endif
pACB = (PACB ) cmd->host->hostdata;
ioport = pACB->IOPortBase;
save_flags(flags);
cli();
bval = inb(ioport+DCNTL);
bval |= IRQ_DISABLE;
outb(bval,ioport+DCNTL); /* disable interrupt */
DC390W_ResetSCSIBus( pACB );
for( i=0; i<500; i++ )
udelay(1000);
for(;;)
{
bval = inb(ioport+ISTAT);
if( bval & SCSI_INT_PENDING )
{
wval = inw( ioport+SIST0 );
if( wval & (SCSI_RESET+SCSI_GERROR) )
break;
}
if(bval & DMA_INT_PENDING)
{
bval = inb(ioport+DSTAT);
if(bval & ABORT_)
{
wval = inw( ioport+SIST0 );
break;
}
}
}
bval = inb(ioport+DCNTL);
bval &= ~IRQ_DISABLE;
outb(bval,ioport+DCNTL); /* re-enable interrupt */
ioport = pACB->IOPortBase;
bval = inb(ioport+STEST3);
bval |= CLR_SCSI_FIFO;
outb(bval,ioport+STEST3);
bval = CLR_DMA_FIFO;
outb(bval,ioport+CTEST3);
ResetDevParam( pACB );
DoingSRB_Done( pACB );
pACB->pActiveDCB = NULL;
wlval = pACB->jmp_reselect;
outl(wlval,(ioport+DSP));
pACB->ACBFlag = 0;
DoWaitingSRB( pACB );
restore_flags(flags);
return( SCSI_RESET_SUCCESS );
}
#include "scsiio.c"
/***********************************************************************
* Function : static void DC390W_initDCB
*
* Purpose : initialize the internal structures for a given DCB
*
* Inputs : cmd - pointer to this scsi cmd request block structure
*
***********************************************************************/
void DC390W_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
{
PEEprom prom;
UCHAR bval;
USHORT index;
if( pACB->DeviceCnt == 0 )
{
pACB->pLinkDCB = pDCB;
pACB->pDCBRunRobin = pDCB;
pDCB->pNextDCB = pDCB;
pPrevDCB = pDCB;
}
else
pPrevDCB->pNextDCB = pDCB;
pDCB->pDCBACB = pACB;
pDCB->QIORBCnt = 0;
pDCB->DCBselect = 0;
pDCB->DCBsxfer = 0;
pDCB->DCBsdid = cmd->target;
pDCB->UnitSCSIID = cmd->target;
pDCB->UnitSCSILUN = cmd->lun;
pDCB->pWaitingSRB = NULL;
pDCB->GoingSRBCnt = 0;
pDCB->TagMask = 0;
pDCB->MaxCommand = 1;
pDCB->AdaptIndex = pACB->AdapterIndex;
index = pACB->AdapterIndex;
prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
pDCB->DevMode = prom->EE_MODE1;
pDCB->NegoPeriod = clock_period[prom->EE_SPEED];
if( pACB->AdaptType == DC390W )
pDCB->DCBscntl3 = SYNC_CLK_F2+ASYNC_CLK_F2;
else
pDCB->DCBscntl3 = SYNC_CLK_F4+ASYNC_CLK_F4;
if( pDCB->DevMode & PARITY_CHK_ )
pDCB->DCBscntl0 = EN_PARITY_CHK+SATN_IF_PARITY_ERR+FULL_ARBITRATION;
else
pDCB->DCBscntl0 = FULL_ARBITRATION;
pDCB->AdpMode = eepromBuf[index][EE_MODE2];
if( pDCB->DevMode & EN_DISCONNECT_ )
bval = 0xC0;
else
bval = 0x80;
bval |= cmd->lun;
pDCB->IdentifyMsg = bval;
if( pDCB->DevMode & SYNC_NEGO_ )
{
pDCB->SyncMode = SYNC_ENABLE;
pDCB->SyncOffset = SYNC_NEGO_OFFSET;
}
if( pDCB->DevMode & WIDE_NEGO_ )
{
if( cmd->lun )
{
if( !(CurrDCBscntl3 & EN_WIDE_SCSI) )
pDCB->DevMode &= ~WIDE_NEGO_;
}
else
CurrDCBscntl3 = 0;
}
pDCB->DCBFlag = 0;
}
/***********************************************************************
* Function : static void DC390W_initSRB
*
* Purpose : initialize the internal structures for a given SRB
*
* Inputs : psrb - pointer to this scsi request block structure
*
***********************************************************************/
void DC390W_initSRB( PSRB psrb )
{
#ifndef VERSION_ELF_1_2_13
psrb->PhysSRB = virt_to_phys( psrb );
psrb->__command[1] = virt_to_phys( psrb->CmdBlock );
psrb->__msgout0[0] = 1;
psrb->__msgout0[1] = virt_to_phys( psrb->MsgOutBuf );
psrb->SegmentPad[0] = 16;
psrb->SegmentPad[1] = virt_to_phys( pad_buffer );
#else
psrb->PhysSRB = (ULONG) psrb;
psrb->__command[1] = (ULONG) psrb->CmdBlock;
psrb->__msgout0[0] = 1;
psrb->__msgout0[1] = (ULONG) psrb->MsgOutBuf;
psrb->SegmentPad[0] = 16;
psrb->SegmentPad[1] = (ULONG) pad_buffer;
#endif
}
void DC390W_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];
DC390W_initSRB( psrb );
}
}
/***********************************************************************
* Function : static void DC390W_initACB
*
* Purpose : initialize the internal structures for a given SCSI host
*
* Inputs : psh - pointer to this host adapter's structure
*
***********************************************************************/
void DC390W_initACB( PSH psh, USHORT chipType, ULONG io_port, UCHAR Irq, USHORT index )
{
PACB pACB;
USHORT i;
UCHAR adaptType, bval;
psh->can_queue = MAX_CMD_QUEUE;
psh->cmd_per_lun = MAX_CMD_PER_LUN;
psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
psh->io_port = io_port;
psh->n_io_port = 0x80;
psh->irq = Irq;
if( chipType == PCI_DEVICE_ID_NCR53C825A )
adaptType = DC390W;
else
{
outb( 2, io_port+GPREG );
bval = inb( io_port+GPREG );
if( bval & 8 )
adaptType = DC390U;
else
adaptType = DC390F;
}
pACB = (PACB) psh->hostdata;
#ifndef VERSION_ELF_1_2_13
if( adaptType == DC390U )
{
psh->max_id = 8;
pACB->max_id = 7;
}
else
{
psh->max_id = 16;
pACB->max_id = 15;
}
#ifdef CONFIG_SCSI_MULTI_LUN
if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
psh->max_lun = 8;
else
#endif
psh->max_lun = 1;
#else
pACB->max_id = 7;
#endif
if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
pACB->max_id--;
#ifdef CONFIG_SCSI_MULTI_LUN
if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
pACB->max_lun = 7;
else
#endif
pACB->max_lun = 0;
pACB->pScsiHost = psh;
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->AdaptSCSILUN = 0;
pACB->DeviceCnt = 0;
pACB->IRQLevel = Irq;
pACB->AdaptType = adaptType;
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];
DC390W_linkSRB( pACB );
for(i=0; i<MAX_SCSI_ID; i++)
pACB->DCBmap[i] = 0;
}
/***********************************************************************
* Function : static int DC390W_initAdapter
*
* Purpose : initialize the SCSI chip ctrl registers
*
* Inputs : psh - pointer to this host adapter's structure
*
***********************************************************************/
int DC390W_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
{
USHORT ioport, wval;
UCHAR bval;
PACB 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 )
{
#ifdef VERSION_ELF_1_2_13
if( request_irq(Irq, DC390W_Interrupt, SA_INTERRUPT, "tmscsiw"))
#else
if( request_irq(Irq, DC390W_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsiw", NULL))
#endif
{
printk("DC390W : register IRQ error!\n");
return( -1 );
}
}
request_region(io_port,psh->n_io_port,"tmscsiw");
ioport = (USHORT) io_port;
outb(IRQ_DISABLE, ioport+DCNTL);
outb(ABORT_OP, ioport+ISTAT);
udelay(100000);
outb(0, ioport+ISTAT);
bval = inb(ioport+DSTAT);
bval = inb(ioport+ISTAT);
wval = inw(ioport+SIST0);
pACB = (PACB) psh->hostdata;
bval = pACB->AdaptSCSIID;
bval |= ENABLE_RESEL;
outb(bval,ioport+SCID);
if(pACB->AdaptType == DC390W)
bval = SYNC_CLK_F2+ASYNC_CLK_F2;
else
{ /* @1.09 */
bval = inb(ioport+CTEST3);
if( (bval & CHIP_REV_MASK) < 0x30 ) /* 53C875 Rev. F or later ? */
goto REVF;
bval = inb(ioport+STEST1);
if( (bval & 0x0C) == 0x0C ) /* double clock already enable ? */
goto REVF;
outb(8,ioport+STEST1); /* enable clock doubler */
udelay(20);
outb(HALT_SCSI_CLK,ioport+STEST3); /* halt clock */
outb(0x0C,ioport+STEST1); /* select double SCSI clock */
outb(0,ioport+STEST3); /* re-enable clock */
REVF:
bval = SYNC_CLK_F4+ASYNC_CLK_F4;
}
outb(bval,ioport+SCNTL3);
bval = SYNC_PERIOD_F4+ASYNCHRONOUS; /* set to async */
outb(bval,ioport+SXFER);
bval = WRT_EN_INVALIDATE; /* Enable write and invalidate */
outb(bval,ioport+CTEST3);
bval = EN_DMA_FIFO_536+BURST_LEN_MSB; /* select 536 bytes DMA FIFO, burst len bit2=1 */
outb(bval,ioport+CTEST5);
bval = BURST_LEN8+EN_READ_LINE+EN_READ_MULTIPLE+BURST_OPCODE_FETCH+AUTO_START; /* set DMA parameter */
outb(bval,ioport+DMODE);
bval = EN_ABORTED+EN_SCRIPT_INT+EN_ILLEGAL_INST; /* enable DMA interrupt */
outb(bval,ioport+DIEN);
bval = EN_CACHE_LINE_SIZE+EN_PRE_FETCH+TOTEM_POLE_IRQ+COMPATIBLE_700;
outb(bval,ioport+DCNTL);
bval = EN_PHASE_MISMATCH+EN_SCSI_GERROR+EN_UNEXPECT_DISC+EN_SCSI_RESET+EN_PARITY_ERROR;
outb(bval,ioport+SIEN0);
bval = EN_SEL_TIMEOUT+EN_GENERAL_TIMEOUT;
outb(bval,ioport+SIEN1);
bval = SEL_TO_204ms; /* 250ms selection timeout */
outb(bval,ioport+STIME0);
wval = 1 << (eepromBuf[index][EE_ADAPT_SCSI_ID]); /* @1.11 */
outw(wval,ioport+RESPID0);
bval = DIS_SINGLE_INIT;
if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
bval |= ACTIVE_NEGATION_;
outb(bval,ioport+STEST3);
return(0);
}
/***********************************************************************
* Function : static int DC390W_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
DC390W_init (PSHT psht, USHORT chipType, ULONG io_port, UCHAR Irq, USHORT index)
{
PSH psh;
PACB pACB;
if( ! CheckEEpromCheckSum( &eepromBuf[index][0], (USHORT) io_port) )
{
psh = scsi_register( psht, sizeof(DC390W_ACB) );
if( !psh )
return( -1 );
if( !pSH_start )
{
pSH_start = psh;
pSH_current = psh;
}
else
{
pSH_current->next = psh;
pSH_current = psh;
}
#ifdef DC390W_DEBUG0
printk("DC390W : pSH = %8x,", (UINT) psh);
#endif
DC390W_initACB( psh, chipType, io_port, Irq, index );
if( !DC390W_initAdapter( psh, io_port, Irq, index ) )
{
pACB = (PACB) psh->hostdata;
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;
}
#ifdef DC390W_DEBUG0
printk("DC390W : pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
(UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
printk("DC390W : ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
sizeof(DC390W_ACB), sizeof(DC390W_DCB), sizeof(DC390W_SRB) );
#endif
}
else
{
pSH_start = NULL;
scsi_unregister( psh );
return( -1 );
}
DC390W_download_script( psh );
return( 0 );
}
else
{
printk("DC390W_init: EEPROM reading error!\n");
return( -1 );
}
}
void MyDelay( void )
{
UCHAR i,j;
j = inb(0x61) & 0x10;
for(;;)
{
i = inb(0x61) & 0x10;
if( j ^ i)
break;
}
}
void EnDisableCE( UCHAR Flag, USHORT scsiIOPort )
{
UCHAR bval;
USHORT port;
port = (scsiIOPort & 0xff00) + GPREG;
if(Flag == ENABLE_CE)
bval = 0x10;
else
bval = 0x00;
outb(bval,port);
udelay(8); /* Delay();*/
}
void EEpromOutDI( USHORT Carry, USHORT scsiIOPort )
{
UCHAR bval;
USHORT port;
port = (scsiIOPort & 0xff00) + GPREG;
bval = 0x10;
if(Carry)
bval |= 0x02; /* SK=0, DI */
outb(bval,port);
udelay(8); /* Delay();*/
bval |= 0x04; /* SK=1, DI */
outb(bval,port);
udelay(8); /* Delay();*/
bval &= 0xfb; /* SK=0, DI */
outb(bval,port);
udelay(8); /* Delay();*/
}
void EEpromPrepare( UCHAR EEpromCmd, USHORT scsiIOPort )
{
UCHAR i,j;
USHORT carryFlag;
carryFlag = 1;
j = 0x80;
for(i=0;i<9;i++)
{
EEpromOutDI(carryFlag,scsiIOPort);
carryFlag = (EEpromCmd & j) ? 1 : 0;
j >>= 1;
}
}
UCHAR EEpromInDo(USHORT scsiIOPort)
{
UCHAR bval;
USHORT port;
port = (scsiIOPort & 0xff00) + GPREG;
bval = 0x14; /* SK=1 */
outb(bval,port);
udelay(8); /* Delay();*/
bval = 0x10; /* SK=0 */
outb(bval,port);
udelay(8); /* Delay();*/
bval = inb(port);
if(bval & 0x01)
return( 1 );
else
return( 0 );
}
USHORT EEpromGetData(USHORT scsiIOPort)
{
UCHAR i;
UCHAR carryFlag;
USHORT wval;
wval = 0;
for(i=0;i<16;i++)
{
wval <<= 1;
carryFlag = EEpromInDo(scsiIOPort);
wval |= carryFlag;
}
return( wval );
}
void ReadEEprom( PUCHAR EEpromBuf, USHORT scsiIOPort )
{
UCHAR cmd;
cmd = EEPROM_READ;
loop_rd:
EnDisableCE(ENABLE_CE, scsiIOPort);
EEpromPrepare(cmd, scsiIOPort);
*((PUSHORT)EEpromBuf) = EEpromGetData(scsiIOPort);
EEpromBuf++;
EEpromBuf++;
cmd++;
EnDisableCE(DISABLE_CE, scsiIOPort);
if(cmd & 0x3f)
goto loop_rd;
}
USHORT CheckEEpromCheckSum( PUCHAR EEpromBuf, USHORT scsiIOPort)
{
USHORT wval,port, *ptr;
UCHAR i,bval;
port = (scsiIOPort & 0xff00) + GPCNTL;
bval = 0x09; /* configure IO Pin */
outb(bval,port);
ReadEEprom(EEpromBuf,scsiIOPort); /* read eeprom data */
wval = 0;
ptr = (PUSHORT) EEpromBuf;
for(i=0; i<128 ;i+=2, ptr++)
wval += *ptr;
return( (wval == 0x1234) ? 0 : -1);
}
static void
DC390W_download_script (struct Scsi_Host *host)
{
ULONG wlval, wlval1, length, alignm;
USHORT j, k, m;
USHORT ioport;
UCHAR bval;
PACB pACB;
PSRB pSRB;
void *pSrc, *pSrc1;
ULONG *pStart;
ULONG Ent_reselected;
ULONG Ent_reselecttag;
ULONG Ent_select0;
ULONG Ent_select1;
ULONG Ent_check_phase;
ULONG Ent_status1_phase;
ULONG Ent_command_phase;
ULONG Ent_jump_table0;
ULONG Ent_din_phaseB;
ULONG Ent_dout_phaseB;
ULONG Ent_din_pad_0;
ULONG Ent_dout_pad_0;
ULONG Ent_jump_tablew;
ULONG Ent_din_pad_1;
ULONG Ent_dout_pad_1;
ULONG Ent_mout_phase;
ULONG Ent_status_phase;
ULONG Ent_min_phase;
ULONG Ent_jump_msgok;
ULONG Ent_msg__1;
ULONG Ent_msg___3;
ULONG Ent_msg___2;
ULONG Ent_set_atn;
ULONG Ent_msg__a;
ULONG Ent_msg__23;
ULONG Ent_msg__3;
ULONG Ent_msg__4;
ULONG Ent_clr_atn;
ULONG Ent_din_phaseW;
ULONG Ent_dout_phaseW;
ULONG Ent_din_pad_addrB;
ULONG Ent_dout_pad_addrB;
ULONG Ent_din_pad_addrW;
ULONG Ent_dout_pad_addrW;
pACB = (PACB) host->hostdata;
ioport = pACB->IOPortBase;
bval = SCRATCHAB_AS_BASE; /* set scratchB contains 4K RAM base address */
outb(bval,ioport+CTEST2);
wlval = inl((ioport+SCRATCHB)); /* get starting address of 4K RAM */
/* wlval += 0x800; */ /* point to Upper 2K RAM */
DesPhysAddr[0] = wlval; /* destination address */
#ifdef DC390W_DEBUG0
printk("DesAddr=%8x,",(UINT) wlval);
#endif
bval = 0; /* set Scratch_A and Scratch_B to normal mode */
outb(bval,ioport+CTEST2);
/*-------------------------------------------------------------------
* patch the label in jump instruction: using offset relative
* to start_script
*------------------------------------------------------------------*/
Ent_reselected = (ULONG) reselected - (ULONG) start_script;
Ent_reselecttag = (ULONG) reselecttag - (ULONG) start_script;
Ent_select0 = (ULONG) select0 - (ULONG) start_script;
Ent_select1 = (ULONG) select1 - (ULONG) start_script;
Ent_check_phase = (ULONG) check_phase - (ULONG) start_script;
Ent_status1_phase = (ULONG) status1_phase - (ULONG) start_script;
Ent_command_phase = (ULONG) command_phase - (ULONG) start_script;
Ent_din_phaseB = (ULONG) din_phaseB - (ULONG) start_script;
Ent_dout_phaseB = (ULONG) dout_phaseB - (ULONG) start_script;
Ent_din_phaseW = (ULONG) din_phaseW - (ULONG) start_script;
Ent_dout_phaseW = (ULONG) dout_phaseW - (ULONG) start_script;
Ent_jump_table0 = (ULONG) jump_table0 - (ULONG) start_script;
Ent_din_pad_0 = (ULONG) din_pad_0 - (ULONG) start_script;
Ent_din_pad_addrB = (ULONG) din_pad_addrB - (ULONG) start_script;
Ent_dout_pad_0 = (ULONG) dout_pad_0 - (ULONG) start_script;
Ent_dout_pad_addrB = (ULONG) dout_pad_addrB - (ULONG) start_script;
Ent_jump_tablew = (ULONG) jump_tablew - (ULONG) start_script;
Ent_din_pad_1 = (ULONG) din_pad_1 - (ULONG) start_script;
Ent_din_pad_addrW = (ULONG) din_pad_addrW - (ULONG) start_script;
Ent_dout_pad_1 = (ULONG) dout_pad_1 - (ULONG) start_script;
Ent_dout_pad_addrW = (ULONG) dout_pad_addrW - (ULONG) start_script;
Ent_mout_phase = (ULONG) mout_phase - (ULONG) start_script;
Ent_status_phase = (ULONG) status_phase - (ULONG) start_script;
Ent_min_phase = (ULONG) min_phase - (ULONG) start_script;
Ent_jump_msgok = (ULONG) jump_msgok - (ULONG) start_script;
Ent_msg__1 = (ULONG) msg__1 - (ULONG) start_script;
Ent_msg___3 = (ULONG) msg___3 - (ULONG) start_script;
Ent_msg___2 = (ULONG) msg___2 - (ULONG) start_script;
Ent_set_atn = (ULONG) set_atn - (ULONG) start_script;
Ent_msg__a = (ULONG) msg__a - (ULONG) start_script;
Ent_msg__23 = (ULONG) msg__23 - (ULONG) start_script;
Ent_msg__3 = (ULONG) msg__3 - (ULONG) start_script;
Ent_msg__4 = (ULONG) msg__4 - (ULONG) start_script;
Ent_clr_atn = (ULONG) clr_atn - (ULONG) start_script;
jmp_select0[0] = Ent_select0 + wlval;
jmp_reselected[0] = Ent_reselected + wlval;
jmp_check_phase[0] = Ent_check_phase + wlval;
jmp_check_phase1[0] = Ent_check_phase + wlval;
jmp_check_phase2[0] = Ent_check_phase + wlval;
jmp_check_phase3[0] = Ent_check_phase + wlval;
jmp_check_phase4[0] = Ent_check_phase + wlval;
jmp_check_phase5[0] = Ent_check_phase + wlval;
jmp_check_phase6[0] = Ent_check_phase + wlval;
jmp_status1_phase[0] = Ent_status1_phase + wlval;
jmp_status1_phase1[0] = Ent_status1_phase + wlval;
jmp_status1_phase2[0] = Ent_status1_phase + wlval;
jmp_status1_phase3[0] = Ent_status1_phase + wlval;
jmp_command_phase[0] = Ent_command_phase + wlval;
for(j=0,k=1,m=0; j< (MAX_SG_LIST_BUF+1); j++)
{
jmp_dio_phaseB[k] = Ent_din_phaseB + m + wlval;
jmp_dio_phaseW[k] = Ent_din_phaseW + m + wlval;
k += 2;
jmp_dio_phaseB[k] = Ent_dout_phaseB + m + wlval;
jmp_dio_phaseW[k] = Ent_dout_phaseW + m + wlval;
k += 2;
m += 8;
}
jmp_din_pad_0[0] = Ent_din_pad_0 + wlval;
jmp_dout_pad_0[0] = Ent_dout_pad_0 + wlval;
jmp_din_pad_addrB[0] = Ent_din_pad_addrB + wlval;
jmp_dout_pad_addrB[0] = Ent_dout_pad_addrB + wlval;
jmp_din_pad_addrW[0] = Ent_din_pad_addrW + wlval;
jmp_dout_pad_addrW[0] = Ent_dout_pad_addrW + wlval;
jmp_din_pad_1[0] = Ent_din_pad_1 + wlval;
jmp_dout_pad_1[0] = Ent_dout_pad_1 + wlval;
jmp_status_phase[0] = Ent_status_phase + wlval;
jmp_min_phase[0] = Ent_min_phase + wlval;
jmp_mout_phase[0] = Ent_mout_phase + wlval;
jmp_jump_msgok[0] = Ent_jump_msgok + wlval;
jmp_msg__1[0] = Ent_msg__1 + wlval;
jmp_msg___3[0] = Ent_msg___3 + wlval;
jmp_msg___2[0] = Ent_msg___2 + wlval;
jmp_msg__a[0] = Ent_msg__a + wlval;
jmp_msg__a1[0] = Ent_msg__a + wlval;
jmp_msg__a2[0] = Ent_msg__a + wlval;
jmp_msg__23[0] = Ent_msg__23 + wlval;
jmp_msg__3[0] = Ent_msg__3 + wlval;
jmp_msg__4[0] = Ent_msg__4 + wlval;
/*--------------------------------------------------------------------
// patch the element in ACB struct: using Physical address
//-------------------------------------------------------------------*/
#ifndef VERSION_ELF_1_2_13
wlval1 = virt_to_phys( pACB->msgin123 );
#else
wlval1 = (ULONG) pACB->msgin123;
#endif
ACB_msgin123_1[0] = wlval1;
ACB_msgin123_2[0] = wlval1;
ACB_msgin123_3[0] = wlval1;
ACB_msgin123_4[0] = wlval1;
ACB_msgin123_5[0] = wlval1;
ACB_msgin123_6[0] = wlval1;
ACB_msgin123_7[0] = wlval1;
#ifndef VERSION_ELF_1_2_13
ACB_status[0] = virt_to_phys( &pACB->status );
#else
ACB_status[0] = (ULONG) &pACB->status;
#endif
/*--------------------------------------------------------------------
// patch the element in SRB struct: using offset in struct
//-------------------------------------------------------------------*/
pSRB = (PSRB) pACB->SRB_array;
select1[0] = (select1[0] & 0xffff0000) + ((ULONG) &pSRB->__select - (ULONG) &pSRB->CmdBlock);
SRB_msgout0[0] = (ULONG) &pSRB->__msgout0 - (ULONG) &pSRB->CmdBlock;
SRB_msgout01[0] = (ULONG) &pSRB->__msgout0 - (ULONG) &pSRB->CmdBlock;
SRB_command[0] = (ULONG) &pSRB->__command - (ULONG) &pSRB->CmdBlock;
SRB_SegmentPad[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock;
SRB_SegmentPad1[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock;
SRB_SegmentPad2[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock;
SRB_SegmentPad3[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock;
wlval = (ULONG) &pSRB->Segment0 - (ULONG) &pSRB->CmdBlock;
for(j=0,k=1; j<(MAX_SG_LIST_BUF+1); j++)
{
din_phaseB[k] = wlval;
dout_phaseB[k] = wlval;
din_phaseW[k] = wlval;
dout_phaseW[k] = wlval;
k += 2;
wlval += 8;
}
bval = inb(ioport+DCNTL);
bval |= IRQ_DISABLE;
outb(bval,ioport+DCNTL); /* disable interrupt */
/* pSrc = scsi_init_malloc( 2048, GFP_ATOMIC); */
pSrc = scsi_init_malloc( 4096, GFP_ATOMIC); /* 1.11 */
#ifdef DC390W_DEBUG0
printk("SrcAlloc=%8x,",(UINT) pSrc);
#endif
alignm = 4 - (((ULONG) pSrc) & 3);
pSrc1 = (void *)(((ULONG) pSrc) + alignm);
length = (ULONG) end_script - (ULONG) start_script;
memcpy( pSrc1, (void *) start_script, length);
pStart = (ULONG *) ((ULONG) start_mov - (ULONG) start_script);
pStart =(ULONG *) (((ULONG) pStart) + ((ULONG) pSrc1));
#ifdef DC390W_DEBUG0
printk("SrcAddr=%8x,\n",(UINT) pSrc1);
#endif
#ifndef VERSION_ELF_1_2_13
(ULONG *)pStart[1] = virt_to_phys( pSrc1 );
#else
(ULONG *)pStart[1] = (ULONG) pSrc1;
#endif
/* wlval = virt_to_phys( start_script ); */ /* physical address of start_script */
/* SrcPhysAddr[0] = wlval; */ /* sources address */
/* start to download SCRIPT instruction to the RAM of NCR53c825A,875 */
/* wlval = virt_to_phys( start_mov ); */
#ifndef VERSION_ELF_1_2_13
wlval = virt_to_phys( pStart );
#else
wlval = (ULONG) pStart;
#endif
outl(wlval,ioport+DSP);
bval = inb(ioport+ISTAT);
while(!(bval & DMA_INT_PENDING)) /* check load start_script is finished? */
bval = inb(ioport+ISTAT);
bval = inb(ioport+DSTAT); /* clear interrupt */
bval = inb(ioport+DCNTL);
bval &= ~IRQ_DISABLE;
outb(bval,ioport+DCNTL); /* re-enable interrupt */
scsi_init_free((char *) pSrc, 4096);
wlval = DesPhysAddr[0]; /* starting addr of RAM */
wlval -= (ULONG) start_script;
pACB->jmp_reselect = wlval + (ULONG) start_script;
pACB->jmp_select = wlval + (ULONG) select1;
pACB->jmp_table8 = wlval + (ULONG) jump_table0;
pACB->jmp_set_atn = wlval + (ULONG) set_atn;
pACB->jmp_clear_ack = wlval + (ULONG) msg__a;
pACB->jmp_next = wlval + (ULONG) check_phase;
pACB->jmp_din8 = wlval + (ULONG) din_phaseB+8;
pACB->jmp_dout8 = wlval + (ULONG) dout_phaseB+8;
pACB->jmp_clear_atn = wlval + (ULONG) clr_atn;
pACB->jmp_reselecttag = wlval + (ULONG) reselecttag;
wlval = pACB->jmp_reselect;
outl(wlval,(ioport+DSP));
return;
}
/***********************************************************************
* Function : int DC390W_detect(Scsi_Host_Template *psht)
*
* Purpose : detects and initializes NCR53c825A,875 SCSI chips
* that were autoprobed, overridden on the LILO command line,
* or specified at compile time.
*
* Inputs : psht - template for this SCSI adapter
*
* Returns : number of host adapters detected
*
***********************************************************************/
int
DC390W_detect(Scsi_Host_Template *psht)
{
UCHAR pci_bus, pci_device_fn, irq;
#ifndef VERSION_ELF_1_2_13
UINT io_port, ram_base;
#else
ULONG io_port, ram_base;
#endif
USHORT i;
int error = 0;
USHORT adaptCnt = 0; /* Number of boards detected */
USHORT pci_index = 0; /* Device index to PCI BIOS calls */
USHORT pci_index2 = 0; /* Device index to PCI BIOS calls */
USHORT chipType = 0;
#ifndef VERSION_ELF_1_2_13
psht->proc_dir = &proc_scsi_tmscsiw;
#endif
InitialTime = 1;
pSHT_start = psht;
jmp_table16 = (ULONG) jump_tablew - (ULONG) jump_table0;
jmp_din16 = (ULONG) din_phaseW - (ULONG) din_phaseB;
jmp_dout16 = (ULONG) dout_phaseW - (ULONG) dout_phaseB;
pACB_start = NULL;
if ( pcibios_present() )
{
for (i = 0; i < MAX_ADAPTER_NUM; ++i)
{
if( !pcibios_find_device( PCI_VENDOR_ID_NCR,
PCI_DEVICE_ID_NCR53C825A,
pci_index, &pci_bus, &pci_device_fn) )
{
chipType = PCI_DEVICE_ID_NCR53C825A;
pci_index++;
}
else if( !pcibios_find_device( PCI_VENDOR_ID_NCR,
PCI_DEVICE_ID_NCR53C875,
pci_index2, &pci_bus, &pci_device_fn) )
{
chipType = PCI_DEVICE_ID_NCR53C875;
pci_index2++;
}
if( chipType )
{
error = pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &io_port);
error |= pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_2, &ram_base);
error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_INTERRUPT_LINE, &irq);
if( error )
{
printk("DC390W_detect: reading configuration registers error!\n");
InitialTime = 0;
return( 0 );
}
(USHORT) io_port = (USHORT) io_port & 0xFFFE;
#ifdef DC390W_DEBUG0
printk("DC390W : IO_PORT=%4x,RAM_BASE=%8x,IRQ=%x,CHIPID=%x,\n",
(UINT) io_port, (UINT) ram_base, irq, (UCHAR)chipType);
#endif
if( !DC390W_init(psht, chipType, io_port, irq, i) )
adaptCnt++;
chipType = 0;
}
else
break;
}
}
InitialTime = 0;
adapterCnt = adaptCnt;
return( adaptCnt );
}
#ifndef VERSION_ELF_1_2_13
/********************************************************************
* Function: tmscsiw_set_info()
*
* Purpose: Set adapter info (!)
*
* Not yet implemented
*
*******************************************************************/
int tmscsiw_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
{
return(-ENOSYS); /* Currently this is a no-op */
}
/********************************************************************
* Function: tmscsiw_proc_info(char* buffer, char **start,
* off_t offset, int length, int hostno, int inout)
*
* Purpose: return SCSI Adapter/Device Info
*
* Input: buffer: Pointer to a buffer where to write info
* start :
* offset:
* hostno: Host adapter index
* inout : Read (=0) or set(!=0) info
*
* Output: buffer: contains info
* length; length of info in buffer
*
* return value: length
*
********************************************************************/
/* KG: proc_info taken from driver aha152x.c */
#undef SPRINTF
#define SPRINTF(args...) pos += sprintf(pos, ## args)
#define YESNO(YN)\
if (YN) SPRINTF(" Yes ");\
else SPRINTF(" No ")
int tmscsiw_proc_info(char *buffer, char **start,
off_t offset, int length, int hostno, int inout)
{
int dev, spd, spd1;
char *pos = buffer;
PSH shpnt;
PACB acbpnt;
PDCB dcbpnt;
unsigned long flags;
/* Scsi_Cmnd *ptr; */
acbpnt = pACB_start;
while(acbpnt != (PACB)-1)
{
shpnt = acbpnt->pScsiHost;
if (shpnt->host_no == hostno) break;
acbpnt = acbpnt->pNextACB;
}
if (acbpnt == (PACB)-1) return(-ESRCH);
if (!shpnt) return(-ESRCH);
if(inout) /* Has data been written to the file ? */
return(tmscsiw_set_info(buffer, length, shpnt));
SPRINTF("Tekram DC390W/U/F (T) PCI SCSI Host Adadpter, ");
SPRINTF("Driver Version 1.12, 1997/02/17\n");
save_flags(flags);
cli();
SPRINTF("SCSI Host Nr %i, ", hostno);
SPRINTF("DC390WUF Adapter Nr %i\n", acbpnt->AdapterIndex);
SPRINTF("IOPortBase 0x%04x, ", acbpnt -> IOPortBase);
SPRINTF("IRQLevel 0x%02x\n",acbpnt -> IRQLevel);
SPRINTF("Adapter Type: ");
switch(acbpnt->AdaptType)
{
case DC390W: SPRINTF("DC390W, Fast Wide SCSI \n"); break;
case DC390U: SPRINTF("DC390U, Ultra SCSI\n"); break;
case DC390F: SPRINTF("DC390F, Ultra Wide SCSI\n"); break;
default: SPRINTF("Unknown !\n");
}
SPRINTF("MaxID %i, MaxLUN %i, ", acbpnt->max_id, acbpnt->max_lun);
SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ Wide NegoPeriod SyncSpeed SyncOffs\n");
dcbpnt = acbpnt->pLinkDCB;
for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
{
SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
YESNO(dcbpnt->DevMode & PARITY_CHK_);
YESNO(dcbpnt->DCBsxfer & OFFSET_MASK);
YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
YESNO(dcbpnt->DevMode & SEND_START_);
YESNO(dcbpnt->MaxCommand > 1);
YESNO(dcbpnt->DCBscntl3 & EN_WIDE_SCSI);
SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2);
if (dcbpnt->DCBsxfer & OFFSET_MASK)
{
spd = 1000/(dcbpnt->SyncPeriod <<2);
spd1 = 1000%(dcbpnt->SyncPeriod <<2);
spd1 = (spd1 * 10)/(dcbpnt->SyncPeriod <<2);
SPRINTF(" %2i.%1i M %02i\n", spd, spd1, dcbpnt->DCBsxfer & OFFSET_MASK);
}
else SPRINTF("\n");
/* Add more info ...*/
dcbpnt = dcbpnt->pNextDCB;
}
restore_flags(flags);
*start = buffer + offset;
if (pos - buffer < offset)
return 0;
else if (pos - buffer - offset < length)
return pos - buffer - offset;
else
return length;
}
#endif /* VERSION_ELF_1_2_13 */
#ifdef MODULE
/***********************************************************************
* Function : static int DC390W_shutdown (struct Scsi_Host *host)
*
* Purpose : does a clean (we hope) shutdown of the NCR SCSI chip.
* Use prior to dumping core, unloading the NCR driver, etc.
*
* Returns : 0 on success
***********************************************************************/
static int
DC390W_shutdown (struct Scsi_Host *host)
{
USHORT ioport;
unsigned long flags;
PACB pACB = (PACB) host->hostdata;
ioport = (unsigned int) pACB->IOPortBase;
save_flags (flags);
cli();
/* pACB->soft_reset(host); */
/*
* For now, we take the simplest solution : reset the SCSI bus. Eventually,
* - If a command is connected, kill it with an ABORT message
* - If commands are disconnected, connect to each target/LUN and
* do a ABORT, followed by a SOFT reset, followed by a hard
* reset.
*/
#ifdef DC390W_DEBUG0
printk("DC390W: shutdown,");
#endif
outb(ASSERT_RST, ioport+SCNTL1);
udelay(25); /* Minimum amount of time to assert RST */
outb(0, ioport+SCNTL1);
restore_flags (flags);
return( 0 );
}
int DC390W_release(struct Scsi_Host *host)
{
int irq_count;
struct Scsi_Host *tmp;
DC390W_shutdown (host);
if (host->irq != IRQ_NONE)
{
for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
{
if ( tmp->irq == host->irq )
++irq_count;
}
if (irq_count == 1)
{
#ifdef DC390W_DEBUG0
printk("DC390W: Free IRQ %i.",host->irq);
#endif
#ifndef VERSION_ELF_1_2_13
free_irq(host->irq,NULL);
#else
free_irq(host->irq);
#endif
}
}
release_region(host->io_port,host->n_io_port);
return( 1 );
}
Scsi_Host_Template driver_template = DC390WUF;
#include "scsi_module.c"
#endif /* def MODULE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.