diff options
author | Thomas Bushnell <thomas@gnu.org> | 1999-04-26 05:58:44 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1999-04-26 05:58:44 +0000 |
commit | 86297c41a26f18d924e64fc93321c59cbc4c48dd (patch) | |
tree | 376954c6b95b735d361875319a1a2a9db6a27527 /linux/src/drivers/scsi/tmscsim.c | |
parent | 851137902d3e7ad87af177487df3eea53e940a1c (diff) |
1998-11-30 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
Clean up linux emulation code to make it architecture-independent
as much as possible.
* linux: Renamed from linuxdev.
* Makefile.in (objfiles): Add linux.o instead of linuxdev.o.
(MAKE): New variable. Used for the linux.o target.
* configure.in: Add AC_CHECK_TOOL(MAKE, make).
* i386/i386/spl.h: Include <i386/ipl.h>, for compatibility with
OSF Mach 3.0. Suggested by Elgin Lee <ehl@funghi.com>.
* linux/src: Renamed from linux/linux.
* linux/dev: Renamed from linux/mach.
* linux/Drivers.in (AC_INIT): Use dev/include/linux/autoconf.h,
instead of mach/include/linux/autoconf.h.
* Makefile.in (all): Target ../linux.o instead of ../linuxdev.o.
* linux/dev/drivers/block/genhd.c: Include <machine/spl.h> instead
of <i386/ipl.h>.
* linux/dev/drivers/net/auto_irq.c: Remove unneeded header files,
<i386/ipl.h> and <i386/pic.h>.
* linux/dev/init/main.c: Many i386-dependent codes moved to ...
* linux/dev/arch/i386/irq.c: ... here.
* linux/dev/arch/i386/setup.c: New file.
* linux/dev/arch/i386/linux_emul.h: Likewise.
* linux/dev/arch/i386/glue/timer.c: Merged into sched.c.
* linux/dev/arch/i386/glue/sched.c: Include <machine/spl.h> instead
of <i386/ipl.h>, and moved to ...
* linux/dev/kernel/sched.c: ... here.
* linux/dev/arch/i386/glue/block.c: Include <machine/spl.h> and
<linux_emul.h>, instead of i386-dependent header files, and
moved to ...
* linux/dev/glue/blocl.c: ... here.
* linux/dev/arch/i386/glue/net.c: Include <machine/spl.h> and
<linux_emul.h>, instead of i386-dependent header files, and
moved to ...
* linux/dev/glue/net.c: ... here.
* linux/dev/arch/i386/glue/misc.c: Remove `x86' and moved to ...
* linux/dev/glue/misc.c: ... here.
* linux/dev/arch/i386/glue/kmem.c: Moved to ...
* linux/dev/glue/kmem.c: ... here.
Diffstat (limited to 'linux/src/drivers/scsi/tmscsim.c')
-rw-r--r-- | linux/src/drivers/scsi/tmscsim.c | 1930 |
1 files changed, 1930 insertions, 0 deletions
diff --git a/linux/src/drivers/scsi/tmscsim.c b/linux/src/drivers/scsi/tmscsim.c new file mode 100644 index 0000000..be986ff --- /dev/null +++ b/linux/src/drivers/scsi/tmscsim.c @@ -0,0 +1,1930 @@ +/*********************************************************************** + * 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() * + * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater * + * than 1GB * + ***********************************************************************/ + + +#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 ( (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 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 | SA_SHIRQ, "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 */ + |