summaryrefslogtreecommitdiff
path: root/linux/src/drivers/scsi/tmscsiw.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/src/drivers/scsi/tmscsiw.c')
-rw-r--r--linux/src/drivers/scsi/tmscsiw.c2096
1 files changed, 2096 insertions, 0 deletions
diff --git a/linux/src/drivers/scsi/tmscsiw.c b/linux/src/drivers/scsi/tmscsiw.c
new file mode 100644
index 0000000..d32b9fc
--- /dev/null
+++ b/linux/src/drivers/scsi/tmscsiw.c
@@ -0,0 +1,2096 @@
+/***********************************************************************
+ * FILE NAME : TMSCSIW.C *
+ * BY : C.L. Huang (ching@tekram.com.tw) *
+ * 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 <K.Garloff@ping.de> *
+ ***********************************************************************/
+/* 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 */
+