/***********************************************************************
* FILE NAME : TMSCSIM.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. *
***********************************************************************/
/* Minor enhancements and bugfixes by *
* Kurt Garloff <K.Garloff@ping.de> *
***********************************************************************/
/* HISTORY: *
* *
* REV# DATE NAME DESCRIPTION *
* 1.00 04/24/96 CLH First release *
* 1.01 06/12/96 CLH Fixed bug of Media Change for Removable *
* Device, scan all LUN. Support Pre2.0.10 *
* 1.02 06/18/96 CLH Fixed bug of Command timeout ... *
* 1.03 09/25/96 KG Added tmscsim_proc_info() *
* 1.04 10/11/96 CLH Updating for support KV 2.0.x *
* 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)*
* 1.06 10/25/96 KG Fixed module support *
* 1.07 11/09/96 KG Fixed tmscsim_proc_info() *
* 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() *
* 1.09 11/30/96 KG Added register the allocated IO space *
* 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset *
* pending interrupt in DC390_detect() *
***********************************************************************/
#define DC390_DEBUG
#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 "tmscsim.h"
#include "constants.h"
#include "sd.h"
#include <linux/stat.h>
#include "dc390.h"
#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI
#ifndef VERSION_ELF_1_2_13
struct proc_dir_entry proc_scsi_tmscsim ={
PROC_SCSI_DC390T, 7 ,"tmscsim",
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
#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 );
int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
#ifdef MODULE
static int DC390_release(struct Scsi_Host *host);
static int DC390_shutdown (struct Scsi_Host *host);
#endif
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 CurrSyncOffset = 0;
static ULONG mech1addr;
static UCHAR mech2bus, mech2Agent, mech2CfgSPenR;
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 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
RewaitSRB0( PDCB pDCB, PSRB pSRB )
{
PSRB psrb1;
ULONG flags;
save_flags(flags);
cli();
if( (psrb1 = pDCB->pWaitingSRB) )
{
pSRB->pNextSRB = psrb1;
pDCB->pWaitingSRB = pSRB;
}
else
{
pSRB->pNextSRB = NULL;
pDCB->pWaitingSRB = pSRB;
pDCB->pWaitLast = pSRB;
}
restore_flags(flags);
}
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
{
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;
}
}
}
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;
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:
restore_flags(flags);
return;
}
/***********************************************************************
* Function : static int DC390_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
DC390_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 DC390_DEBUG0
/* if(pACB->scan_devices) */
printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
#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("DC390: 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 DC390_DEBUG0
printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
#endif
DC390_initDCB( pACB, pDCB, cmd );
}
else /* ???? */
{
/* printk("DC390: 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("DC390: 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 DC390_DEBUG0
printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
#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;
pSRB->ScsiCmdLen = 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->SGIndex = 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->SRBState = 0;
pSRB->TotalXferredLen = 0;
pSRB->SGPhysAddr = 0;
pSRB->SGToBeXferLen = 0;
pSRB->ScsiPhase = 0;
pSRB->EndMessage = 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;
pSRB->ScsiCmdLen = 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->SGIndex = 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->SRBState = 0;
pSRB->TotalXferredLen = 0;
pSRB->SGPhysAddr = 0;
pSRB->SGToBeXferLen = 0;
pSRB->ScsiPhase = 0;
pSRB->EndMessage = 0;
SendSRB( pcmd, pACB, pSRB );
restore_flags(flags);
return;
}
/***********************************************************************
* Function:
* DC390_bios_param
*
* Description:
* Return the disk geometry for the given SCSI device.
***********************************************************************/
#ifdef VERSION_ELF_1_2_13
int DC390_bios_param(Disk *disk, int devno, int geom[])
#else
int DC390_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 ( cylinders > 1024)
{
heads = 255;
sectors = 63;
cylinders = disk->capacity / (255 * 63);
}
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
return (0);
}
/***********************************************************************
* Function : int DC390_abort (Scsi_Cmnd *cmd)
*
* Purpose : Abort an errant SCSI command
*
* Inputs : cmd - command to abort
*
* Returns : 0 on success, -1 on failure.
***********************************************************************/
int
DC390_abort (Scsi_Cmnd *cmd)
{
ULONG flags;
PACB pACB;
PDCB pDCB, pdcb;
PSRB pSRB, psrb;
USHORT count, i;
PSCSICMD pcmd, pcmd1;
int status;
#ifdef DC390_DEBUG0
printk("DC390 : 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; /* No check for psrb == NULL ? */
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
{
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 : int DC390_reset (Scsi_Cmnd *cmd, ...)
*
* Purpose : perform a hard reset on the SCSI bus
*
* Inputs : cmd - command which caused the SCSI RESET
*
* Returns : 0 on success.
***********************************************************************/
#ifdef VERSION_2_0_0
int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
#else
int DC390_reset (Scsi_Cmnd *cmd)
#endif
{
USHORT ioport;
unsigned long flags;
PACB pACB;
UCHAR bval;
USHORT i;
#ifdef DC390_DEBUG1
printk("DC390: RESET,");
#endif
pACB = (PACB ) cmd->host->hostdata;
ioport = pACB->IOPortBase;
save_flags(flags);
cli();
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++ )
udelay(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 );
restore_flags(flags);
#ifdef DC390_DEBUG1
printk("DC390: RESET1,");
#endif
return( SCSI_RESET_SUCCESS );
}
#include "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;
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->UnitSCSIID = cmd->target;
pDCB->UnitSCSILUN = cmd->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][cmd->target << 2];
pDCB->DevMode = prom->EE_MODE1;
pDCB->AdpMode = eepromBuf[index][EE_MODE2];
if( pDCB->DevMode & EN_DISCONNECT_ )
bval = 0xC0;
else
bval = 0x80;
bval |= cmd->lun;
pDCB->IdentifyMsg = bval;
pDCB->SyncMode = 0;
if( pDCB->DevMode & SYNC_NEGO_ )
{
if( !(cmd->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 )
{
#ifndef VERSION_ELF_1_2_13
#ifdef DC390_DEBUG0
printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
#endif
psrb->PhysSRB = virt_to_bus( psrb );
#else
psrb->PhysSRB = (ULONG) psrb;
#endif
}
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( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
{
PACB pACB;
USHORT i;
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;
pACB = (PACB) psh->hostdata;
#ifndef VERSION_ELF_1_2_13
psh->max_id = 8;
#ifdef CONFIG_SCSI_MULTI_LUN
if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
psh->max_lun = 8;
else
#endif
psh->max_lun = 1;
#endif
pACB->max_id = 7;
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->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;
}
/***********************************************************************
* Function : static int DC390_initAdapter
*
* Purpose : initialize the SCSI chip ctrl registers
*
* Inputs : psh - pointer to this host adapter's structure
*
***********************************************************************/
int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
{
USHORT ioport;
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, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
#else
if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
#endif
{
printk("DC390: register IRQ error!\n");
return( -1 );
}
}
request_region(io_port,psh->n_io_port,"tmscsim");
ioport = (USHORT) io_port;
pACB = (PACB) psh->hostdata;
bval = SEL_TIMEOUT; /* 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;
ULONG wval;
ULONG flags;
save_flags(flags);
cli();
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);
restore_flags(flags);
return(bval);
}
USHORT
DC390_inWord( USHORT mechnum, UCHAR regval )
{
USHORT wval;
ULONG flags;
save_flags(flags);
cli();
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);
restore_flags(flags);
return(wval);
}
ULONG
DC390_inDword(USHORT mechnum, UCHAR regval )
{
ULONG wlval;
ULONG flags;
USHORT wval;
save_flags(flags);
cli();
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);
restore_flags(flags);
return(wlval);
}
void
DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
{
USHORT wval;
ULONG flags;
save_flags(flags);
cli();
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);
restore_flags(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);
udelay(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);
}
udelay(160);
bval |= 0x80;
DC390_OutB(mechnum,*regval,bval);
udelay(160);
bval = 0;
DC390_OutB(mechnum,*regval,bval);
udelay(160);
}
UCHAR
DC390_EEpromInDO( USHORT mechnum )
{
UCHAR bval,regval;
regval = 0x80;
bval = 0x80;
DC390_OutB(mechnum,regval,bval);
udelay(160);
bval = 0x40;
DC390_OutB(mechnum,regval,bval);
udelay(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_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 = -1;
return( rc );
}
USHORT
DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
{
USHORT devnum;
devnum = BusDevFunNum;
if(Mechnum == 2)
{
if(devnum & 0x80)
return(-1);
mech2bus = (UCHAR)((devnum & 0xff00) >> 8); /* Bus num */
mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3; /* Dev num */
mech2Agent |= 0xc0;
mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07; /* Fun num */
mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
}
else /* use mech #1 method */
{
mech1addr = 0x80000000 | ((ULONG)devnum << 8);
}
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 (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
{
PSH psh;
PACB pACB;
if( !DC390_CheckEEpromCheckSum( MechNum, index) )
{
psh = scsi_register( psht, sizeof(DC390_ACB) );
if( !psh )
return( -1 );
if( !pSH_start )
{
pSH_start = psh;
pSH_current = psh;
}
else
{
pSH_current->next = psh;
pSH_current = psh;
}
#ifdef DC390_DEBUG0
printk("DC390: pSH = %8x,", (UINT) psh);
printk("DC390: Index %02i,", index);
#endif
DC390_initACB( psh, io_port, Irq, index );
if( !DC390_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 DC390_DEBUG0
printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
(UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
#endif
}
else
{
pSH_start = NULL;
scsi_unregister( psh );
return( -1 );
}
return( 0 );
}
else
{
printk("DC390_init: EEPROM reading error!\n");
return( -1 );
}
}
/***********************************************************************
* Function : int DC390_detect(Scsi_Host_Template *psht)
*
* Purpose : detects and initializes AMD53C974 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
DC390_detect(Scsi_Host_Template *psht)
{
#ifdef FOR_PCI_OK
UCHAR pci_bus, pci_device_fn;
int error = 0;
USHORT chipType = 0;
USHORT i;
#endif
UCHAR irq;
UCHAR istatus;
#ifndef VERSION_ELF_1_2_13
UINT io_port;
#else
ULONG io_port;
#endif
USHORT adaptCnt = 0; /* Number of boards detected */
USHORT pci_index = 0; /* Device index to PCI BIOS calls */
USHORT MechNum, BusDevFunNum;
ULONG wlval;
#ifndef VERSION_ELF_1_2_13
psht->proc_dir = &proc_scsi_tmscsim;
#endif
InitialTime = 1;
pSHT_start = psht;
pACB_start = NULL;
MechNum = 1;
for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
{
BusDevFunNum = 0;
for (; adaptCnt < MAX_ADAPTER_NUM ;)
{
if( !DC390_ToMech( MechNum, BusDevFunNum) )
{
wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
PCI_VENDOR_ID_AMD) )
{
io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
#ifdef DC390_DEBUG0
printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
#endif
if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
{
adaptCnt++;
pci_index++;
istatus = inb( (USHORT)io_port+INT_Status ); /* Reset Pending INT */
#ifdef DC390_DEBUG0
printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
#endif
}
}
}
if( BusDevFunNum != 0xfff8 )
BusDevFunNum += 8; /* next device # */
else
break;
}
}
#ifdef FOR_PCI_OK
if ( pcibios_present() )
{
for (i = 0; i < MAX_ADAPTER_NUM; ++i)
{
if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD53C974,
pci_index, &pci_bus, &pci_device_fn) )
{
chipType = PCI_DEVICE_ID_AMD53C974;
pci_index++;
}
if( chipType )
{
error = pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &io_port);
error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_INTERRUPT_LINE, &irq);
if( error )
{
printk("DC390_detect: reading configuration registers error!\n");
InitialTime = 0;
return( 0 );
}
(USHORT) io_port = (USHORT) io_port & 0xFFFE;
#ifdef DC390_DEBUG0
printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
#endif
if( !DC390_init(psht, io_port, irq, i) )
adaptCnt++;
chipType = 0;
}
else
break;
}
}
#endif
InitialTime = 0;
adapterCnt = adaptCnt;
return( adaptCnt );
}
#ifndef VERSION_ELF_1_2_13
/********************************************************************
* Function: tmscsim_set_info()
*
* Purpose: Set adapter info (!)
*
* Not yet implemented
*
*******************************************************************/
int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
{
return(-ENOSYS); /* Currently this is a no-op */
}
/********************************************************************
* Function: tmscsim_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 tmscsim_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(tmscsim_set_info(buffer, length, shpnt));
SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
SPRINTF("Driver Version 1.10, 1996/12/05\n");
save_flags(flags);
cli();
SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
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 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->SyncMode & SYNC_NEGO_DONE);
YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
YESNO(dcbpnt->DevMode & SEND_START_);
YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2);
if (dcbpnt->SyncOffset & 0x0f)
{
spd = 1000/(dcbpnt->NegoPeriod <<2);
spd1 = 1000%(dcbpnt->NegoPeriod <<2);
spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
}
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 DC390_shutdown (struct Scsi_Host *host)
*
* Purpose : does a clean (we hope) shutdown of the SCSI chip.
* Use prior to dumping core, unloading the driver, etc.
*
* Returns : 0 on success
***********************************************************************/
static int
DC390_shutdown (struct Scsi_Host *host)
{
UCHAR bval;
USHORT ioport;
unsigned long flags;
PACB pACB = (PACB)(host->hostdata);
ioport = (unsigned int) pACB->IOPortBase;
save_flags (flags);
cli();
/* pACB->soft_reset(host); */
#ifdef DC390_DEBUG0
printk("DC390: shutdown,");
#endif
bval = inb(ioport+CtrlReg1);
bval |= DIS_INT_ON_SCSI_RST;
outb(bval,ioport+CtrlReg1); /* disable interrupt */
DC390_ResetSCSIBus( pACB );
restore_flags (flags);
return( 0 );
}
int DC390_release(struct Scsi_Host *host)
{
int irq_count;
struct Scsi_Host *tmp;
DC390_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 DC390_DEBUG0
printk("DC390: 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 = DC390_T;
#include "scsi_module.c"
#endif /* def MODULE */