--- /dev/null Thu Jan 1 01:00:00 1970 +++ linux/drivers/scsi/dc395x_trm.h Mon Jun 28 23:12:44 1999 @@ -0,0 +1,96 @@ +/* +********************************************************************** +** File Name : dc395x_trm.h +** +** TEKRAM DC395U/UW/F ,DC315/U +** PCI SCSI Bus Master Host AdapterDevice Driver +** (SCSI chip set used Tekram ASIC TRM-S1040) +** +********************************************************************** +*/ + +#define DC395_BANNER "Tekram DC395U/UW/F DC315/U" +#define DC395_VERSION "1.01, 1999/06/28" + +/* Kernel version autodetection */ +#include +#ifndef ASC_LINUX_VERSION +# define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +#endif +//----------------------------------------------------- +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50) + #define VERSION_ELF_1_2_13 +#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95) + #define VERSION_1_3_85 +#else + #define VERSION_2_0_0 +#endif +//****************************************************** +// Tekram TRM_S1040 for DC395x driver, header file +//****************************************************** + +#ifndef DC395x_trm_H +#define DC395x_trm_H + + #if defined(HOSTS_C) || defined(MODULE) + //-------------- + #ifdef VERSION_2_0_0 + #include + #else + #include + #endif + //-------------- + extern int DC395x_trm_detect(Scsi_Host_Template *psht); + extern int DC395x_trm_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); + extern int DC395x_trm_abort(Scsi_Cmnd *cmd); + //-------------- + #ifdef VERSION_2_0_0 + extern int DC395x_trm_reset(Scsi_Cmnd *cmd, unsigned int resetFlags); + #else + extern int DC395x_trm_reset(Scsi_Cmnd *cmd); + #endif + //-------------- + #ifdef VERSION_ELF_1_2_13 + extern int DC395x_trm_bios_param(Disk *disk, int devno, int geom[]); + #else + extern int DC395x_trm_bios_param(Disk *disk, kdev_t devno, int geom[]); + #endif + //-------------- + #ifdef MODULE + static int DC395x_trm_release(struct Scsi_Host *); + #else + #define DC395x_trm_release NULL + #endif + //-------------- + #ifndef VERSION_ELF_1_2_13 + extern struct proc_dir_entry proc_scsi_dc395x; + extern int DC395x_trm_proc_info(char*, char**, off_t, int, int, int); + #endif + //-------------- + #define DC395x_trm_MAXTAGS ( 32 ) + #define DC395x_trm_CAN_QUEUE ( 7 * DC395x_trm_MAXTAGS ) + #define DC395x_trm_CMD_PER_LUN ( DC395x_trm_MAXTAGS ) + + #ifdef VERSION_2_0_0 + + #define DC395x_TRMS1040 { \ + proc_dir: &proc_scsi_dc395x, \ + proc_info: DC395x_trm_proc_info, \ + name: DC395_BANNER " V" DC395_VERSION, \ + detect: DC395x_trm_detect, \ + release: DC395x_trm_release, \ + queuecommand: DC395x_trm_queue_command, \ + abort: DC395x_trm_abort, \ + reset: DC395x_trm_reset, \ + bios_param: DC395x_trm_bios_param, \ + can_queue: DC395x_trm_CAN_QUEUE, \ + this_id: 7, \ + sg_tablesize: 32, /* old (SG_ALL) */ \ + cmd_per_lun: 2, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ + } + #endif + #endif /* defined(HOSTS_C) || defined(MODULE) */ +#endif /* DC395x_trm_H */ --- /dev/null Thu Jan 1 01:00:00 1970 +++ linux/drivers/scsi/dc395x_trm.c Mon Jun 28 23:10:46 1999 @@ -0,0 +1,4880 @@ +//*********************************************************************** +//* O.S : Linux +//* FILE NAME : dc395x_trm.c +//* BY : C.L. Huang +//* Erich Chen +//* Description: Device Driver for Tekram DC395U/UW/F ,DC315/U +//* PCI SCSI Bus Master Host Adapter +//* (SCSI chip set used Tekram ASIC TRM-S1040) +//* (C)Copyright 1995-1999 Tekram Technology Co., Ltd. +//*********************************************************************** +//* Patches and integration into 2.2+ kernel by +//* Kurt Garloff +//*********************************************************************** +//* Tekram PCI SCSI adapter (DC395/U/UW/F or DC315/U) revision history +//* +//* REV# DATE NAME DESCRIPTION +//* 1.00 02/28/99 Erich Chen First release +//* 1.01 06/28/99 Kurt Garloff SMP fixes for 2.2 (locking), +//* cleanup +//*********************************************************************** +//* TO DO: +//* Implement new (2.1.x) PCI config access +/* +************************************************************************* +** +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +************************************************************************* +*/ + +#define DC395x_trm_DEBUG0 + +#define SCSI_MALLOC + +#ifdef MODULE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50) +#include "../block/blk.h" +#else +#include +#endif + +#include "scsi.h" +#include "hosts.h" +#include "constants.h" +#include "sd.h" +#include +#include "dc395x_trm.h" + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,93) +# include +# include +# define USE_SPINLOCKS 1 +# define NEW_PCI 1 +#endif + +#ifdef USE_SPINLOCKS +# define DC395_LOCK_IO spin_lock_irqsave (&io_request_lock, flags) +# define DC395_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, flags) +#else +# define DC395_LOCK_IO save_flags (flags); cli () +# define DC395_UNLOCK_IO restore_flags (flags) +#endif + + +/* +************************************************************************** +*/ +#define IRQ_NONE 255 + +typedef unsigned char BYTE; /* 8 bits */ +typedef unsigned short WORD; /* 16 bits */ +typedef unsigned long DWORD; /* 32 bits */ +typedef unsigned int UINT; /* 16 bits */ +typedef BYTE *PBYTE; +typedef WORD *PWORD; +typedef DWORD *PDWORD; +typedef Scsi_Host_Template *PSHT; +typedef struct Scsi_Host *PSH; +typedef Scsi_Device *PSCSIDEV; +typedef Scsi_Cmnd *PSCSICMD; +typedef void *PVOID; +typedef struct scatterlist *PSGL, SGL; +/* +**struct scatterlist +**{ +** char * address; // Location data is to be transferred to +** char * alt_address; // Location of actual if address is a dma indirect buffer. NULL otherwise +** unsigned int length; +**}; +*/ +/*-----------------------------------------------------------------------*/ +typedef struct _SyncMsg +{ + BYTE ExtendMsg; + BYTE ExtMsgLen; + BYTE SyncXferReq; + BYTE Period; + BYTE ReqOffset; +} SyncMsg; +/*-----------------------------------------------------------------------*/ +typedef struct _SGentry +{ + DWORD address; + DWORD length; +} SGentry, *PSGE0; + +#define MAX_ADAPTER_NUM 4 +#define MAX_DEVICES 10 +#define MAX_SG_LISTENTRY 32 +#define MAX_CMD_QUEUE 20 +#define MAX_CMD_PER_LUN 8 +#define MAX_SCSI_ID 16 +#define MAX_SRB_CNT MAX_CMD_QUEUE+4 +#define END_SCAN 2 + +#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ + +/* +;----------------------------------------------------------------------- +; SCSI Request Block +;----------------------------------------------------------------------- +*/ +struct _SRB +{ + BYTE CmdBlock[12]; + struct _SRB *pNextSRB; + struct _DCB *pSRBDCB; + + DWORD PhysSRB; + + SGentry SegmentX[MAX_SG_LISTENTRY]; + + SGentry SgSenseTemp; + /* + ** make a one entry of S/G list table + ** use it as use_sg case when at request_buffer case + */ + PSCSICMD pcmd; + PSGE0 SRBSGListPointer; + + DWORD SRBTotalXferLength; + + DWORD SRBSGPhyAddr; /* a segment starting address */ + + WORD SRBState; + PBYTE pMsgPtr; + + BYTE SRBSGCount; + BYTE SRBSGIndex; + BYTE MsgInBuf[6]; + BYTE MsgOutBuf[6]; + + BYTE AdaptStatus; + BYTE TargetStatus; + BYTE MsgCnt; + BYTE EndMessage; + + BYTE TagNumber; + BYTE IORBFlag; /* 81h-Reset, 2-retry */ + BYTE SRBStatus; + BYTE RetryCnt; + + DWORD Segment0[2]; + DWORD Segment1[2]; + + BYTE SRBFlag; + BYTE ScsiCmdLen; + BYTE ScsiPhase; + BYTE Reserved3[1]; /* for dword alignment */ +}; +typedef struct _SRB DC395X_TRM_SRB, *PSRB; + +/* +;----------------------------------------------------------------------- +; Device Control Block +;----------------------------------------------------------------------- +*/ +struct _DCB +{ + struct _DCB *pNextDCB; + struct _ACB *pDCBACB; + + PSCSICMD pQIORBhead; + PSCSICMD pQIORBtail; + + PSCSICMD AboIORBhead; + PSCSICMD AboIORBtail; + + WORD QIORBCnt; + WORD AboIORBcnt; + + PSRB pWaitingSRB; + PSRB pWaitLastSRB; + + PSRB pGoingSRB; + PSRB pGoingLastSRB; + + PSRB pActiveSRB; + WORD GoingSRBCnt; + + WORD WaitSRBCnt; + WORD MaxCommand; + + DWORD TagMask; + + WORD AdaptIndex; /* UnitInfo struc start */ + WORD UnitIndex; /* nth Unit on this card */ + + BYTE InqDataBuf[8]; + + BYTE CapacityBuf[8]; + + BYTE TargetID; /* SCSI Target ID (SCSI Only) */ + BYTE TargetLUN; /* SCSI Log. Unit (SCSI Only) */ + BYTE IdentifyMsg; + BYTE DevMode; + + BYTE AdpMode; + BYTE SyncMode; /* 0:async mode */ + BYTE MaxNegoPeriod; /* for nego. */ + BYTE SyncPeriod; /* for reg. */ + + BYTE SyncOffset; /* for reg. and nego.(low nibble) */ + BYTE UnitCtrlFlag; + BYTE DCBFlag; + BYTE DevType; + /* BYTE Reserved2[3]; for dword alignment */ +}; +typedef struct _DCB DC395X_TRM_DCB, *PDCB; +/* +;----------------------------------------------------------------------- +; Adapter Control Block +;----------------------------------------------------------------------- +*/ +struct _ACB +{ + DWORD PhysACB; + PSH pScsiHost; + struct _ACB *pNextACB; + + WORD IOPortBase; + WORD Revxx1; + + PDCB pLinkDCB; + PDCB pDCBRunRobin; + + PDCB pActiveDCB; + PDCB pDCB_free; + + PSRB pFreeSRB; + PSRB pTmpSRB; + + WORD SRBCount; + WORD AdapterIndex; /* nth Adapter this driver */ + + WORD max_id; + WORD max_lun; + + BYTE msgin123[4]; + + + BYTE AdaptSCSIID; /* Adapter SCSI ID */ + BYTE AdaptSCSILUN; /* Adapter SCSI LUN */ + BYTE status; + BYTE DeviceCnt; + + BYTE IRQLevel; + BYTE TagMaxNum; + BYTE ACBFlag; + BYTE Gmode2; + + BYTE Config; + BYTE LUNchk; + BYTE scan_devices; + BYTE HostID_Bit; + + BYTE DCBmap[MAX_SCSI_ID]; + + DC395X_TRM_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */ + + BYTE Reserved1[2]; /* for dword alignment */ + + DC395X_TRM_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */ + DC395X_TRM_SRB TmpSRB; +}; +typedef struct _ACB DC395X_TRM_ACB, *PACB; + +/*-----------------------------------------------------------------------*/ + +#define PCI_Vendor_ID_TEKRAM 0x1DE1 /* Vendor ID */ +#define PCI_Device_ID_TRM_S1040 0x0391 /* Device ID */ + +#define BIT31 0x80000000 +#define BIT30 0x40000000 +#define BIT29 0x20000000 +#define BIT28 0x10000000 +#define BIT27 0x08000000 +#define BIT26 0x04000000 +#define BIT25 0x02000000 +#define BIT24 0x01000000 +#define BIT23 0x00800000 +#define BIT22 0x00400000 +#define BIT21 0x00200000 +#define BIT20 0x00100000 +#define BIT19 0x00080000 +#define BIT18 0x00040000 +#define BIT17 0x00020000 +#define BIT16 0x00010000 +#define BIT15 0x00008000 +#define BIT14 0x00004000 +#define BIT13 0x00002000 +#define BIT12 0x00001000 +#define BIT11 0x00000800 +#define BIT10 0x00000400 +#define BIT9 0x00000200 +#define BIT8 0x00000100 +#define BIT7 0x00000080 +#define BIT6 0x00000040 +#define BIT5 0x00000020 +#define BIT4 0x00000010 +#define BIT3 0x00000008 +#define BIT2 0x00000004 +#define BIT1 0x00000002 +#define BIT0 0x00000001 + +/*---UnitCtrlFlag */ +#define UNIT_ALLOCATED BIT0 +#define UNIT_INFO_CHANGED BIT1 +#define FORMATING_MEDIA BIT2 +#define UNIT_RETRY BIT3 + +/*---UnitFlags */ +#define DASD_SUPPORT BIT0 +#define SCSI_SUPPORT BIT1 +#define ASPI_SUPPORT BIT2 + +/*----SRBState machine definition */ +#define SRB_FREE 0x0000 +#define SRB_WAIT 0x0001 +#define SRB_READY 0x0002 +#define SRB_MSGOUT 0x0004 /*arbitration+msg_out 1st byte*/ +#define SRB_MSGIN 0x0008 +#define SRB_EXTEND_MSGIN 0x0010 +#define SRB_COMMAND 0x0020 +#define SRB_START_ 0x0040 /*arbitration+msg_out+command_out*/ +#define SRB_DISCONNECT 0x0080 +#define SRB_DATA_XFER 0x0100 +#define SRB_XFERPAD 0x0200 +#define SRB_STATUS 0x0400 +#define SRB_COMPLETED 0x0800 +#define SRB_ABORT_SENT 0x1000 +#define SRB_DO_SYNC_NEGO 0x2000 +#define SRB_DO_WIDE_NEGO 0x4000 +#define SRB_UNEXPECT_RESEL 0x8000 +/* +********************************************************************** +** +** ACB Config +** +********************************************************************** +*/ +#define HCC_WIDE_CARD 0x20 +#define HCC_SCSI_RESET 0x10 +#define HCC_PARITY 0x08 +#define HCC_AUTOTERM 0x04 +#define HCC_LOW8TERM 0x02 +#define HCC_UP8TERM 0x01 +/*---ACBFlag */ +#define RESET_DEV BIT0 +#define RESET_DETECT BIT1 +#define RESET_DONE BIT2 + +/*---DCBFlag */ +#define ABORT_DEV_ BIT0 + +/*---SRBstatus */ +#define SRB_OK BIT0 +#define ABORTION BIT1 +#define OVER_RUN BIT2 +#define UNDER_RUN BIT3 +#define PARITY_ERROR BIT4 +#define SRB_ERROR BIT5 + +/*---SRBFlag */ +#define DATAOUT BIT7 +#define DATAIN BIT6 +#define RESIDUAL_VALID BIT5 +#define ENABLE_TIMER BIT4 +#define RESET_DEV0 BIT2 +#define ABORT_DEV BIT1 +#define AUTO_REQSENSE BIT0 + +/*---Adapter status */ +#define H_STATUS_GOOD 0 +#define H_SEL_TIMEOUT 0x11 +#define H_OVER_UNDER_RUN 0x12 +#define H_UNEXP_BUS_FREE 0x13 +#define H_TARGET_PHASE_F 0x14 +#define H_INVALID_CCB_OP 0x16 +#define H_LINK_CCB_BAD 0x17 +#define H_BAD_TARGET_DIR 0x18 +#define H_DUPLICATE_CCB 0x19 +#define H_BAD_CCB_OR_SG 0x1A +#define H_ABORT 0x0FF + +/* SCSI BUS Status byte codes*/ +#define SCSI_STAT_GOOD 0x0 /* Good status */ +#define SCSI_STAT_CHECKCOND 0x02 /* SCSI Check Condition */ +#define SCSI_STAT_CONDMET 0x04 /* Condition Met */ +#define SCSI_STAT_BUSY 0x08 /* Target busy status */ +#define SCSI_STAT_INTER 0x10 /* Intermediate status */ +#define SCSI_STAT_INTERCONDMET 0x14 /* Intermediate condition met */ +#define SCSI_STAT_RESCONFLICT 0x18 /* Reservation conflict */ +#define SCSI_STAT_CMDTERM 0x22 /* Command Terminated */ +#define SCSI_STAT_QUEUEFULL 0x28 /* Queue Full */ +#define SCSI_STAT_UNEXP_BUS_F 0xFD /* Unexpect Bus Free */ +#define SCSI_STAT_BUS_RST_DETECT 0xFE /* Scsi Bus Reset detected */ +#define SCSI_STAT_SEL_TIMEOUT 0xFF /* Selection Time out */ + +/*---Sync_Mode */ +#define SYNC_WIDE_TAG_ATNT_DISABLE 0 +#define SYNC_NEGO_ENABLE BIT0 +#define SYNC_NEGO_DONE BIT1 +#define WIDE_NEGO_ENABLE BIT2 +#define WIDE_NEGO_DONE BIT3 +#define EN_TAG_QUEUING BIT4 +#define EN_ATN_STOP BIT5 + +#define SYNC_NEGO_OFFSET 15 + +/*----SCSI MSG BYTE*/ +#define MSG_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_SAVE_PTR 0x02 +#define MSG_RESTORE_PTR 0x03 +#define MSG_DISCONNECT 0x04 +#define MSG_INITIATOR_ERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT_ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define MSG_LINK_CMD_COMPL 0x0A +#define MSG_LINK_CMD_COMPL_FLG 0x0B +#define MSG_BUS_RESET 0x0C +#define MSG_ABORT_TAG 0x0D +#define MSG_SIMPLE_QTAG 0x20 +#define MSG_HEAD_QTAG 0x21 +#define MSG_ORDER_QTAG 0x22 +#define MSG_IGNOREWIDE 0x23 +#define MSG_IDENTIFY 0x80 +#define MSG_HOST_ID 0xC0 + +/*----SCSI STATUS BYTE*/ +#define STATUS_GOOD 0x00 +#define CHECK_CONDITION_ 0x02 +#define STATUS_BUSY 0x08 +#define STATUS_INTERMEDIATE 0x10 +#define RESERVE_CONFLICT 0x18 + +/* cmd->result */ +#define STATUS_MASK_ 0xFF +#define MSG_MASK 0xFF00 +#define RETURN_MASK 0xFF0000 + +/* +** Inquiry Data format +*/ + +typedef struct _SCSIInqData { /* INQ */ + + BYTE DevType; /* Periph Qualifier & Periph Dev Type*/ + BYTE RMB_TypeMod; /* rem media bit & Dev Type Modifier */ + BYTE Vers; /* ISO, ECMA, & ANSI versions */ + BYTE RDF; /* AEN, TRMIOP, & response data format*/ + BYTE AddLen; /* length of additional data */ + BYTE Res1; /* reserved */ + BYTE Res2; /* reserved */ + BYTE Flags; /* RelADr,Wbus32,Wbus16,Sync,etc. */ + BYTE VendorID[8]; /* Vendor Identification */ + BYTE ProductID[16]; /* Product Identification */ + BYTE ProductRev[4]; /* Product Revision */ +} SCSI_INQDATA, *PSCSI_INQDATA; +/* Inquiry byte 0 masks */ +#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ +#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ +/* Inquiry byte 1 mask */ +#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */ +/* Peripheral Device Type definitions */ +#define SCSI_DASD 0x00 /* Direct-access Device */ +#define SCSI_SEQACESS 0x01 /* Sequential-access device */ +#define SCSI_PRINTER 0x02 /* Printer device */ +#define SCSI_PROCESSOR 0x03 /* Processor device */ +#define SCSI_WRITEONCE 0x04 /* Write-once device */ +#define SCSI_CDROM 0x05 /* CD-ROM device */ +#define SCSI_SCANNER 0x06 /* Scanner device */ +#define SCSI_OPTICAL 0x07 /* Optical memory device */ +#define SCSI_MEDCHGR 0x08 /* Medium changer device */ +#define SCSI_COMM 0x09 /* Communications device */ +#define SCSI_NODEV 0x1F /* Unknown or no device type */ +/* +** Inquiry flag definitions (Inq data byte 7) +*/ +#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing*/ +#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */ +#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */ +#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */ +#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */ +#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */ +#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */ +/*--------------------------*/ +#define ENABLE_CE 1 +#define DISABLE_CE 0 +#define EEPROM_READ 0x80 +/*------------------------------------------------------------------------------*/ +#define INQUIRY_SIZE 36 +#define CAPACITY_SIZE 8 +#define MAX_PCI_DEVICES 21 +#define MAX_PCI_BUSES 8 +#define TOTAL_SRB_ENTRY 255 +#define TOTAL_SG_ENTRY 64 +#define MAX_SUPPORTED_ADAPTERS 4 /* 8 */ +#define MAX_OFFSET 15 +#define MAX_TARGETS 16 +#define MAX_TAGS_SUPPORTTED 255 +/* +*********************************************************************** +* The PCI configuration register offset for TRM_S1040 +*********************************************************************** +*/ +#define TRM_S1040_ID 0x00 /* Vendor and Device ID */ +#define TRM_S1040_COMMAND 0x04 /* PCI command register */ +#define TRM_S1040_IOBASE 0x10 /* I/O Space base address */ +#define TRM_S1040_ROMBASE 0x30 /* Expansion ROM Base Address */ +#define TRM_S1040_INTLINE 0x3C /* Interrupt line */ + +/* +*********************************************************************** +** +** The SCSI register offset for TRM_S1040 +** +*********************************************************************** +*/ +#define TRM_S1040_SCSI_STATUS 0x80 /* SCSI Status (R) */ +/* ######### */ +#define COMMANDPHASEDONE 0x2000 /* SCSI command phase done */ +#define SCSIXFERDONE 0x0800 /* SCSI SCSI transfer done */ +#define SCSIXFERCNT_2_ZERO 0x0100 /* SCSI SCSI transfer count to zero */ +#define SCSIINTERRUPT 0x0080 /* SCSI interrupt pending */ +#define COMMANDABORT 0x0040 /* SCSI command abort */ +#define SEQUENCERACTIVE 0x0020 /* SCSI sequencer active */ +#define PHASEMISMATCH 0x0010 /* SCSI phase mismatch */ +#define PARITYERROR 0x0008 /* SCSI parity error */ + +#define PHASEMASK 0x0007 /* Phase MSG/CD/IO */ +#define PH_DATA_OUT 0x00 /* Data out phase */ +#define PH_DATA_IN 0x01 /* Data in phase */ +#define PH_COMMAND 0x02 /* Command phase */ +#define PH_STATUS 0x03 /* Status phase */ +#define PH_BUS_FREE 0x05 /* Invalid phase used as bus free */ +#define PH_MSG_OUT 0x06 /* Message out phase */ +#define PH_MSG_IN 0x07 /* Message in phase */ + +/* +**************************************** +*/ +#define TRM_S1040_SCSI_CONTROL 0x80 /* SCSI Control (W) */ +/* ######### */ +#define DO_CLRATN 0x0400 /* Clear ATN */ +#define DO_SETATN 0x0200 /* Set ATN */ +#define DO_CMDABORT 0x0100 /* Abort SCSI command */ +#define DO_RSTMODULE 0x0010 /* Reset SCSI chip */ +#define DO_RSTSCSI 0x0008 /* Reset SCSI bus */ +#define DO_CLRFIFO 0x0004 /* Clear SCSI transfer FIFO */ +#define DO_DATALATCH 0x0002 /* Enable SCSI bus data latch */ +#define DO_HWRESELECT 0x0001 /* Enable hardware reselection */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_FIFOCNT 0x82 /* SCSI FIFO Counter 5bits(R) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_SIGNAL 0x83 /* SCSI low level signal (R/W) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_INTSTATUS 0x84 /* SCSI Interrupt Status (R) */ +/* ######### */ +#define INT_SCAM 0x80 /* SCAM selection interrupt */ +#define INT_SELECT 0x40 /* Selection interrupt */ +#define INT_SELTIMEOUT 0x20 /* Selection timeout interrupt */ +#define INT_DISCONNECT 0x10 /* Bus disconnected interrupt */ +#define INT_RESELECTED 0x08 /* Reselected interrupt */ +#define INT_SCSIRESET 0x04 /* SCSI reset detected interrupt */ +#define INT_BUSSERVICE 0x02 /* Bus service interrupt */ +#define INT_CMDDONE 0x01 /* SCSI command done interrupt */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_OFFSET 0x84 /* SCSI Offset Count (W) */ +/* +** Bit Name Definition +** 07-05 0 RSVD Reversed. Always 0. +** 04 0 OFFSET4 Reversed for LVDS. Always 0. +** 03-00 0 OFFSET[03:00] Offset number from 0 to 15 +*/ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_SYNC 0x85 /* SCSI Synchronous Control (R/W) */ +/* ######### */ +#define LVDS_SYNC 0x20 /* Enable LVDS synchronous */ +#define WIDE_SYNC 0x10 /* Enable WIDE synchronous */ +#define ALT_SYNC 0x08 /* Enable Fast-20 alternate synchronous */ +/* +****************************************************************** +** SYNCM 7 6 5 4 3 2 1 0 +** Name RSVD RSVD LVDS WIDE ALTPERD PERIOD2 PERIOD1 PERIOD0 +** Default 0 0 0 0 0 0 0 0 +** +** +** Bit Name Definition +** 07-06 0 RSVD Reversed. Always read 0 +** 05 0 LVDS Reversed. Always read 0 +** 04 0 WIDE/WSCSI Enable wide (16-bits) SCSI transfer. +** 03 0 ALTPERD/ALTPD Alternate (Sync./Period) mode. +** +** @@ When this bit is set, +** the synchronous period bits 2:0 +** in the Synchronous Mode register +** are used to transfer data +** at the Fast-20 rate. +** @@ When this bit is reset, +** the synchronous period bits 2:0 +** in the Synchronous Mode Register +** are used to transfer data +** at the Fast-40 rate. +** +** 02-00 0 PERIOD[2:0]/SXPD[02:00] Synchronous SCSI Transfer Rate. +** These 3 bits specify +** the Synchronous SCSI Transfer Rate +** for Fast-20 and Fast-10. +** These bits are also reset +** by a SCSI Bus reset. +** +** For Fast-10 bit ALTPD = 0 and LVDS = 0 +** and bit2,bit1,bit0 is defined as follows : +** +** 000 100ns, 10.0 Mbytes/s +** 001 150ns, 6.6 Mbytes/s +** 010 200ns, 5.0 Mbytes/s +** 011 250ns, 4.0 Mbytes/s +** 100 300ns, 3.3 Mbytes/s +** 101 350ns, 2.8 Mbytes/s +** 110 400ns, 2.5 Mbytes/s +** 111 450ns, 2.2 Mbytes/s +** +** For Fast-20 bit ALTPD = 1 and LVDS = 0 +** and bit2,bit1,bit0 is defined as follows : +** +** 000 50ns, 20.0 Mbytes/s +** 001 75ns, 13.3 Mbytes/s +** 010 100ns, 10.0 Mbytes/s +** 011 125ns, 8.0 Mbytes/s +** 100 150ns, 6.6 Mbytes/s +** 101 175ns, 5.7 Mbytes/s +** 110 200ns, 5.0 Mbytes/s +** 111 250ns, 4.0 Mbytes/s +** +** For Fast-40 bit ALTPD = 0 and LVDS = 1 +** and bit2,bit1,bit0 is defined as follows : +** +** 000 25ns, 40.0 Mbytes/s +** 001 50ns, 20.0 Mbytes/s +** 010 75ns, 13.3 Mbytes/s +** 011 100ns, 10.0 Mbytes/s +** 100 125ns, 8.0 Mbytes/s +** 101 150ns, 6.6 Mbytes/s +** 110 175ns, 5.7 Mbytes/s +** 111 200ns, 5.0 Mbytes/s +****************************************************************** +*/ + +/* +**************************************** +*/ +#define TRM_S1040_SCSI_TARGETID 0x86 /* SCSI Target ID (R/W) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_IDMSG 0x87 /* SCSI Identify Message (R) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_HOSTID 0x87 /* SCSI Host ID (W) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_COUNTER 0x88 /* SCSI Transfer Counter 24bits(R/W)*/ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_INTEN 0x8C /* SCSI Interrupt Enable (R/W) */ +/* ######### */ +#define EN_SCAM 0x80 /* Enable SCAM selection interrupt */ +#define EN_SELECT 0x40 /* Enable selection interrupt */ +#define EN_SELTIMEOUT 0x20 /* Enable selection timeout interrupt */ +#define EN_DISCONNECT 0x10 /* Enable bus disconnected interrupt */ +#define EN_RESELECTED 0x08 /* Enable reselected interrupt */ +#define EN_SCSIRESET 0x04 /* Enable SCSI reset detected interrupt */ +#define EN_BUSSERVICE 0x02 /* Enable bus service interrupt */ +#define EN_CMDDONE 0x01 /* Enable SCSI command done interrupt */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_CONFIG0 0x8D /* SCSI Configuration 0 (R/W) */ +/* ######### */ +#define PHASELATCH 0x40 /* Enable phase latch */ +#define INITIATOR 0x20 /* Enable initiator mode */ +#define PARITYCHECK 0x10 /* Enable parity check */ +#define BLOCKRST 0x01 /* Disable SCSI reset1 */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_CONFIG1 0x8E /* SCSI Configuration 1 (R/W) */ +/* ######### */ +#define ACTIVE_NEGPLUS 0x10 /* Enhance active negation */ +#define FILTER_DISABLE 0x08 /* Disable SCSI data filter */ +#define ACTIVE_NEG 0x02 /* Enable active negation */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_CONFIG2 0x8F /* SCSI Configuration 2 (R/W) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_COMMAND 0x90 /* SCSI Command (R/W) */ +/* ######### */ +#define SCMD_COMP 0x12 /* Command complete */ +#define SCMD_SEL_ATN 0x60 /* Selection with ATN */ +#define SCMD_SEL_ATN3 0x64 /* Selection with ATN3 */ +#define SCMD_SEL_ATNSTOP 0xB8 /* Selection with ATN and Stop */ +#define SCMD_FIFO_OUT 0xC0 /* SCSI FIFO transfer out */ +#define SCMD_DMA_OUT 0xC1 /* SCSI DMA transfer out */ +#define SCMD_FIFO_IN 0xC2 /* SCSI FIFO transfer in */ +#define SCMD_DMA_IN 0xC3 /* SCSI DMA transfer in */ +#define SCMD_MSGACCEPT 0xD8 /* Message accept */ +/* +** Code Command Description +** +** 02 Enable reselection with FIFO +** 40 Select without ATN with FIFO +** 60 Select with ATN with FIFO +** 64 Select with ATN3 with FIFO +** A0 Select with ATN and stop with FIFO +** C0 Transfer information out with FIFO +** C1 Transfer information out with DMA +** C2 Transfer information in with FIFO +** C3 Transfer information in with DMA +** 12 Initiator command complete with FIFO +** 50 Initiator transfer information out sequence without ATN with FIFO +** 70 Initiator transfer information out sequence with ATN with FIFO +** 74 Initiator transfer information out sequence with ATN3 with FIFO +** 52 Initiator transfer information in sequence without ATN with FIFO +** 72 Initiator transfer information in sequence with ATN with FIFO +** 76 Initiator transfer information in sequence with ATN3 with FIFO +** 90 Initiator transfer information out command complete with FIFO +** 92 Initiator transfer information in command complete with FIFO +** D2 Enable selection +** 08 Reselection +** 48 Disconnect command with FIFO +** 88 Terminate command with FIFO +** C8 Target command complete with FIFO +** 18 SCAM Arbitration/ Selection +** 5A Enable reselection +** 98 Select without ATN with FIFO +** B8 Select with ATN with FIFO +** D8 Message Accepted +** 58 NOP +*/ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_TIMEOUT 0x91 /* SCSI Time Out Value (R/W) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_FIFO 0x98 /* SCSI FIFO (R/W) */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_TCR0 0x9C /* SCSI Target Control 0 (R/W) */ +/* ######### */ +#define TCR0_WIDE_NEGO_DONE 0x8000 /* Wide nego done */ +#define TCR0_SYNC_NEGO_DONE 0x4000 /* Synchronous nego done */ +#define TCR0_ENABLE_LVDS 0x2000 /* Enable LVDS synchronous */ +#define TCR0_ENABLE_WIDE 0x1000 /* Enable WIDE synchronous */ +#define TCR0_ENABLE_ALT 0x0800 /* Enable alternate synchronous */ +#define TCR0_PERIOD_MASK 0x0700 /* Transfer rate */ + +#define TCR0_DO_WIDE_NEGO 0x0080 /* Do wide NEGO */ +#define TCR0_DO_SYNC_NEGO 0x0040 /* Do sync NEGO */ +#define TCR0_DISCONNECT_EN 0x0020 /* Disconnection enable */ +#define TCR0_OFFSET_MASK 0x001F /* Offset number */ +/* +**************************************** +*/ +#define TRM_S1040_SCSI_TCR1 0x9E /* SCSI Target Control 1 (R/W) */ +/* ######### */ +#define MAXTAG_MASK 0x7F00 /* Maximum tags (127) */ +#define NON_TAG_BUSY 0x0080 /* Non tag command active */ +#define ACTTAG_MASK 0x007F /* Active tags */ +/* +*********************************************************************** +** +** The DMA register offset for TRM_S1040 +** +*********************************************************************** +*/ +#define TRM_S1040_DMA_COMMAND 0xA0 /* DMA Command (R/W) */ +/* ######### */ +#define XFERDATAIN 0x0103 /* Transfer data in */ +#define XFERDATAOUT 0x0102 /* Transfer data out */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_FIFOCNT 0xA1 /* DMA FIFO Counter (R) */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_CONTROL 0xA1 /* DMA Control (W) */ +/* ######### */ +#define STOPDMAXFER 0x08 /* Stop DMA transfer */ +#define ABORTXFER 0x04 /* Abort DMA transfer */ +#define CLRXFIFO 0x02 /* Clear DMA transfer FIFO */ +#define STARTDMAXFER 0x01 /* Start DMA transfer */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_STATUS 0xA3 /* DMA Interrupt Status (R/W) */ +/* ######### */ +#define XFERPENDING 0x80 /* Transfer pending */ +#define DMAXFERCOMP 0x02 /* Bus Master XFER Complete status */ +#define SCSICOMP 0x01 /* SCSI complete interrupt */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_INTEN 0xA4 /* DMA Interrupt Enable (R/W) */ +/* ######### */ +#define EN_SCSIINTR 0x01 /* Enable SCSI complete interrupt */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_CONFIG 0xA6 /* DMA Configuration (R/W) */ +/* ######### */ +#define DMA_ENHANCE 0x8000 /* Enable DMA enhance feature */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_XCNT 0xA8 /* DMA Transfer Counter (R/W) */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_CXCNT 0xAC /* DMA Current Transfer Counter (R) */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_XLOWADDR 0xB0 /* DMA Transfer Physical Low Address */ +/* +**************************************** +*/ +#define TRM_S1040_DMA_XHIGHADDR 0xB4 /* DMA Transfer Physical High Address */ + +/* +*********************************************************************** +** +** The general register offset for TRM_S1040 +** +*********************************************************************** +*/ +#define TRM_S1040_GEN_CONTROL 0xD4 /* Global Control */ +/* ######### */ +#define EN_EEPROM 0x10 /* Enable EEPROM programming */ +#define AUTOTERM 0x04 /* Enable Auto SCSI terminator */ +#define LOW8TERM 0x02 /* Enable Lower 8 bit SCSI terminator */ +#define UP8TERM 0x01 /* Enable Upper 8 bit SCSI terminator */ +/* +**************************************** +*/ +#define TRM_S1040_GEN_STATUS 0xD5 /* Global Status */ +/* ######### */ +#define GTIMEOUT 0x80 /* Global timer reach 0 */ +#define CON5068 0x10 /* External 50/68 pin connected */ +#define CON68 0x08 /* Internal 68 pin connected */ +#define CON50 0x04 /* Internal 50 pin connected */ +#define WIDESCSI 0x02 /* Wide SCSI card */ +/* +**************************************** +*/ +#define TRM_S1040_GEN_NVRAM 0xD6 /* Serial NON-VOLATILE RAM port */ +/* ######### */ +#define NVR_BITOUT 0x08 /* Serial data out */ +#define NVR_BITIN 0x04 /* Serial data in */ +#define NVR_CLOCK 0x02 /* Serial clock */ +#define NVR_SELECT 0x01 /* Serial select */ +/* +**************************************** +*/ +#define TRM_S1040_GEN_EDATA 0xD7 /* Parallel EEPROM data port */ +/* +**************************************** +*/ +#define TRM_S1040_GEN_EADDRESS 0xD8 /* Parallel EEPROM address */ +/* +**************************************** +*/ +#define TRM_S1040_GEN_TIMER 0xDB /* Global timer */ + +/* +*********************************************************************** +** The SEEPROM structure for TRM_S1040 +*********************************************************************** +*/ +typedef struct NVRAM_TARGET_STRUCT +{ + BYTE NvmTarCfg0; /* Target configuration byte 0 */ + BYTE NvmTarPeriod; /* Target period */ + BYTE NvmTarCfg2; /* Target configuration byte 2 */ + BYTE NvmTarCfg3; /* Target configuration byte 3 */ +} NVRAMTARGETTYPE; +/* NvmTarCfg0: Target configuration byte 0 :..pDCB->DevMode */ +#define NTC_DO_WIDE_NEGO 0x20 /* Wide negotiate */ +#define NTC_DO_TAG_QUEUING 0x10 /* Enable SCSI tag queuing */ +#define NTC_DO_SEND_START 0x08 /* Send start command SPINUP*/ +#define NTC_DO_DISCONNECT 0x04 /* Enable SCSI disconnect */ +#define NTC_DO_SYNC_NEGO 0x02 /* Sync negotiation */ +#define NTC_DO_PARITY_CHK 0x01 /* (it sould define at NAC ) + Parity check enable */ + +/* +********************************************************************** +** +** +** +********************************************************************** +*/ +typedef struct NVRAM_STRUC +{ + BYTE NvramSubVendorID[2]; /*0,1 Sub Vendor ID */ + BYTE NvramSubSysID[2]; /*2,3 Sub System ID */ + BYTE NvramSubClass; /*4 Sub Class */ + BYTE NvramVendorID[2]; /*5,6 Vendor ID */ + BYTE NvramDeviceID[2]; /*7,8 Device ID */ + BYTE NvramReserved; /*9 Reserved */ + NVRAMTARGETTYPE NvramTarget[MAX_TARGETS];/* + **10,11,12,13 + **14,15,16,17 + ** .... + ** .... + **70,71,72,73 + */ + BYTE NvramScsiId; /*74 Host Adapter SCSI ID */ + BYTE NvramChannelCfg; /*75 Channel configuration */ + BYTE NvramDelayTime; /*76 Power on delay time */ + BYTE NvramMaxTag; /*77 Maximum tags */ + BYTE NvramReserved0; /*78 */ + BYTE NvramBootTarget; /*79 */ + BYTE NvramBootLun; /*80 */ + BYTE NvramReserved1; /*81 */ + WORD Reserved[22]; /*82,..125 */ + WORD NvramCheckSum; /*126,127*/ +} NVRAMTYPE,*PNVRAMTYPE; +/* Nvram Initiater bits definition */ +#define MORE2_DRV BIT0 +#define GREATER_1G BIT1 +#define RST_SCSI_BUS BIT2 +#define ACTIVE_NEGATION BIT3 +#define NO_SEEK BIT4 +#define LUN_CHECK BIT5 + +/* Nvram Adapter Cfg bits definition */ +#define NAC_SCANLUN 0x20 /* Include LUN as BIOS device */ +#define NAC_POWERON_SCSI_RESET 0x04 /* Power on reset enable */ +#define NAC_GREATER_1G 0x02 /* > 1G support enable */ +#define NAC_GT2DRIVES 0x01 /* Support more than 2 drives */ +/* +**#define NAC_DO_PARITY_CHK 0x08 // Parity check enable +*/ +/*------------------------------------------------------------------------------*/ + + +#ifndef VERSION_ELF_1_2_13 +struct proc_dir_entry proc_scsi_dc395x = +{ + PROC_SCSI_DC395X_TRMS1040, + 15, + "DC395x_TRMS1040", + S_IFDIR | S_IRUGO | S_IXUGO, + 2 +}; +#endif + +static void DC395x_trm_check_eeprom(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort); +static void TRM_S1040_read_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort); +static BYTE TRM_S1040_get_data(WORD scsiIOPort, BYTE bAddr); +static void TRM_S1040_write_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort); +static void TRM_S1040_set_data(WORD scsiIOPort, BYTE bAddr, BYTE bData); +static void TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr); + void TRM_S1040_wait_30us(WORD scsiIOPort); + +static void DC395x_trm_DataOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status); +static void DC395x_trm_Disconnect( PACB pACB ); +static void DC395x_trm_Reselect( PACB pACB ); +static void DC395x_trm_ScsiRstDetect( PACB pACB ); +static void DC395x_trm_ResetSCSIBus( PACB pACB ); +static WORD DC395x_trm_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DC395x_trm_BuildSRB(Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB); + int DC395x_trm_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index ); + void DC395x_trm_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); + +static void DC395x_trm_SetXferRate( PACB pACB, PDCB pDCB ); +static void DC395x_trm_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir); +static void DC395x_trm_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DC395x_trm_DoingSRB_Done( PACB pACB ); +static void DC395x_trm_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DC395x_trm_EnableMsgOutAbort2( PACB pACB, PSRB pSRB ); +static void DC395x_trm_EnableMsgOutAbort1( PACB pACB, PSRB pSRB ); + + + + +#ifdef MODULE +static int DC395x_trm_release(struct Scsi_Host *host); +static int DC395x_trm_shutdown (struct Scsi_Host *host); +#endif + + +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 WORD adapterCnt = 0; +static WORD InitialTime = 0; +static WORD CurrSyncOffset = 0; + + +/* +********************************************************* +** +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** +********************************************************* +*/ +static PVOID DC395x_trm_SCSI_phase0[]={ + DC395x_trm_DataOutPhase0, /* phase:0 */ + DC395x_trm_DataInPhase0, /* phase:1 */ + DC395x_trm_CommandPhase0, /* phase:2 */ + DC395x_trm_StatusPhase0, /* phase:3 */ + DC395x_trm_Nop0, /* phase:4 PH_BUS_FREE .. initial phase */ + DC395x_trm_Nop1, /* phase:5 PH_BUS_FREE .. initial phase */ + DC395x_trm_MsgOutPhase0, /* phase:6 */ + DC395x_trm_MsgInPhase0, /* phase:7 */ + }; +/* +********************************************************* +** +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** +********************************************************* +*/ +static PVOID DC395x_trm_SCSI_phase1[]={ + DC395x_trm_DataOutPhase1, /* phase:0 */ + DC395x_trm_DataInPhase1, /* phase:1 */ + DC395x_trm_CommandPhase1, /* phase:2 */ + DC395x_trm_StatusPhase1, /* phase:3 */ + DC395x_trm_Nop0, /* phase:4 PH_BUS_FREE .. initial phase */ + DC395x_trm_Nop1, /* phase:5 PH_BUS_FREE .. initial phase */ + DC395x_trm_MsgOutPhase1, /* phase:6 */ + DC395x_trm_MsgInPhase1, /* phase:7 */ + }; + +NVRAMTYPE eepromBuf[MAX_ADAPTER_NUM]; +/* +**Fast20: 000 50ns, 20.0 Mbytes/s +** 001 75ns, 13.3 Mbytes/s +** 010 100ns, 10.0 Mbytes/s +** 011 125ns, 8.0 Mbytes/s +** 100 150ns, 6.6 Mbytes/s +** 101 175ns, 5.7 Mbytes/s +** 110 200ns, 5.0 Mbytes/s +** 111 250ns, 4.0 Mbytes/s +** +**Fast40: 000 25ns, 40.0 Mbytes/s +** 001 50ns, 20.0 Mbytes/s +** 010 75ns, 13.3 Mbytes/s +** 011 100ns, 10.0 Mbytes/s +** 100 125ns, 8.0 Mbytes/s +** 101 150ns, 6.6 Mbytes/s +** 110 175ns, 5.7 Mbytes/s +** 111 200ns, 5.0 Mbytes/s +*/ +BYTE dc395x_trm_clock_period[] = {12,18,25,31,37,43,50,62}; + /* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */ + +/* +********************************************************************* +** +** DC395x_trm_queue_command DC395x_trm_DoNextCmd +** +********************************************************************* +*/ +static void DC395x_trm_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) +{ + PSCSICMD pcmd; + + 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; + } + +} +/* +********************************************************************* +** +** DC395x_trm_queue_command DC395x_trm_DoNextCmd +** +********************************************************************* +*/ +static PSCSICMD DC395x_trm_Getcmd( PDCB pDCB ) +{ + PSCSICMD pcmd; + + pcmd = pDCB->pQIORBhead; + pDCB->pQIORBhead = pcmd->next; + pcmd->next = NULL; + pDCB->QIORBCnt--; + + return( pcmd ); +} + +/* +********************************************************************* +** +** DC395x_trm_queue_command DC395x_trm_DoNextCmd +** +********************************************************************* +*/ +static PSRB DC395x_trm_GetSRB( PACB pACB ) +{ + PSRB pSRB; + + pSRB = pACB->pFreeSRB; + if( pSRB ) + { + pACB->pFreeSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + return( pSRB ); +} + +/* +********************************************************************* +** +** DC395x_trm_SendSRB +** +** If DC395x_trm_StartSCSI return 1 : +** current interrupt status is interrupt disreenable +** It's said that SCSI processor has more one SRB need to do +** +********************************************************************* +*/ +static void DC395x_trm_RewaitSRB0( PDCB pDCB, PSRB pSRB ) +{ + PSRB pSRBTemp1; + + /* $$$$$$$ */ + if( (pSRBTemp1 = pDCB->pWaitingSRB) ) + { + pSRB->pNextSRB = pSRBTemp1; + } + else + { + pSRB->pNextSRB = NULL; + pDCB->pWaitLastSRB = pSRB; + } + pDCB->pWaitingSRB = pSRB; + /* $$$$$$$ */ +} + +/* +********************************************************************* +** +** DC395x_trm_Disconnect DC395x_trm_Reselect +** DC395x_trm_RequestSense DC395x_trm_SRBdone +** +********************************************************************* +*/ +static void DC395x_trm_RewaitSRB( PDCB pDCB, PSRB pSRB ) +{ + PSRB ptempsrb; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_RewaitSRB..............\n "); + #endif + + pDCB->GoingSRBCnt--; + ptempsrb = pDCB->pGoingSRB; + /* $$$$$$$ */ + if( pSRB == ptempsrb ) + { + /* + ** current SRB is GoingSRB + ** load next SRB to GoingSRB + */ + pDCB->pGoingSRB = ptempsrb->pNextSRB; + } + else + { + /* + ** current SRB is not GoingSRB + ** link the SRB Q and load its NextSRB to NextSRB of GoingSRB + */ + while( pSRB != ptempsrb->pNextSRB ) + { + ptempsrb = ptempsrb->pNextSRB; + } + ptempsrb->pNextSRB = pSRB->pNextSRB; + + if( pSRB == pDCB->pGoingLastSRB ) + { + pDCB->pGoingLastSRB = ptempsrb; + } + } + /* $$$$$$$ */ + if( pDCB->pWaitingSRB != NULL ) + { + /* + ** there was one SRB waiting + */ + pSRB->pNextSRB = pDCB->pWaitingSRB; + pDCB->pWaitingSRB = pSRB; + } + else + { + /* + ** WaitingSRB is NULL + ** point this SRB to WaitLastSRB + */ + pSRB->pNextSRB = NULL; + pDCB->pWaitLastSRB = pSRB; + pDCB->pWaitingSRB = pSRB; + } + + /* $$$$$$$ */ + pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* Free TAG number */ +} + +/* +********************************************************************* +** +** DC395x_trm_reset DC395x_trm_Disconnect +** DC395x_trm_ScsiRstDetect +** +********************************************************************* +*/ +static void DC395x_trm_DoWaitingSRB( PACB pACB ) +{ + PDCB pDCBTemp, pDCBTemp1; + PSRB pSRB; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_DoWaitingSRB..............\n "); + #endif + + if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) + { + pDCBTemp = pACB->pDCBRunRobin; + if( !pDCBTemp ) + { + pDCBTemp = pACB->pLinkDCB; + pACB->pDCBRunRobin = pDCBTemp; + } + pDCBTemp1 = pDCBTemp; + for( ;pDCBTemp1; ) + { + pACB->pDCBRunRobin = pDCBTemp1->pNextDCB; + if( !( pDCBTemp1->MaxCommand > pDCBTemp1->GoingSRBCnt ) || !( pSRB = pDCBTemp1->pWaitingSRB ) ) + { + if(pACB->pDCBRunRobin == pDCBTemp) + { + break; + } + pDCBTemp1 = pDCBTemp1->pNextDCB; + } + else + { + if( !DC395x_trm_StartSCSI(pACB, pDCBTemp1, pSRB) ) + { + /* + ** If DC395x_trm_StartSCSI return 0 : + ** current interrupt status is interrupt enable + ** It's said that SCSI processor is unoccupied + */ + + pDCBTemp1->GoingSRBCnt++; + if( pDCBTemp1->pWaitLastSRB == pSRB ) + { + pDCBTemp1->pWaitingSRB = NULL; + pDCBTemp1->pWaitLastSRB = NULL; + } + else + { + pDCBTemp1->pWaitingSRB = pSRB->pNextSRB; + } + pSRB->pNextSRB = NULL; + if( pDCBTemp1->pGoingSRB ) + { + pDCBTemp1->pGoingLastSRB->pNextSRB = pSRB; + } + else + { + pDCBTemp1->pGoingSRB = pSRB; + } + pDCBTemp1->pGoingLastSRB = pSRB; + } + break; + } + } + } + return; +} + +/* +********************************************************************* +** +** DC395x_trm_SendSRB +** +** +********************************************************************* +*/ +static void DC395x_trm_SRBwaiting( PDCB pDCB, PSRB pSRB) +{ + if( pDCB->pWaitingSRB ) + { + pDCB->pWaitLastSRB->pNextSRB = pSRB; + pSRB->pNextSRB = NULL; + } + else + { + pDCB->pWaitingSRB = pSRB; + } + pDCB->pWaitLastSRB = pSRB; +} + +/* +********************************************************************* +** +** DC395x_trm_queue_command +** DC395x_trm_DoNextCmd +** +********************************************************************* +*/ +static void DC395x_trm_SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) +{ + PDCB pDCB; + + pDCB = pSRB->pSRBDCB; + if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) + { + DC395x_trm_SRBwaiting(pDCB, pSRB); + goto SND_EXIT; + } + if( pDCB->pWaitingSRB ) + { + /* + ** there was one SRB waiting at least ,load this SRB for doing + ** load NextSRB to current WaitingSRB of DCB + ** load NULL to current NextSRB of SRB + */ + DC395x_trm_SRBwaiting(pDCB, pSRB); + /* pSRB = GetWaitingSRB(pDCB); */ + pSRB = pDCB->pWaitingSRB; + pDCB->pWaitingSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + if( !DC395x_trm_StartSCSI(pACB, pDCB, pSRB) ) + { + /* + ** If DC395x_trm_StartSCSI return 0 : + ** current interrupt status is interrupt enable + ** It's said that SCSI processor is unoccupied + */ + pDCB->GoingSRBCnt++; + if( pDCB->pGoingSRB ) + { + /* + ** pDCB->pGoingSRB not null + ** you need Q this SRB in SRB range Q + */ + pDCB->pGoingLastSRB->pNextSRB = pSRB; + pDCB->pGoingLastSRB = pSRB; + } + else + { + /* + ** no SRB range and that pDCB->pGoingSRB is null + ** this SRB's priority is first for doing and is last SRB + */ + pDCB->pGoingSRB = pSRB; + pDCB->pGoingLastSRB = pSRB; + } + } + else + { + /* + ** If DC395x_trm_StartSCSI return 1 : + ** current interrupt status is interrupt disreenable + ** It's said that SCSI processor has more one SRB need to do + */ + DC395x_trm_RewaitSRB0( pDCB, pSRB ); + } + +SND_EXIT: + return; +} + +/* +********************************************************************** +** +** Function : static int DC395x_trm_queue_command(Scsi_Cmnd *cmd,void (*done)(Scsi_Cmnd *)) +** Purpose : enqueues a SCSI command (SCSI I/O) +** Inputs : cmd - SCSI command, done - function called on completion, +** with a pointer to the command descriptor. +** Returns : 0 +** +********************************************************************** +*/ +int DC395x_trm_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + WORD ioport; + Scsi_Cmnd *pcmd; + struct Scsi_Host *psh; + PACB pACB; + PDCB pDCB; + PSRB pSRB; + + psh = cmd->host; + pACB = (PACB ) psh->hostdata; + ioport = pACB->IOPortBase; + #ifdef DC390_DEBUG1 + 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) ) + { /* if scan device ending than link the head of DCB chain with tail */ + 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) ) + { + 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; + //*************************************************** + //* initial device control block + //*************************************************** + DC395x_trm_initDCB( pACB, pDCB, cmd ); + } + else + { + /* printk("DC395x: 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("DC395x: Ignore target %d lun %d\n",cmd->target, cmd->lun); */ + cmd->result = (DID_BAD_TARGET << 16); + done(cmd); + return(0); + } + else + { + /* + ** get a DCB from head of DCB chain + ** that had same target_ID and target_lun with upper layer + */ + pDCB = pACB->pLinkDCB; + while( (pDCB->TargetID != cmd->target) || (pDCB->TargetLUN != cmd->lun) ) + { + pDCB = pDCB->pNextDCB; + } + } + + cmd->scsi_done = done; + cmd->result = 0; + + if( pDCB->QIORBCnt ) + { + DC395x_trm_QLinkcmd( cmd, pDCB ); + pcmd = DC395x_trm_Getcmd( pDCB ); + } + else + { + pcmd = cmd; + } + + pSRB = DC395x_trm_GetSRB( pACB ); + + if( !pSRB ) + { + DC395x_trm_QLinkcmd( pcmd, pDCB ); + return(0); + } + DC395x_trm_BuildSRB( pcmd, pDCB, pSRB); + DC395x_trm_SendSRB( pcmd, pACB, pSRB ); + return(0); +} +/* +********************************************************************** +** +** Function: static void DC395x_trm_BuildSRB (Scsi_Cmd *pcmd, PDCB pDCB, PSRB pSRB) +** +** Purpose: Prepare SRB for being sent to Device DCB w/ command *pcmd +** +********************************************************************** +*/ +static void DC395x_trm_BuildSRB(Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) +{ + + int i,max; + PSGE0 sgp; + struct scatterlist *sl; + + pSRB->pSRBDCB = pDCB; + pSRB->pcmd = pcmd; + pSRB->ScsiCmdLen = pcmd->cmd_len; + /* + ** move uper layer's command block to layer of SCSI Request Block + ** for SCSI processor command doing + */ + memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); + + if( pcmd->use_sg ) + { + pSRB->SRBSGCount = pcmd->use_sg; + pSRB->SRBSGListPointer=(PSGE0) &pSRB->SegmentX[0]; + sgp = pSRB->SRBSGListPointer; + sl = (struct scatterlist *) pcmd->request_buffer; + pSRB->SRBTotalXferLength = 0; + max = pcmd->use_sg; + if(max > MAX_SG_LISTENTRY) + { + printk("cmd->use_sg bigger then dc395x: MAX_SG_LISTENTRY.... \n"); + } + for (i = 0; i < max; i++,sgp++) + { + sgp->address = (DWORD) virt_to_phys( sl[i].address ); + sgp->length = (DWORD) sl[i].length; + pSRB->SRBTotalXferLength += (DWORD) sl[i].length; + } + } + else if( pcmd->request_buffer ) + { + pSRB->SRBSGCount = 1; + pSRB->SRBSGListPointer = (PSGE0) &pSRB->SegmentX[0];/* a one entry of S/G list table */ + pSRB->SegmentX[0].address = (DWORD) virt_to_phys( pcmd->request_buffer );/* Actual requested buffer */ + pSRB->SegmentX[0].length = (DWORD) pcmd->request_bufflen;/* Actual request size */ + pSRB->SRBTotalXferLength = (DWORD) pcmd->request_bufflen; + } + else + { + pSRB->SRBSGCount = 0; + pSRB->SRBTotalXferLength = 0; + } + pSRB->SRBSGIndex = 0; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pSRB->MsgCnt = 0; + pSRB->SRBStatus = 0; + pSRB->SRBFlag = 0; + pSRB->SRBState = 0; + + pSRB->ScsiPhase = PH_BUS_FREE; /* initial phase */ + pSRB->EndMessage = 0; +} +/* +********************************************************************* +** +** DC395x_trm_SRBdone +** +********************************************************************* +*/ +static void DC395x_trm_DoNextCmd( PACB pACB, PDCB pDCB ) +{ + Scsi_Cmnd *pcmd; + PSRB pSRB; + + if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) + { + return; + } + + pcmd = DC395x_trm_Getcmd( pDCB ); + pSRB = DC395x_trm_GetSRB( pACB ); + if( !pSRB ) + { + DC395x_trm_QLinkcmd( pcmd, pDCB ); + } + else + { + DC395x_trm_BuildSRB( pcmd, pDCB, pSRB); + DC395x_trm_SendSRB( pcmd, pACB, pSRB ); + } + return; +} + + +/* +********************************************************************** +** +** Function : DC395x_trm_bios_param +** Description: Return the disk geometry for the given SCSI device. +********************************************************************** +*/ +#ifdef VERSION_ELF_1_2_13 +int DC395x_trm_bios_param(Disk *disk, int devno, int geom[]) +#else +int DC395x_trm_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 & NAC_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 DC395x_trm_abort (Scsi_Cmnd *cmd) +** Purpose : Abort an errant SCSI command +** Inputs : cmd - command to abort +** Returns : 0 on success, -1 on failure. +********************************************************************** +*/ +int DC395x_trm_abort (Scsi_Cmnd *cmd) +{ + PACB pACB; + PDCB pDCB, pDCBTemp; + PSRB pSRB, pSRBTemp; + WORD count, i; + PSCSICMD pcmd, pcmd1; + int status; + + pACB = (PACB) cmd->host->hostdata; + pDCB = pACB->pLinkDCB; + pDCBTemp = pDCB; + while( (pDCB->TargetID != cmd->target) || (pDCB->TargetLUN != cmd->lun) ) + { + pDCB = pDCB->pNextDCB; + if( pDCB == pDCBTemp ) + { + 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; inext == 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 + { + pSRBTemp = pSRB; + if( !(pSRBTemp->pNextSRB) ) + { + goto ON_GOING; + } + while( pSRBTemp->pNextSRB->pcmd != cmd ) + { + pSRBTemp = pSRBTemp->pNextSRB; + if( !(pSRBTemp->pNextSRB) ) + { + goto ON_GOING; + } + } + pSRB = pSRBTemp->pNextSRB; + pSRBTemp->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pWaitLastSRB ) + { + pDCB->pWaitLastSRB = pSRBTemp; /* No check for pSRBTemp == 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; ipcmd != 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); + return( status ); +} + +/* +********************************************************************* +** +** DC395x_trm_reset DC395x_trm_ScsiRstDetect +** +********************************************************************* +*/ +static void DC395x_trm_ResetDevParam( PACB pACB ) +{ + PDCB pDCB, pDCBTemp; + PNVRAMTYPE pEEpromBuf; + BYTE PeriodIndex; + WORD index; + + pDCB = pACB->pLinkDCB; + if( pDCB == NULL ) + { + return; + } + pDCBTemp = pDCB; + do + { + pDCB->SyncMode &= ~SYNC_NEGO_DONE; + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + index = pACB->AdapterIndex; + pEEpromBuf = &eepromBuf[index]; + + pDCB->DevMode = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0; + pDCB->AdpMode = pEEpromBuf->NvramChannelCfg; + PeriodIndex = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod & 0x07; + pDCB->MaxNegoPeriod = dc395x_trm_clock_period[ PeriodIndex ] ; + if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && (pACB->Config & HCC_WIDE_CARD)) + { + pDCB->SyncMode |= WIDE_NEGO_ENABLE; + } + pDCB = pDCB->pNextDCB; + } + while( pDCBTemp != pDCB ); +} + +/* +********************************************************************* +** +** DC395x_trm_ScsiRstDetect +** +********************************************************************* +*/ +static void DC395x_trm_RecoverSRB( PACB pACB ) +{ + PDCB pDCB, pDCBTemp; + PSRB pSRBTemp, pSRBTemp2; + WORD cnt, i; + + pDCB = pACB->pLinkDCB; + if( pDCB == NULL ) + { + return; + } + pDCBTemp = pDCB; + do + { + cnt = pDCBTemp->GoingSRBCnt; + pSRBTemp = pDCBTemp->pGoingSRB; + for (i=0; ipNextSRB; + /* DC395x_trm_RewaitSRB( pDCB, pSRBTemp ); */ + if( pDCBTemp->pWaitingSRB ) + { + pSRBTemp2->pNextSRB = pDCBTemp->pWaitingSRB; + pDCBTemp->pWaitingSRB = pSRBTemp2; + } + else + { + pDCBTemp->pWaitingSRB = pSRBTemp2; + pDCBTemp->pWaitLastSRB = pSRBTemp2; + pSRBTemp2->pNextSRB = NULL; + } + } + pDCBTemp->GoingSRBCnt = 0; + pDCBTemp->pGoingSRB = NULL; + pDCBTemp->TagMask = 0; + pDCBTemp = pDCBTemp->pNextDCB; + } + while( pDCBTemp != pDCB ); +} + + +/* +********************************************************************** +** +** Function : int DC395x_trm_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 DC395x_trm_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) +#else + int DC395x_trm_reset(Scsi_Cmnd *cmd) +#endif +{ + WORD ioport; + PACB pACB; + WORD i; + + pACB = (PACB ) cmd->host->hostdata; + ioport = pACB->IOPortBase; + /* + ** disable interrupt + */ + outb(0x00,ioport+TRM_S1040_DMA_INTEN); + outb(0x00,ioport+TRM_S1040_SCSI_INTEN); + + DC395x_trm_ResetSCSIBus( pACB ); + for( i=0; i<500; i++ ) + { + udelay(1000); + } + /* + ** re-enable interrupt + */ + /* Enable SCSI interrupt*/ + outb(0x7F,ioport+TRM_S1040_SCSI_INTEN); + /* Enable DMA interrupt */ + outb(EN_SCSIINTR,ioport+TRM_S1040_DMA_INTEN); + /* Clear DMA FIFO */ + outb(CLRXFIFO,ioport+TRM_S1040_DMA_CONTROL); + /* Clear SCSI FIFO */ + outw(DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + + DC395x_trm_ResetDevParam( pACB ); + DC395x_trm_DoingSRB_Done( pACB ); + pACB->pActiveDCB = NULL; + + pACB->ACBFlag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */ + DC395x_trm_DoWaitingSRB( pACB ); + + return( SCSI_RESET_SUCCESS ); +} + +/* +********************************************************************** +** scsiio +** DC395x_trm_DoWaitingSRB DC395x_trm_SRBdone +** DC395x_trm_SendSRB DC395x_trm_RequestSense +** +** +** +********************************************************************* +*/ +static WORD DC395x_trm_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + WORD ioport, return_code; + BYTE tag_number, scsicommand, i,command,identify_message; + PBYTE ptr; + DWORD tag_mask; + + pSRB->TagNumber = 31;/* pACB->TagMaxNum: had error read in eeprom*/ + ioport = pACB->IOPortBase; + + outb(pACB->AdaptSCSIID,ioport+TRM_S1040_SCSI_HOSTID); + outb(pDCB->TargetID,ioport+TRM_S1040_SCSI_TARGETID); + outb(pDCB->SyncPeriod,ioport+TRM_S1040_SCSI_SYNC); + outb(pDCB->SyncOffset,ioport+TRM_S1040_SCSI_OFFSET); + pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ + /* Flush FIFO */ + outw( DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + + identify_message = pDCB->IdentifyMsg; + + if( (pSRB->CmdBlock[0] == INQUIRY) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) + { + if( (pDCB->SyncMode & WIDE_NEGO_ENABLE) || (pDCB->SyncMode & SYNC_NEGO_ENABLE) ) + { + if( !(pDCB->IdentifyMsg & 7) || (pSRB->CmdBlock[0] != INQUIRY) ) + { + scsicommand = SCMD_SEL_ATNSTOP; + pSRB->SRBState = SRB_MSGOUT; + goto polling; + } + } + /* + ** Send identify message + */ + outb( (identify_message & 0xBF) ,ioport+TRM_S1040_SCSI_FIFO); + scsicommand = SCMD_SEL_ATN; + pSRB->SRBState = SRB_START_; + } + else + { + /* + ** Send identify message + */ + outb(identify_message,ioport+TRM_S1040_SCSI_FIFO); + scsicommand = SCMD_SEL_ATN; + pSRB->SRBState = SRB_START_; + if(pDCB->SyncMode & EN_TAG_QUEUING) + { + /* Send Tag message */ + /* + ** Get tag id + */ + tag_mask = 1; + tag_number = 0; + while( tag_mask & pDCB->TagMask ) + { + tag_mask = tag_mask << 1; + tag_number++; + } + /* + ** Send Tag id + */ + outb(MSG_SIMPLE_QTAG,ioport+TRM_S1040_SCSI_FIFO); + outb(tag_number,ioport+TRM_S1040_SCSI_FIFO); + + pDCB->TagMask |= tag_mask; + pSRB->TagNumber = tag_number; + + scsicommand = SCMD_SEL_ATN3; + pSRB->SRBState = SRB_START_; + } + } +polling: + /* + ** Send CDB ..command block ......... + */ + if( pSRB->SRBFlag & AUTO_REQSENSE ) + { + outb(REQUEST_SENSE,ioport+TRM_S1040_SCSI_FIFO); + outb((pDCB->IdentifyMsg << 5),ioport+TRM_S1040_SCSI_FIFO); + outb(0,ioport+TRM_S1040_SCSI_FIFO); + outb(0,ioport+TRM_S1040_SCSI_FIFO); + outb(sizeof(pSRB->pcmd->sense_buffer),ioport+TRM_S1040_SCSI_FIFO); + outb(0,ioport+TRM_S1040_SCSI_FIFO); + } + else + { + ptr = (PBYTE) pSRB->CmdBlock; + for(i=0; i < pSRB->ScsiCmdLen ; i++) + { + command = *ptr++; + outb(command,ioport+TRM_S1040_SCSI_FIFO); + } + } + if( inw( ioport+TRM_S1040_SCSI_STATUS ) & SCSIINTERRUPT ) + { + /* + ** If DC395x_trm_StartSCSI return 1 : + ** current interrupt status is interrupt disreenable + ** It's said that SCSI processor has more one SRB need to do, + ** SCSI processor has been occupied by one SRB. + */ + pSRB->SRBState = SRB_READY; + pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); + return_code = 1; + } + else + { + /* + ** If DC395x_trm_StartSCSI return 0 : + ** current interrupt status is interrupt enable + ** It's said that SCSI processor is unoccupied + */ + pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ + pACB->pActiveDCB = pDCB; + pDCB->pActiveSRB = pSRB; + return_code = 0; + outw(DO_DATALATCH | DO_HWRESELECT, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb(scsicommand,ioport+TRM_S1040_SCSI_COMMAND); + } + return( return_code ); +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_initAdapter +** +********************************************************************* +*/ +#ifndef VERSION_ELF_1_2_13 +static void + DC395x_trm_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +#else +static void + DC395x_trm_Interrupt( int irq, struct pt_regs *regs) +#endif +{ + PACB pACB; + PDCB pDCB; + PSRB pSRB; + WORD ioport = 0; + WORD phase, i; + void (*stateV)( PACB, PSRB, PWORD ); + BYTE scsi_intstatus; + WORD scsi_status=0; + DWORD flags; + + pACB = pACB_start; + if( pACB == NULL ) + return; + + DC395_LOCK_IO; + + for( i=0; i < adapterCnt; i++ ) + { + /* + ** find mach correct pACB with same IRQLevel + ** and request SCSI interrupt service + ** :...search which pACB->IRQLevel is matching with irq + */ + if( pACB->IRQLevel == (BYTE) irq ) + { + ioport = pACB->IOPortBase; + scsi_status = inw( ioport+TRM_S1040_SCSI_STATUS ); + /* + #define PH_DATA_OUT 0x00 // Data out phase + #define PH_DATA_IN 0x01 // Data in phase + #define PH_COMMAND 0x02 // Command phase + #define PH_STATUS 0x03 // Status phase + #define PH_BUS_FREE 0x05 // Invalid phase used as bus free + #define PH_MSG_OUT 0x06 // Message out phase + #define PH_MSG_IN 0x07 // Message in phase + */ + if( scsi_status & SCSIINTERRUPT ) + { + /* + ** interrupt service request signal + ** is come from this adapter (pACB) + */ + break; + } + else + { + /* + ** point to next adapter pACB if no interrupt pending + */ + pACB = pACB->pNextACB; + } + } + else + { + /* + ** point to next adapter pACB + */ + pACB = pACB->pNextACB; + } + } + if( pACB == (PACB )-1 ) + { + printk("DC395x_trm_Interrupt: Spurious interrupt detected!\n"); + goto out_unlock; + } + scsi_intstatus = inb( ioport+TRM_S1040_SCSI_INTSTATUS ); + + if(scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) + { + DC395x_trm_Disconnect( pACB );/* bus free interrupt */ + goto out_unlock; + } + if(scsi_intstatus & INT_RESELECTED) + { + DC395x_trm_Reselect( pACB ); + goto out_unlock; + } + if(scsi_intstatus & INT_SCSIRESET) + { + DC395x_trm_ScsiRstDetect( pACB ); + goto out_unlock; + } + if( scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE) ) + { + pDCB = pACB->pActiveDCB; + pSRB = pDCB->pActiveSRB; + if( pDCB ) + { + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); + } + } + /* + ************************************************************ + ** software sequential machine + ************************************************************ + */ + phase = (WORD) pSRB->ScsiPhase; + /* + ** 62037 or 62137 + ** call DC395x_trm_SCSI_phase0[]... "phase entry" + ** handle every phase before start transfer + */ + /* DC395x_trm_DataOutPhase0, phase:0 */ + /* DC395x_trm_DataInPhase0, phase:1 */ + /* DC395x_trm_CommandPhase0, phase:2 */ + /* DC395x_trm_StatusPhase0, phase:3 */ + /* DC395x_trm_Nop0, phase:4 PH_BUS_FREE .. initial phase */ + /* DC395x_trm_Nop1, phase:5 PH_BUS_FREE .. initial phase */ + /* DC395x_trm_MsgOutPhase0, phase:6 */ + /* DC395x_trm_MsgInPhase0, phase:7 */ + stateV = (void *) DC395x_trm_SCSI_phase0[phase]; + stateV( pACB, pSRB, &scsi_status ); + /* + **$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + ** + ** if there were any exception occured + ** scsi_status will be modify to bus free phase + ** new scsi_status transfer out from ... prvious stateV + ** + **$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + */ + pSRB->ScsiPhase = scsi_status & PHASEMASK; + phase = (WORD) scsi_status & PHASEMASK; + /* + ** call DC395x_trm_SCSI_phase1[]... "phase entry" + ** handle every phase do transfer + */ + /* DC395x_trm_DataOutPhase1, phase:0 */ + /* DC395x_trm_DataInPhase1, phase:1 */ + /* DC395x_trm_CommandPhase1, phase:2 */ + /* DC395x_trm_StatusPhase1, phase:3 */ + /* DC395x_trm_Nop0, phase:4 PH_BUS_FREE .. initial phase */ + /* DC395x_trm_Nop1, phase:5 PH_BUS_FREE .. initial phase */ + /* DC395x_trm_MsgOutPhase1, phase:6 */ + /* DC395x_trm_MsgInPhase1, phase:7 */ + stateV = (void *) DC395x_trm_SCSI_phase1[phase]; + stateV( pACB, pSRB, &scsi_status ); + } + out_unlock: + DC395_UNLOCK_IO; +} +/* +********************************************************************* +** scsiio +** DC395x_trm_MsgOutPhase0: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =6 +** +** +********************************************************************* +*/ +static void DC395x_trm_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + WORD ioport; + + ioport = pACB->IOPortBase; + if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) + { + *pscsi_status = PH_BUS_FREE;/*.. initial phase*/ + } +} +/* +********************************************************************* +** scsiio +** DC395x_trm_MsgOutPhase1: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =6 +** +** +********************************************************************* +*/ +static void DC395x_trm_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + WORD ioport, i; + PBYTE ptr; + PDCB pDCB; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_MsgOutPhase1..............\n "); + #endif + ioport = pACB->IOPortBase; + outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); + pDCB = pACB->pActiveDCB; + if( !(pSRB->SRBState & SRB_MSGOUT) ) + { + if( pSRB->MsgCnt ) + { + ptr = (PBYTE) pSRB->MsgOutBuf; + for(i=0; i < pSRB->MsgCnt ; i++) + { + outb(*ptr, ioport+TRM_S1040_SCSI_FIFO); + ptr++; + } + pSRB->MsgCnt = 0; + if( (pDCB->DCBFlag & ABORT_DEV_) && (pSRB->MsgOutBuf[0] == MSG_ABORT) ) + { + pSRB->SRBState = SRB_ABORT_SENT; + } + } + else + { + + if( (pSRB->CmdBlock[0] == INQUIRY ) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) + { + if( pDCB->SyncMode & SYNC_NEGO_ENABLE ) + { + goto mop1; + } + } + outb(MSG_ABORT, ioport+TRM_S1040_SCSI_FIFO); + } + } + else + { +mop1: /* message out phase */ + if( !(pSRB->SRBState & SRB_DO_WIDE_NEGO) && (pDCB->SyncMode & WIDE_NEGO_ENABLE) ) + { + + /* + ** WIDE DATA TRANSFER REQUEST code (03h) + */ + pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP ); + outb( (pDCB->IdentifyMsg & 0xBF) ,ioport+TRM_S1040_SCSI_FIFO); + outb( MSG_EXTENDED,ioport+TRM_S1040_SCSI_FIFO); /* (01h) */ + outb( 2,ioport+TRM_S1040_SCSI_FIFO); /* Message length (02h) */ + outb( 3,ioport+TRM_S1040_SCSI_FIFO); /* wide data xfer (03h) */ + outb( 1,ioport+TRM_S1040_SCSI_FIFO); /* width:0(8bit),1(16bit),2(32bit) */ + pSRB->SRBState |= SRB_DO_WIDE_NEGO; + } + else if( !(pSRB->SRBState & SRB_DO_SYNC_NEGO) && (pDCB->SyncMode & SYNC_NEGO_ENABLE) ) + { + /* + ** SYNCHRONOUS DATA TRANSFER REQUEST code (01h) + */ + if(!(pDCB->SyncMode & WIDE_NEGO_DONE) ) + { + outb( (pDCB->IdentifyMsg & 0xBF) ,ioport+TRM_S1040_SCSI_FIFO); + } + outb( MSG_EXTENDED,ioport+TRM_S1040_SCSI_FIFO); /* (01h) */ + outb( 3,ioport+TRM_S1040_SCSI_FIFO); /* Message length (03h) */ + outb( 1,ioport+TRM_S1040_SCSI_FIFO); /* SYNCHRONOUS DATA TRANSFER REQUEST code (01h) */ + outb( pDCB->MaxNegoPeriod,ioport+TRM_S1040_SCSI_FIFO);/* Transfer peeriod factor */ + outb( SYNC_NEGO_OFFSET,ioport+TRM_S1040_SCSI_FIFO); /* REQ/ACK offset */ + pSRB->SRBState |= SRB_DO_SYNC_NEGO; + } + } + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb( SCMD_FIFO_OUT, ioport+TRM_S1040_SCSI_COMMAND); +} +/* +********************************************************************* +** scsiio +** DC395x_trm_CommandPhase0: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =2 +** +** +********************************************************************* +*/ +static void DC395x_trm_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ +} +/* +********************************************************************* +** scsiio +** DC395x_trm_CommandPhase1: one of DC395x_trm_SCSI_phase1[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** if phase =2 +** +** +********************************************************************* +*/ +static void DC395x_trm_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + PDCB pDCB; + PBYTE ptr; + WORD ioport, i; + + + ioport = pACB->IOPortBase; + outw( DO_CLRATN | DO_CLRFIFO , ioport+TRM_S1040_SCSI_CONTROL); + if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) + { + ptr = (PBYTE) pSRB->CmdBlock; + for(i=0; i < pSRB->ScsiCmdLen ; i++) + { + outb(*ptr, ioport+TRM_S1040_SCSI_FIFO); + ptr++; + } + } + else + { + outb(REQUEST_SENSE, ioport+TRM_S1040_SCSI_FIFO); + pDCB = pACB->pActiveDCB; + /* target id */ + outb((pDCB->IdentifyMsg << 5), ioport+TRM_S1040_SCSI_FIFO); + outb(0, ioport+TRM_S1040_SCSI_FIFO); + outb(0, ioport+TRM_S1040_SCSI_FIFO); + outb(sizeof(pSRB->pcmd->sense_buffer), ioport+TRM_S1040_SCSI_FIFO); + outb(0, ioport+TRM_S1040_SCSI_FIFO); + } + pSRB->SRBState = SRB_COMMAND; + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb(SCMD_FIFO_OUT, ioport+TRM_S1040_SCSI_COMMAND); +} +/* +********************************************************************* +** scsiio +** DC395x_trm_DataOutPhase0: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =0 +** +** +********************************************************************* +*/ +static void DC395x_trm_DataOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + PDCB pDCB; + BYTE TempDMAstatus,SGIndexTemp; + WORD ioport,scsi_status; + PSGE0 psge; + DWORD TempSRBXferredLength,dLeftCounter=0; + + + pDCB = pSRB->pSRBDCB; + ioport = pACB->IOPortBase; + scsi_status = *pscsi_status; + + if( !(pSRB->SRBState & SRB_XFERPAD) ) + { + if( scsi_status & PARITYERROR ) + { + pSRB->SRBStatus |= PARITY_ERROR; + } + if (!(scsi_status & SCSIXFERDONE)) + { + /* + ** when data transfer from DMA FIFO to SCSI FIFO + ** if there was some data left in SCSI FIFO + */ + dLeftCounter = (DWORD) (inb(ioport+TRM_S1040_SCSI_FIFOCNT) & 0x1F); + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) + { + /* + ** if WIDE scsi SCSI FIFOCNT unit is word + ** so need to * 2 + */ + dLeftCounter <<= 1; + } + } + /* + ** caculate all the residue data that not yet tranfered + ** SCSI transfer counter + left in SCSI FIFO data + ** + ** .....TRM_S1040_SCSI_COUNTER (24bits) + ** The counter always decrement by one for every SCSI byte transfer. + ** .....TRM_S1040_SCSI_FIFOCNT ( 5bits) + ** The counter is SCSI FIFO offset counter + */ + dLeftCounter += inl(ioport+TRM_S1040_SCSI_COUNTER); + if ( dLeftCounter == 1 ) + { + dLeftCounter = 0; + outw(DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + } + if((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO) ) + { + TempDMAstatus = inb(ioport+TRM_S1040_DMA_STATUS); + while( !(TempDMAstatus & DMAXFERCOMP) ) + { + TempDMAstatus = inb(ioport+TRM_S1040_DMA_STATUS); + } + pSRB->SRBTotalXferLength = 0; + } + else /* Update SG list */ + { + /* + ** if transfer not yet complete + ** there were some data residue in SCSI FIFO or + ** SCSI transfer counter not empty + */ + if (pSRB->SRBTotalXferLength != dLeftCounter) + { + /* + ** data that had transferred length + */ + TempSRBXferredLength = pSRB->SRBTotalXferLength - dLeftCounter; + /* + ** next time to be transferred length + */ + pSRB->SRBTotalXferLength = dLeftCounter; + /* + ** parsing from last time disconnect SGIndex + */ + psge = pSRB->SRBSGListPointer + pSRB->SRBSGIndex; + for ( SGIndexTemp= pSRB->SRBSGIndex ; SGIndexTemp < pSRB->SRBSGCount; SGIndexTemp++) + { + /* + ** find last time which SG transfer be disconnect + */ + if (TempSRBXferredLength >= psge->length) + { + TempSRBXferredLength -= psge->length; + } + else + { + /* + ** update last time disconnected SG list + */ + psge->length -= TempSRBXferredLength; /* residue data length */ + psge->address += TempSRBXferredLength;/* residue data pointer */ + pSRB->SRBSGIndex = SGIndexTemp; + break; + } + psge++; + } + } + } + } +} +/* +********************************************************************* +** scsiio +** DC395x_trm_DataOutPhase1: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =0 +** +** 62037 +********************************************************************* +*/ +static void DC395x_trm_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + WORD ioDir; + /* + ** do prepare befor transfer when data out phase + */ + ioDir = XFERDATAOUT; + DC395x_trm_DataIO_transfer( pACB, pSRB, ioDir); +} + + +/* +********************************************************************* +** scsiio +** DC395x_trm_DataInPhase0: one of DC395x_trm_SCSI_phase1[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** if phase =1 +** +** +********************************************************************* +*/ +static void DC395x_trm_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + BYTE bval,SGIndexTemp; + WORD ioport,scsi_status; + PSGE0 psge; + DWORD TempSRBXferredLength,dLeftCounter=0; + + ioport = pACB->IOPortBase; + scsi_status = *pscsi_status; + if( !(pSRB->SRBState & SRB_XFERPAD) ) + { + if( scsi_status & PARITYERROR ) + { + pSRB->SRBStatus |= PARITY_ERROR; + } + dLeftCounter += inl(ioport+TRM_S1040_SCSI_COUNTER); + if((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO) ) + { + bval = inb(ioport+TRM_S1040_DMA_STATUS); + while( !(bval & DMAXFERCOMP) ) + { + bval = inb(ioport+TRM_S1040_DMA_STATUS); + } + pSRB->SRBTotalXferLength = 0; + } + else /* phase changed */ + { + /* + ** parsing the case: + ** when a transfer not yet complete + ** but be disconnected by uper layer + ** if transfer not yet complete + ** there were some data residue in SCSI FIFO or + ** SCSI transfer counter not empty + */ + if (pSRB->SRBTotalXferLength != dLeftCounter) + { + /* + ** data that had transferred length + */ + TempSRBXferredLength = pSRB->SRBTotalXferLength - dLeftCounter; + /* + ** next time to be transferred length + */ + pSRB->SRBTotalXferLength = dLeftCounter; + /* + ** parsing from last time disconnect SGIndex + */ + psge = pSRB->SRBSGListPointer + pSRB->SRBSGIndex; + for ( SGIndexTemp = pSRB->SRBSGIndex; SGIndexTemp < pSRB->SRBSGCount ; SGIndexTemp++) + { + /* + ** find last time which SG transfer be disconnect + */ + if (TempSRBXferredLength >= psge->length) + { + TempSRBXferredLength -= psge->length; + } + else + { + /* + ** update last time disconnected SG list + */ + psge->length -= TempSRBXferredLength; /* residue data length */ + psge->address += TempSRBXferredLength;/* residue data pointer */ + pSRB->SRBSGIndex = SGIndexTemp; + break; + } + psge++; + } + } + } + } +} +/* +********************************************************************* +** scsiio +** DC395x_trm_DataInPhase1: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =1 +** +** +********************************************************************* +*/ +static void DC395x_trm_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + WORD ioDir; + /* + ** do prepare befor transfer when data in phase + */ + ioDir = XFERDATAIN; + DC395x_trm_DataIO_transfer( pACB, pSRB, ioDir); +} + + +/* +********************************************************************* +** scsiio +** DC395x_trm_DataOutPhase1 +** DC395x_trm_DataInPhase1 +** +********************************************************************* +*/ +static void DC395x_trm_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir) +{ + BYTE bval; + WORD ioport; + PDCB pDCB; + + ioport = pACB->IOPortBase; + pDCB = pSRB->pSRBDCB; + if( pSRB->SRBSGIndex < pSRB->SRBSGCount ) + { + if( pSRB->SRBTotalXferLength != 0 ) + { + + #ifndef VERSION_ELF_1_2_13 + pSRB->SRBSGPhyAddr = virt_to_phys( pSRB->SRBSGListPointer ); + #else + pSRB->SRBSGPhyAddr = (DWORD) pSRB->SRBSGListPointer; + #endif + /* + ** load what physical address of Scatter/Gather list table want to be + ** transfer + */ + pSRB->SRBState = SRB_DATA_XFER; + outl( 0, ioport+TRM_S1040_DMA_XHIGHADDR); + outl( ( pSRB->SRBSGPhyAddr + ((DWORD)pSRB->SRBSGIndex << 3) ), ioport+TRM_S1040_DMA_XLOWADDR); + /* load how many bytes in the Scatter/Gather list table */ + outl( ((DWORD) (pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3), ioport+TRM_S1040_DMA_XCNT); + /* load total transfer length (24bits) max value 16Mbyte */ + outl(pSRB->SRBTotalXferLength, ioport+TRM_S1040_SCSI_COUNTER); + /* Start DMA transfer */ + outw(ioDir, ioport+TRM_S1040_DMA_COMMAND); + /* outw(STARTDMAXFER, ioport+TRM_S1040_DMA_CONTROL);*/ + /* Start SCSI transfer */ + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + bval = (ioDir == XFERDATAOUT) ? SCMD_DMA_OUT : SCMD_DMA_IN; + outb(bval, ioport+TRM_S1040_SCSI_COMMAND); + } + else /* xfer pad */ + { + if( pSRB->SRBSGCount ) + { + pSRB->AdaptStatus = H_OVER_UNDER_RUN; + pSRB->SRBStatus |= OVER_RUN; + } + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) + { + outl(2,ioport+TRM_S1040_SCSI_COUNTER); + } + else + { + outl(1,ioport+TRM_S1040_SCSI_COUNTER); + } + if(ioDir == XFERDATAOUT) + { + outw(0, ioport+TRM_S1040_SCSI_FIFO); + } + else + { + inw(ioport+TRM_S1040_SCSI_FIFO); + } + pSRB->SRBState |= SRB_XFERPAD; + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + bval = (ioDir == XFERDATAOUT) ? SCMD_FIFO_OUT : SCMD_FIFO_IN; + outb(bval, ioport+TRM_S1040_SCSI_COMMAND); + } + } +} +/* +********************************************************************* +** scsiio +** DC395x_trm_StatusPhase0: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =3 +** +** +********************************************************************* +*/ +static void DC395x_trm_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + WORD ioport; + + ioport = pACB->IOPortBase; + + pSRB->TargetStatus = inb(ioport+TRM_S1040_SCSI_FIFO); + pSRB->EndMessage = inb(ioport+TRM_S1040_SCSI_FIFO); /* get message */ + pSRB->SRBState = SRB_COMPLETED; + *pscsi_status = PH_BUS_FREE; /*.. initial phase*/ + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb(SCMD_MSGACCEPT, ioport+TRM_S1040_SCSI_COMMAND); +} +/* +********************************************************************* +** scsiio +** DC395x_trm_StatusPhase1: one of DC395x_trm_SCSI_phase1[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** if phase =3 +** +** +********************************************************************* +*/ +static void DC395x_trm_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + WORD ioport; + + ioport = pACB->IOPortBase; + + if (inw(ioport+TRM_S1040_DMA_COMMAND) & 0x0001) + { + if (!(inb(ioport+TRM_S1040_SCSI_FIFOCNT) & 0x40)) + { + outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); + } + if (!(inw(ioport+TRM_S1040_DMA_FIFOCNT) & 0x8000)) + { + outb(CLRXFIFO, ioport+TRM_S1040_DMA_CONTROL); + } + } + else + { + if (!(inw(ioport+TRM_S1040_DMA_FIFOCNT) & 0x8000)) + { + outb(CLRXFIFO, ioport+TRM_S1040_DMA_CONTROL); + } + if (!(inb(ioport+TRM_S1040_SCSI_FIFOCNT) & 0x40)) + { + outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); + } + } + pSRB->SRBState = SRB_STATUS; + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb(SCMD_COMP, ioport+TRM_S1040_SCSI_COMMAND); +} +/* +********************************************************************* +** scsiio +** DC395x_trm_MsgInPhase0: one of DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** if phase =7 +** +** extended message codes: +** +** code description +** +** 02h Reserved +** 00h MODIFY DATA POINTER +** 01h SYNCHRONOUS DATA TRANSFER REQUEST +** 03h WIDE DATA TRANSFER REQUEST +** 04h - 7Fh Reserved +** 80h - FFh Vendor specific +** +********************************************************************* +*/ +static void DC395x_trm_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + BYTE message_in_code,bIndex,message_in_tag_id; + WORD ioport; + PDCB pDCB; + PSRB pSRBTemp; + + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_MsgInPhase0..............\n "); + #endif + ioport = pACB->IOPortBase; + pDCB = pACB->pActiveDCB; + + message_in_code = inb( ioport+TRM_S1040_SCSI_FIFO ); + if( !(pSRB->SRBState & SRB_EXTEND_MSGIN) ) + { + if(message_in_code == MSG_DISCONNECT) + { + pSRB->SRBState = SRB_DISCONNECT; + goto min6; + } + else if( message_in_code == MSG_SAVE_PTR ) + { + goto min6; + } + else if( (message_in_code == MSG_EXTENDED) || ((message_in_code >= MSG_SIMPLE_QTAG) && (message_in_code <= MSG_ORDER_QTAG)) ) + { + pSRB->SRBState |= SRB_EXTEND_MSGIN; + pSRB->MsgInBuf[0] = message_in_code;/* extended message (01h)*/ + pSRB->MsgCnt = 1; + pSRB->pMsgPtr = &pSRB->MsgInBuf[1]; /* extended message length (n)*/ + goto min6; + } + else if(message_in_code == MSG_REJECT_) + { + /* Reject message */ + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) + { /* do wide nego reject */ + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode |= WIDE_NEGO_DONE; + pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP | WIDE_NEGO_ENABLE ); + pSRB->SRBState &= ~(SRB_DO_WIDE_NEGO+SRB_MSGIN); + if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE)) + { + /* Set ATN, in case ATN was clear */ + pSRB->SRBState |= SRB_MSGOUT; + outw(DO_SETATN,ioport+TRM_S1040_SCSI_CONTROL); + } + else + { + /* Clear ATN */ + outw(DO_CLRATN,ioport+TRM_S1040_SCSI_CONTROL); + } + } + else if(pDCB->SyncMode & SYNC_NEGO_ENABLE) + { + /* do sync nego reject */ + outw(DO_CLRATN,ioport+TRM_S1040_SCSI_CONTROL); + if( pSRB->SRBState & SRB_DO_SYNC_NEGO ) + { + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode &= ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + goto re_prog; + } + } + goto min6; + } + else if(message_in_code == MSG_IGNOREWIDE) + { + outl(1,ioport+TRM_S1040_SCSI_COUNTER); + inb(ioport+TRM_S1040_SCSI_FIFO); + goto min6; + } + else + { + /* Restore data pointer message */ + /* Save data pointer message */ + /* Completion message */ + /* NOP message */ + goto min6; + } + } + else /* when extend message in:pSRB->SRBState = SRB_EXTEND_MSGIN */ + { + /* + ** Parsing incomming extented messages + */ + *pSRB->pMsgPtr = message_in_code; + pSRB->MsgCnt++; + pSRB->pMsgPtr++; + #ifdef DC395x_trm_DEBUG1 + printk("pSRB->MsgInBuf[0]=%2x \n ",pSRB->MsgInBuf[0]); + printk("pSRB->MsgInBuf[1]=%2x \n ",pSRB->MsgInBuf[1]); + printk("pSRB->MsgInBuf[2]=%2x \n ",pSRB->MsgInBuf[2]); + printk("pSRB->MsgInBuf[3]=%2x \n ",pSRB->MsgInBuf[3]); + printk("pSRB->MsgInBuf[4]=%2x \n ",pSRB->MsgInBuf[4]); + #endif + if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) && (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) ) + { + /* + ** is QUEUE tag message : + ** + ** byte 0: + ** HEAD QUEUE TAG (20h) + ** ORDERED QUEUE TAG (21h) + ** SIMPLE QUEUE TAG (22h) + ** byte 1: + ** Queue tag (00h - FFh) + */ + if( pSRB->MsgCnt == 2) + { + pSRB->SRBState = 0; + message_in_tag_id = pSRB->MsgInBuf[1]; + pSRB = pDCB->pGoingSRB; + pSRBTemp = pDCB->pGoingLastSRB; + if( pSRB ) + { + for( ;; ) + { + if(pSRB->TagNumber != message_in_tag_id) + { + if( pSRB == pSRBTemp ) + { + goto mingx0; + } + pSRB = pSRB->pNextSRB; + } + else + { + break; + } + } + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + pSRB->SRBState = SRB_ABORT_SENT; + DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); + } + if( !(pSRB->SRBState & SRB_DISCONNECT) ) + { + goto mingx0; + } + pDCB->pActiveSRB = pSRB; + pSRB->SRBState = SRB_DATA_XFER; + } + else + { +mingx0: + pSRB = pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + DC395x_trm_EnableMsgOutAbort2( pACB, pSRB ); + } + } + } + else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgInBuf[2] == 3) && (pSRB->MsgCnt == 4) ) + { + /* + ** is Wide data xfer Extended message : + ** ====================================== + ** WIDE DATA TRANSFER REQUEST + ** ====================================== + ** byte 0 : Extended message (01h) + ** byte 1 : Extended message length (02h) + ** byte 2 : WIDE DATA TRANSFER code (03h) + ** byte 3 : Transfer width exponent + */ + pDCB = pSRB->pSRBDCB; + pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_WIDE_NEGO); + if( (pSRB->MsgInBuf[1] != 2) ) + { + /* Length is wrong, reject it */ + pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); + goto min6; + } + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) + { + /* Do wide negoniation */ + if (pSRB->MsgInBuf[3] > 2) /* > 32 bit */ + { + /* reject_msg: */ + pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); + goto min6; + } + if (pSRB->MsgInBuf[3] == 2) /* == 32 bit */ + { + pSRB->MsgInBuf[3] = 1; /* do 16 bits */ + } + else + { + if (!(pDCB->SyncMode & WIDE_NEGO_DONE)) + { + pSRB->SRBState &= ~(SRB_DO_WIDE_NEGO+SRB_MSGIN); + pDCB->SyncMode |= WIDE_NEGO_DONE; + pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP | WIDE_NEGO_ENABLE ); + if (pSRB->MsgInBuf[3] != 0) + { + /* is Wide data xfer */ + pDCB->SyncPeriod |= WIDE_SYNC; + } + } + } + } + else + { + pSRB->MsgInBuf[3] = 0; + } + pSRB->SRBState |= SRB_MSGOUT; + outw( DO_SETATN,ioport+TRM_S1040_SCSI_CONTROL ); + goto min6; + } + else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgInBuf[2] == 1) && (pSRB->MsgCnt == 5) ) + { + /* + ** is 8bit transfer Extended message : + ** ================================= + ** SYNCHRONOUS DATA TRANSFER REQUEST + ** ================================= + ** byte 0 : Extended message (01h) + ** byte 1 : Extended message length (03) + ** byte 2 : SYNCHRONOUS DATA TRANSFER code (01h) + ** byte 3 : Transfer period factor + ** byte 4 : REQ/ACK offset + */ + pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_SYNC_NEGO); + if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) ) + { /* reject_msg: */ + pSRB->MsgCnt = 1; + pSRB->MsgInBuf[0] = MSG_REJECT_; + outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); + } + else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) ) + { + /*set_async*/ + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode &= ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + goto re_prog; + } + else + { + /* set_sync */ + pDCB = pSRB->pSRBDCB; + pDCB->SyncMode |= SYNC_NEGO_ENABLE+SYNC_NEGO_DONE; + pDCB->MaxNegoPeriod = pSRB->MsgInBuf[3];/* Transfer period factor */ + pDCB->SyncOffset = pSRB->MsgInBuf[4]; /* REQ/ACK offset */ + for (bIndex = 0; bIndex < 7; bIndex++) + { + if (pSRB->MsgInBuf[3] <= dc395x_trm_clock_period[bIndex]) + { + break; + } + } + pDCB->SyncPeriod |= (bIndex | ALT_SYNC); +re_prog: + /* + ** Update period & offset register + */ + outb(pDCB->SyncPeriod, ioport+TRM_S1040_SCSI_SYNC); + outb(pDCB->SyncOffset, ioport+TRM_S1040_SCSI_OFFSET); + DC395x_trm_SetXferRate( pACB, pDCB); + } + } + } +min6: + *pscsi_status = PH_BUS_FREE;/*.. initial phase*/ + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb(SCMD_MSGACCEPT, ioport+TRM_S1040_SCSI_COMMAND); +} +/* +********************************************************************* +** scsiio +** DC395x_trm_MsgInPhase1: one of DC395x_trm_SCSI_phase1[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** if phase =7 +** +** +********************************************************************* +*/ +static void DC395x_trm_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + + WORD ioport; + + + ioport = pACB->IOPortBase; + + outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); + outl(1,ioport+TRM_S1040_SCSI_COUNTER); + if( !(pSRB->SRBState & SRB_MSGIN) ) + { + pSRB->SRBState &= SRB_DISCONNECT; + pSRB->SRBState |= SRB_MSGIN; + } + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb(SCMD_FIFO_IN, ioport+TRM_S1040_SCSI_COMMAND); +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_Nop0: one of DC395x_trm_SCSI_phase1[] ,DC395x_trm_SCSI_phase0[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** if phase =4 ..PH_BUS_FREE +** +** +********************************************************************* +*/ +static void +DC395x_trm_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + +} +/* +********************************************************************* +** scsiio +** DC395x_trm_Nop1: one of DC395x_trm_SCSI_phase0[] ,DC395x_trm_SCSI_phase1[] vectors +** stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** if phase =5 +** +** +********************************************************************* +*/ +static void DC395x_trm_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +{ + +} +/* +********************************************************************* +** scsiio +** DC395x_trm_MsgInPhase0 +** +********************************************************************* +*/ +static void DC395x_trm_SetXferRate( PACB pACB, PDCB pDCB ) +{ + BYTE bval; + WORD cnt, i; + PDCB pDCBTemp; + + /* + ** set all lun device's period , offset + */ + if( !(pDCB->IdentifyMsg & 0x07) ) + { + if( pACB->scan_devices ) + { + CurrSyncOffset = pDCB->SyncOffset; + } + else + { + pDCBTemp = pACB->pLinkDCB; + cnt = pACB->DeviceCnt; + bval = pDCB->TargetID; + for(i=0; iTargetID == bval ) + { + pDCBTemp->SyncPeriod = pDCB->SyncPeriod; + pDCBTemp->SyncOffset = pDCB->SyncOffset; + pDCBTemp->SyncMode = pDCB->SyncMode; + } + pDCBTemp = pDCBTemp->pNextDCB; + } + } + } + return; +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_Interrupt +** +********************************************************************* +*/ +static void DC395x_trm_Disconnect( PACB pACB ) +{ + PDCB pDCB; + PSRB pSRB, pSRBTemp; + WORD ioport, i,count; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_Disconnect..............\n "); + #endif + ioport = pACB->IOPortBase; + pDCB = pACB->pActiveDCB; + if (!pDCB) + { + #ifdef DC395x_trm_DEBUG1 + printk(" Exception Disconnect DCB=NULL..............\n "); + #endif + int j = 400; + while (--j) udelay (1000); + outw((DO_CLRFIFO | DO_HWRESELECT),ioport+TRM_S1040_SCSI_CONTROL); + return; + } + pSRB = pDCB->pActiveSRB; + pACB->pActiveDCB = 0; + + pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ + outw((DO_CLRFIFO | DO_HWRESELECT),ioport+TRM_S1040_SCSI_CONTROL); + if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) + { + #ifdef DC395x_trm_DEBUG1 + printk(" SRB_UNEXPECT_RESEL..............\n "); + #endif + pSRB->SRBState = 0; + DC395x_trm_DoWaitingSRB( pACB ); + } + else if( pSRB->SRBState & SRB_ABORT_SENT ) + { + #ifdef DC395x_trm_DEBUG1 + printk(" SRB_ABORT_SENT..............\n "); + #endif + pDCB->TagMask = 0; + pDCB->DCBFlag = 0; + count= pDCB->GoingSRBCnt; + pDCB->GoingSRBCnt = 0; + pSRB = pDCB->pGoingSRB; + for( i=0; i < count ; i++) + { + pSRBTemp = pSRB->pNextSRB; + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pSRB = pSRBTemp; + } + pDCB->pGoingSRB = 0; + DC395x_trm_DoWaitingSRB( pACB ); + } + else + { + if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) + { + /* + ** Selection time out + ** + ** SRB_START_ + ** SRB_MSGOUT + ** !SRB_DISCONNECT + ** !SRB_COMPLETED + */ + if( !(pACB->scan_devices) ) + { + pSRB->SRBState = SRB_READY; + DC395x_trm_RewaitSRB( pDCB, pSRB); + } + else + { + pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; + goto disc1; + } + } + else if( pSRB->SRBState & SRB_DISCONNECT ) + { + /* + ** SRB_DISCONNECT + */ + DC395x_trm_DoWaitingSRB( pACB ); + } + else if( pSRB->SRBState & SRB_COMPLETED ) + { +disc1: + /* + ** SRB_COMPLETED + */ + if(pDCB->MaxCommand > 1) + { + pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ + } + pDCB->pActiveSRB = 0; + pSRB->SRBState = SRB_FREE; + DC395x_trm_SRBdone( pACB, pDCB, pSRB); + } + } + return; +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_Interrupt +** +********************************************************************* +*/ +static void DC395x_trm_Reselect( PACB pACB ) +{ + PDCB pDCB; + PSRB pSRB; + WORD ioport,RselTarLunId; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_Reselect..............\n "); + #endif + + ioport = pACB->IOPortBase; + pDCB = pACB->pActiveDCB; + if( pDCB ) + { /* Arbitration lost but Reselection win */ + pSRB = pDCB->pActiveSRB; + if( !( pACB->scan_devices ) ) + { + #ifdef DC395x_trm_DEBUG1 + printk("Arbitration lost but Reselection win..............\n "); + #endif + pSRB->SRBState = SRB_READY; + DC395x_trm_RewaitSRB( pDCB, pSRB); + } + } + /* Read Reselected Target Id and LUN */ + RselTarLunId = inw(ioport+TRM_S1040_SCSI_TARGETID) & 0x1FFF; + pDCB = pACB->pLinkDCB; + while( RselTarLunId != *((PWORD) &pDCB->TargetID) ) + { + /* get pDCB of the reselect id */ + pDCB = pDCB->pNextDCB; + if( pDCB == pACB->pLinkDCB ) + { + return; + } + } + + pACB->pActiveDCB = pDCB; + if( pDCB->SyncMode & EN_TAG_QUEUING ) + { + pSRB = pACB->pTmpSRB; + pDCB->pActiveSRB = pSRB; + } + else + { + pSRB = pDCB->pActiveSRB; + if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) ) + { + /* + ** abort command + */ + pSRB= pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); + } + else + { + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + pSRB->SRBState = SRB_ABORT_SENT; + DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); + } + else + { + pSRB->SRBState = SRB_DATA_XFER; + } + } + } + pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ + /* + *********************************************** + ** Program HA ID, target ID, period and offset + *********************************************** + */ + outb((BYTE) RselTarLunId,ioport+TRM_S1040_SCSI_TARGETID); /* target ID */ + outb( pACB->AdaptSCSIID,ioport+TRM_S1040_SCSI_HOSTID); /* host ID */ + outb( pDCB->SyncPeriod,ioport+TRM_S1040_SCSI_SYNC); /* period */ + outb( pDCB->SyncOffset,ioport+TRM_S1040_SCSI_OFFSET); /* offset */ + outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + /* + ** SCSI cammand + */ + outb( SCMD_MSGACCEPT, ioport+TRM_S1040_SCSI_COMMAND); +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_Disconnect +** Complete execution of a SCSI command +** Signal completion to the generic SCSI driver +** +********************************************************************* +*/ +static void DC395x_trm_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + PSRB pSRBTemp; + BYTE tempcnt,status; + PSCSICMD pcmd; + PSCSI_INQDATA ptr; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_SRBdone..............\n "); + #endif + pcmd = pSRB->pcmd; + status = pSRB->TargetStatus; + if(pSRB->SRBFlag & AUTO_REQSENSE) + { + /* + ** target status.......................... + */ + pSRB->SRBFlag &= ~AUTO_REQSENSE; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = SCSI_STAT_CHECKCOND; + if(status == SCSI_STAT_CHECKCOND) + { + pcmd->result = DID_BAD_TARGET << 16; + goto ckc_e; + } + *((PDWORD) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + *((PDWORD) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + pSRB->SRBTotalXferLength = pSRB->Segment1[1]; + pSRB->SegmentX[0].address = pSRB->SgSenseTemp.address; + pSRB->SegmentX[0].length = pSRB->SgSenseTemp.length; + + if( (pSRB->SRBTotalXferLength) && (pSRB->SRBTotalXferLength >= pcmd->underflow) ) + { + pcmd->result |= (DID_OK << 16); + } + else + { + pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | SCSI_STAT_CHECKCOND; + } + goto ckc_e; + } +//*********************************************************** + if( status ) + { + /* + ** target status.......................... + */ + if( status == SCSI_STAT_CHECKCOND) + { + DC395x_trm_RequestSense( pACB, pDCB, pSRB ); + return; + } + else if( status == SCSI_STAT_QUEUEFULL ) + { + tempcnt = (BYTE) pDCB->GoingSRBCnt; + tempcnt--; + pDCB->MaxCommand = tempcnt; + DC395x_trm_RewaitSRB( pDCB, pSRB ); + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + return; + } + else if(status == SCSI_STAT_SEL_TIMEOUT) + { + pSRB->AdaptStatus = H_SEL_TIMEOUT; + pSRB->TargetStatus = 0; + pcmd->result = DID_BAD_TARGET << 16; + } + else + { + pSRB->AdaptStatus = 0; + pcmd->result |= (DID_ERROR << 16) | (DWORD) (pSRB->EndMessage << 8) | (DWORD) status; + } + } + else + { + /* + ** process initiator status.......................... + */ + status = pSRB->AdaptStatus; + if(status & H_OVER_UNDER_RUN) + { + pSRB->TargetStatus = 0; + pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8); + } + else if( pSRB->SRBStatus & PARITY_ERROR) + { + pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8); + } + else /* No error */ + { + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pcmd->result |= (DID_OK << 16); + } + } +ckc_e: + if( pACB->scan_devices ) + { + if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + { + if(pcmd->result != (DID_OK << 16)) /*status word :NO error*/ + { + if( pcmd->result & SCSI_STAT_CHECKCOND ) + { + goto RTN_OK; + } + else + { + pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); + pPrevDCB->pNextDCB = pACB->pLinkDCB; + if( (pcmd->target == pACB->max_id) && ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) ) + { + pACB->scan_devices = 0; + } + } + } + else + { +RTN_OK: + pPrevDCB->pNextDCB = pDCB; + pDCB->pNextDCB = pACB->pLinkDCB; + if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) ) + { + pACB->scan_devices = END_SCAN; + } + } + } + else if( pSRB->CmdBlock[0] == INQUIRY ) + { + if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) ) + { + pACB->scan_devices = 0; + } + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + { + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + } + if( (ptr->DevType & SCSI_DEVTYPE) == SCSI_NODEV ) + { + pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); + pPrevDCB->pNextDCB = pACB->pLinkDCB; + } + else + { + pACB->DeviceCnt++; + pPrevDCB = pDCB; + pACB->pDCB_free = (PDCB) ((DWORD) (pACB->pDCB_free) + sizeof( DC395X_TRM_DCB )); + pDCB->DevType = ptr->DevType & SCSI_DEVTYPE; + if( (pDCB->DevType == TYPE_DISK) || (pDCB->DevType == TYPE_MOD) ) + { + if( ( ((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2) ) && + (ptr->Flags & SCSI_INQ_CMDQUEUE) && + (pDCB->DevMode & NTC_DO_TAG_QUEUING) && + (pDCB->DevMode & NTC_DO_DISCONNECT) ) + { + pDCB->MaxCommand = 32 ; /* there had some thing wrong with pACB->TagMaxNum;*/ + pDCB->SyncMode |= EN_TAG_QUEUING; + pDCB->TagMask = 0; + } + } + }/*bval1 == SCSI_NODEV*/ + }/*pSRB->CmdBlock[0] == INQUIRY*/ + }/* pACB->scan_devices */ + + /* ReleaseSRB( pDCB, pSRB ); */ + if(pSRB == pDCB->pGoingSRB ) + { + /* + ** this SRB is Device's GoingSRB and say that + ** the last SRB had been done + ** you need point this SRB's next SRB to pDCB->pGoingSRB + ** (which SRB next time will be going) + */ + pDCB->pGoingSRB = pSRB->pNextSRB; + } + else + { + /* + ** this SRB had been done you need relink the SRB Q + ** before release this SRB + */ + pSRBTemp = pDCB->pGoingSRB; + while( pSRBTemp->pNextSRB != pSRB ) + { + pSRBTemp = pSRBTemp->pNextSRB; + } + pSRBTemp->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pGoingLastSRB ) + { + pDCB->pGoingLastSRB = pSRBTemp; + } + } + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pDCB->GoingSRBCnt--; + DC395x_trm_DoWaitingSRB( pACB ); + + /* Notify cmd done */ + pcmd->scsi_done( pcmd ); + if( pDCB->QIORBCnt ) + { + DC395x_trm_DoNextCmd( pACB, pDCB ); + } + return; +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_reset +** +********************************************************************* +*/ +static void DC395x_trm_DoingSRB_Done( PACB pACB ) +{ + PDCB pDCB, pDCBTemp; + PSRB pSRBTemp, pSRBTemp2; + WORD cnt, i; + PSCSICMD pcmd; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_DoingSRB_Done..............\n "); + #endif + pDCB = pACB->pLinkDCB; + pDCBTemp = pDCB; + do + { + cnt = pDCBTemp->GoingSRBCnt; + pSRBTemp = pDCBTemp->pGoingSRB; + for( i=0; ipNextSRB; + pcmd = pSRBTemp->pcmd; + pcmd->result = DID_RESET << 16; + /* ReleaseSRB( pDCB, pSRB ); */ + pSRBTemp->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRBTemp; + pcmd->scsi_done( pcmd ); + pSRBTemp = pSRBTemp2; + } + pDCBTemp->GoingSRBCnt = 0;; + pDCBTemp->pGoingSRB = NULL; + pDCBTemp->TagMask = 0; + pDCBTemp = pDCBTemp->pNextDCB; + } + while( pDCBTemp != pDCB ); +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_shutdown DC395x_trm_reset +** +********************************************************************* +*/ +static void DC395x_trm_ResetSCSIBus( PACB pACB ) +{ + WORD ioport; + + pACB->ACBFlag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ + ioport = pACB->IOPortBase; + + outw(DO_RSTSCSI,ioport+TRM_S1040_SCSI_CONTROL); + while (!( inw(ioport+TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_Interrupt +** +********************************************************************* +*/ +static void DC395x_trm_ScsiRstDetect( PACB pACB ) +{ + DWORD wlval; + WORD ioport; + + #ifdef DC395x_trm_DEBUG1 + printk("DC395x_trm_ScsiRstDetect..............\n "); + #endif + sti(); + wlval = jiffies + HZ; + while( jiffies < wlval ); /* delay 1 sec */ + + ioport = pACB->IOPortBase; + + outb(STOPDMAXFER,ioport+TRM_S1040_DMA_CONTROL); + + outw(DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + + if( pACB->ACBFlag & RESET_DEV ) /* RESET_DETECT, RESET_DONE, RESET_DEV */ + { + pACB->ACBFlag |= RESET_DONE; + } + else + { + pACB->ACBFlag |= RESET_DETECT; + DC395x_trm_ResetDevParam( pACB ); + /* DC395x_trm_DoingSRB_Done( pACB ); ???? */ + DC395x_trm_RecoverSRB( pACB ); + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; + DC395x_trm_DoWaitingSRB( pACB ); + } + + return; +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_SRBdone +** +********************************************************************* +*/ +static void DC395x_trm_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + PSCSICMD pcmd; + + pSRB->SRBFlag |= AUTO_REQSENSE; + pSRB->Segment0[0] = *((PDWORD) &(pSRB->CmdBlock[0])); + pSRB->Segment0[1] = *((PDWORD) &(pSRB->CmdBlock[4])); + pSRB->Segment1[0] = (DWORD) ((pSRB->ScsiCmdLen << 8) + pSRB->SRBSGCount); + pSRB->Segment1[1] = pSRB->SRBTotalXferLength; /* ?????????? */ + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + + pcmd = pSRB->pcmd; + /* pSRB->SegmentX : a one entry of S/G list table */ + pSRB->SRBTotalXferLength = sizeof(pcmd->sense_buffer); + pSRB->SgSenseTemp.address = pSRB->SegmentX[0].address; + pSRB->SgSenseTemp.length = pSRB->SegmentX[0].length; + pSRB->SegmentX[0].address = (DWORD) &(pcmd->sense_buffer); + pSRB->SegmentX[0].length = sizeof(pcmd->sense_buffer); + pSRB->SRBSGListPointer = &pSRB->SegmentX[0]; + pSRB->SRBSGCount = 1; + pSRB->SRBSGIndex = 0; + + *((PDWORD) &(pSRB->CmdBlock[0])) = 0x00000003; + pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; + *((PWORD) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer); + pSRB->ScsiCmdLen = 6; + if( DC395x_trm_StartSCSI( pACB, pDCB, pSRB ) ) + { + /* + ** If DC395x_trm_StartSCSI return 1 : + ** current interrupt status is interrupt disreenable + ** It's said that SCSI processor has more one SRB need to do + */ + DC395x_trm_RewaitSRB( pDCB, pSRB ); + } + +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_MsgInPhase0 DC395x_trm_EnableMsgOutAbort1 +** +********************************************************************* +*/ +static void DC395x_trm_EnableMsgOutAbort2( PACB pACB, PSRB pSRB ) +{ + WORD ioport; + + ioport = pACB->IOPortBase; + pSRB->MsgCnt = 1; + outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_Reselect DC395x_trm_Interrupt DC395x_trm_MsgInPhase0 +** +********************************************************************* +*/ +static void DC395x_trm_EnableMsgOutAbort1( PACB pACB, PSRB pSRB ) +{ + pSRB->MsgOutBuf[0] = MSG_ABORT; + DC395x_trm_EnableMsgOutAbort2( pACB, pSRB ); +} + +/* +********************************************************************** +** DC395x_trm_queue_command +** +** Function : static void DC395x_trm_initDCB +** Purpose : initialize the internal structures for a given DCB +** Inputs : cmd - pointer to this scsi cmd request block structure +** +********************************************************************** +*/ +void DC395x_trm_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) +{ + PNVRAMTYPE pEEpromBuf; + BYTE bval,PeriodIndex; + WORD index; + + if( pACB->DeviceCnt == 0 ) + { + pACB->pLinkDCB = pDCB; + /* + ** RunRobin impersonate the role + ** that let each device had good proportion + ** about SCSI command proceeding + */ + pACB->pDCBRunRobin = pDCB; + pDCB->pNextDCB = pDCB; + pPrevDCB = pDCB; + } + else + { + pPrevDCB->pNextDCB = pDCB; + } + /* $$$$$$$ */ + pDCB->pDCBACB = pACB; + pDCB->QIORBCnt = 0; + pDCB->TargetID = cmd->target; + pDCB->TargetLUN = cmd->lun; + /* $$$$$$$ */ + pDCB->pWaitingSRB = NULL; + pDCB->pGoingSRB = NULL; + pDCB->GoingSRBCnt = 0; + pDCB->pActiveSRB = NULL; + /* $$$$$$$ */ + pDCB->TagMask = 0; + pDCB->DCBFlag = 0; + pDCB->MaxCommand = 1; + pDCB->AdaptIndex = pACB->AdapterIndex; + /* $$$$$$$ */ + index = pACB->AdapterIndex; + pEEpromBuf = &eepromBuf[index]; + pDCB->DevMode = pEEpromBuf->NvramTarget[cmd->target].NvmTarCfg0; + pDCB->AdpMode = pEEpromBuf->NvramChannelCfg; + pDCB->SyncMode = 0; + /* $$$$$$$ */ + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + PeriodIndex = pEEpromBuf->NvramTarget[cmd->target].NvmTarPeriod & 0x07; + pDCB->MaxNegoPeriod = dc395x_trm_clock_period[ PeriodIndex ] ; + + if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && (pACB->Config & HCC_WIDE_CARD)) + { + pDCB->SyncMode |= WIDE_NEGO_ENABLE; + } + if (pDCB->DevMode & NTC_DO_SYNC_NEGO) + { + if( !(cmd->lun) || CurrSyncOffset ) + { + pDCB->SyncMode |= SYNC_NEGO_ENABLE; + } + } + /* $$$$$$$ */ + if( pDCB->DevMode & NTC_DO_DISCONNECT ) + { + bval = 0xC0; + } + else + { + bval = 0x80; + } + bval |= cmd->lun; + pDCB->IdentifyMsg = bval; + /* $$$$$$$ */ +} + + +/* +********************************************************************** +** DC395x_trm_linkSRB +** DC395x_trm_initACB +** +** Function : static void DC395x_trm_initSRB +** Purpose : initialize the internal structures for a given SRB +** Inputs : pSRBTemp - pointer to this scsi request block structure +** +********************************************************************** +*/ +void DC395x_trm_initSRB( PSRB pSRB ) +{ + + #ifndef VERSION_ELF_1_2_13 + pSRB->PhysSRB = virt_to_bus( pSRB ); + #else + pSRB->PhysSRB = (DWORD) pSRB; + #endif +} + +/* +********************************************************************* +** scsiio +** DC395x_trm_initACB +** +********************************************************************* +*/ +void DC395x_trm_linkSRB( PACB pACB ) +{ + WORD count, i; + + count = pACB->SRBCount; + + for( i=0; i< count; i++) + { + if( i != count - 1) + { + /* + ** link all SRB + */ + pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; + } + else + { + /* + ** load NULL to NextSRB of the last SRB + */ + pACB->SRB_array[i].pNextSRB = NULL; + } + /* + ** convert and save physical address of SRB to pSRB->PhysSRB + */ + DC395x_trm_initSRB( (PSRB) &pACB->SRB_array[i] ); + } +} + + +/* +************************************************************************ +** DC395x_trm_init +** +** Function : static void DC395x_trm_initACB +** Purpose : initialize the internal structures for a given SCSI host +** Inputs : psh - pointer to this host adapter's structure +** +************************************************************************ +*/ +void DC395x_trm_initACB( PSH psh, DWORD io_port, BYTE Irq, WORD index ) +{ + PNVRAMTYPE pEEpromBuf; + PACB pACB; + WORD i; + + pEEpromBuf = &eepromBuf[index]; + psh->can_queue = MAX_CMD_QUEUE; + psh->cmd_per_lun = MAX_CMD_PER_LUN; + psh->this_id = (int) pEEpromBuf->NvramScsiId; + 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 = 16; + #ifdef CONFIG_SCSI_MULTI_LUN + if( pEEpromBuf->NvramChannelCfg & NAC_SCANLUN ) + psh->max_lun = 8; + else + #endif + psh->max_lun = 1; +#endif + pACB->max_id = 15; + if( pACB->max_id == pEEpromBuf->NvramScsiId ) + pACB->max_id--; + #ifdef CONFIG_SCSI_MULTI_LUN + if( pEEpromBuf->NvramChannelCfg & NAC_SCANLUN ) + pACB->max_lun = 7; + else + #endif + pACB->max_lun = 0; + /* + ******************************** + */ + pACB->pScsiHost = psh; + pACB->IOPortBase = (WORD) 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 = pEEpromBuf->NvramScsiId; + pACB->HostID_Bit = (1 << pACB->AdaptSCSIID); + pACB->AdaptSCSILUN = 0; + pACB->DeviceCnt = 0; + pACB->IRQLevel = Irq; + pACB->TagMaxNum = pEEpromBuf->NvramMaxTag << 2; + pACB->ACBFlag = 0; /* RESET_DETECT, RESET_DONE, RESET_DEV */ + pACB->scan_devices = 1; + pACB->Gmode2 = pEEpromBuf->NvramChannelCfg; + if( pEEpromBuf->NvramChannelCfg & NAC_SCANLUN ) + { + pACB->LUNchk = 1; + } + /* + ******************************** + */ + pACB->pDCB_free = &pACB->DCB_array[0]; + /* + ** link all device's SRB Q of this adapter + */ + DC395x_trm_linkSRB( pACB ); + /* + ** temp SRB for Q tag used or abord command used + */ + pACB->pTmpSRB = &pACB->TmpSRB; + /* + ** convert and save physical address of SRB to pSRB->PhysSRB + */ + DC395x_trm_initSRB( pACB->pTmpSRB ); + for(i=0; iDCBmap[i] = 0; + } +} + + +/* +********************************************************************** +** +** DC395x_trm_init +** +** Function : static int DC395x_trm_initAdapter +** Purpose : initialize the SCSI chip ctrl registers +** Inputs : psh - pointer to this host adapter's structure +** +********************************************************************** +*/ +int DC395x_trm_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index ) +{ + PNVRAMTYPE pEEpromBuf; + WORD ioport,wval; + BYTE bval; + PACB pACB, pTempACB; + WORD used_irq = 0; + + pEEpromBuf = &eepromBuf[index]; + pTempACB = pACB_start; + if( pTempACB != NULL ) + { + for ( ; (pTempACB != (PACB) -1) ; ) + { + if( pTempACB->IRQLevel == Irq ) + { + used_irq = 1; + break; + } + else + { + pTempACB = pTempACB->pNextACB; + } + } + } + + if( !used_irq ) + { + #ifdef VERSION_ELF_1_2_13 + if( request_irq(Irq, DC395x_trm_Interrupt, SA_INTERRUPT, "DC395x")) + #else + if( request_irq(Irq, DC395x_trm_Interrupt, SA_INTERRUPT | SA_SHIRQ, "DC395x", NULL)) + #endif + { + printk("DC395x: register IRQ error!\n"); + return( -1 ); + } + } + /* %%%%%%%%%%%%% */ + request_region(io_port,psh->n_io_port,"DC395x"); + /* %%%%%%%%%%%%% */ + ioport = (WORD) io_port; + pACB = (PACB) psh->hostdata; + /* selection timeout = 250 ms */ + outb(SEL_TIMEOUT,ioport+TRM_S1040_SCSI_TIMEOUT); + /* Mask all the interrupt */ + outb(0x00,ioport+TRM_S1040_DMA_INTEN); + outb(0x00,ioport+TRM_S1040_SCSI_INTEN); + /* Reset SCSI module */ + outw(DO_RSTMODULE,ioport+TRM_S1040_SCSI_CONTROL); + /* program configuration 0 */ + pACB->Config = HCC_AUTOTERM | HCC_PARITY; + if ( inb(ioport+TRM_S1040_GEN_STATUS) & WIDESCSI ) + { + pACB->Config |= HCC_WIDE_CARD; + } + if (pEEpromBuf->NvramChannelCfg & NAC_POWERON_SCSI_RESET) + { + pACB->Config |= HCC_SCSI_RESET; + } + if (pACB->Config & HCC_PARITY) + { + bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK; + } + else + { + bval = PHASELATCH | INITIATOR | BLOCKRST ; + } + outb(bval,ioport+TRM_S1040_SCSI_CONFIG0); + /* program configuration 1 */ + outb(0x13,ioport+TRM_S1040_SCSI_CONFIG1); + /* program Host ID */ + bval = pEEpromBuf->NvramScsiId; + outb(bval,ioport+TRM_S1040_SCSI_HOSTID); + /* set ansynchronous transfer */ + outb(0x00,ioport+TRM_S1040_SCSI_OFFSET); + /* Trun LED control off*/ + wval = inw(ioport+TRM_S1040_GEN_CONTROL) & 0x7F; + outw(wval,ioport+TRM_S1040_GEN_CONTROL); + /* DMA config */ + wval = inw(ioport+TRM_S1040_DMA_CONFIG) | DMA_ENHANCE ; + outw(wval,ioport+TRM_S1040_DMA_CONFIG); + /* Clear pending interrupt status*/ + inb(ioport+TRM_S1040_SCSI_INTSTATUS); + /* Enable SCSI interrupt */ + outb(0x7F,ioport+TRM_S1040_SCSI_INTEN); + outb(EN_SCSIINTR,ioport+TRM_S1040_DMA_INTEN); + return(0); +} +/* +************************************************************************ +** DC395x_trm_check_eeprom +** +**---------------------------------------------------------------------- +** Function : TRM_S1040_write_all +** Description : write pEEpromBuf 128 bytes to seeprom +** Input : scsiIOPort - chip's base address +** Output : none +************************************************************************ +*/ +static void TRM_S1040_write_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort) +{ + BYTE *bpEeprom = (BYTE *) pEEpromBuf; + BYTE bAddr; + + /* Enable SEEPROM */ + outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) | EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL); + /* + ** Write enable + */ + TRM_S1040_write_cmd(scsiIOPort, 0x04, 0xFF); + outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM ); + TRM_S1040_wait_30us(scsiIOPort); + for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++) + { + TRM_S1040_set_data(scsiIOPort, bAddr, *bpEeprom); + } + /* + ** Write disable + */ + TRM_S1040_write_cmd(scsiIOPort, 0x04, 0x00); + outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM ); + TRM_S1040_wait_30us(scsiIOPort); + /* Disable SEEPROM */ + outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) & ~EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL); + return; +} +/* +*********************************************************************** +** TRM_S1040_write_all +** +**--------------------------------------------------------------------- +** Function : TRM_S1040_set_data +** Description : write one byte to seeprom +** Input : scsiIOPort - chip's base address +** bAddr - address of SEEPROM +** bData - data of SEEPROM +** Output : none +*********************************************************************** +*/ +static void TRM_S1040_set_data(WORD scsiIOPort, BYTE bAddr, BYTE bData) +{ + int i; + BYTE bSendData; + /* + ** Send write command & address + */ + TRM_S1040_write_cmd(scsiIOPort, 0x05, bAddr); + /* + ** Write data + */ + for (i = 0; i < 8; i++, bData <<= 1) + { + bSendData = NVR_SELECT; + if (bData & 0x80) /* Start from bit 7 */ + { + bSendData |= NVR_BITOUT; + } + outb( bSendData , scsiIOPort+TRM_S1040_GEN_NVRAM ); + TRM_S1040_wait_30us(scsiIOPort); + outb( (bSendData | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + } + outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + /* + ** Disable chip select + */ + outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + outb( NVR_SELECT ,scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + /* + ** Wait for write ready + */ + while (1) + { + outb( (NVR_SELECT | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + if (inb(scsiIOPort+TRM_S1040_GEN_NVRAM) & NVR_BITIN) + { + break; + } + } + /* + ** Disable chip select + */ + outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM); + return; +} +/* +************************************************************************ +** DC395x_trm_check_eeprom +** +**---------------------------------------------------------------------- +** Function : TRM_S1040_read_all +** Description : read seeprom 128 bytes to pEEpromBuf +** Input : pEEpromBuf,scsiIOPort - chip's base address +** Output : none +************************************************************************ +*/ +static void TRM_S1040_read_all(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort) +{ + BYTE *bpEeprom = (BYTE *) pEEpromBuf; + BYTE bAddr; + + /* + ** Enable SEEPROM + */ + outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) | EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL); + for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++) + { + *bpEeprom = TRM_S1040_get_data(scsiIOPort, bAddr); + } + /* + ** Disable SEEPROM + */ + outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) & ~EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL ); + return; +} +/* +************************************************************************ +** TRM_S1040_read_all +** +**---------------------------------------------------------------------- +** Function : TRM_S1040_get_data +** Description : read one byte from seeprom +** Input : scsiIOPort - chip's base address +** bAddr - address of SEEPROM +** Output : bData - data of SEEPROM +************************************************************************ +*/ +static BYTE TRM_S1040_get_data(WORD scsiIOPort, BYTE bAddr) +{ + int i; + BYTE bReadData, bData = 0; + /* + ** Send read command & address + */ + TRM_S1040_write_cmd(scsiIOPort, 0x06, bAddr); + + for (i = 0; i < 8; i++) + { /* + ** Read data + */ + outb( (NVR_SELECT | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM); + /* + ** Get data bit while falling edge + */ + bReadData = inb(scsiIOPort+TRM_S1040_GEN_NVRAM); + bData <<= 1; + if (bReadData & NVR_BITIN) + { + bData |= 1; + } + TRM_S1040_wait_30us(scsiIOPort); + } + /* + ** Disable chip select + */ + outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM); + return (bData); +} +/* +************************************************************************ +** +** Function : TRM_S1040_wait_30us +** Description : wait 30 us +** Input : scsiIOPort - chip's base address +** Output : none +************************************************************************ +*/ +void TRM_S1040_wait_30us(WORD scsiIOPort) +{ + /* ScsiPortStallExecution(30); wait 30 us */ + outb( 5 , scsiIOPort+TRM_S1040_GEN_TIMER); + while (!(inb(scsiIOPort+TRM_S1040_GEN_STATUS) & GTIMEOUT)); + return; +} +/* +************************************************************************ +** TRM_S1040_get_data TRM_S1040_write_all +** TRM_S1040_set_data +**---------------------------------------------------------------------- +** Function : TRM_S1040_write_cmd +** Description : write SB and Op Code into seeprom +** Input : scsiIOPort ... chip's base address +** bCmd ... SB + Op Code +** bAddr ... address of SEEPROM +** Output : none +************************************************************************ +*/ +static void TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr) +{ + int i; + BYTE bSendData; + + + for (i = 0; i < 3; i++, bCmd <<= 1) + { /* + ** Program SB+OP code + */ + bSendData = NVR_SELECT; + if (bCmd & 0x04) /* Start from bit 2 */ + { + bSendData |= NVR_BITOUT; + } + outb( bSendData , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + outb( (bSendData | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + } + + for (i = 0; i < 7; i++, bAddr <<= 1) + { /* + ** Program address + */ + bSendData = NVR_SELECT; + if (bAddr & 0x40) /* Start from bit 6 */ + { + bSendData |= NVR_BITOUT; + } + outb( bSendData , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + outb( (bSendData | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); + } + outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM); + TRM_S1040_wait_30us(scsiIOPort); +} + +/* +************************************************************************ +** DC395x_trm_init +** +**---------------------------------------------------------------------- +** Function : DC395x_trm_check_eeprom +** Description : read seeprom 128 bytes to pEEpromBuf and check +** checksum. If it is worong, updated with default value +** Input : eeprom,scsiIOPort - chip's base address +** Output : none +************************************************************************ +*/ +static void DC395x_trm_check_eeprom(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort) +{ + WORD *wpEeprom = (WORD *) pEEpromBuf; + WORD wAddr, wCheckSum; + DWORD dAddr, *dpEeprom; + + TRM_S1040_read_all(pEEpromBuf,scsiIOPort); + wCheckSum = 0; + for (wAddr = 0, wpEeprom = (WORD *) pEEpromBuf; wAddr < 64; wAddr++, wpEeprom++) + { + wCheckSum += *wpEeprom; + } + if (wCheckSum != 0x1234) + { /* + ** Checksum error, load default + */ + pEEpromBuf->NvramSubVendorID[0] = (BYTE) PCI_Vendor_ID_TEKRAM; + pEEpromBuf->NvramSubVendorID[1] = (BYTE) (PCI_Vendor_ID_TEKRAM >> 8); + pEEpromBuf->NvramSubSysID[0] = (BYTE) PCI_Device_ID_TRM_S1040; + pEEpromBuf->NvramSubSysID[1] = (BYTE) (PCI_Device_ID_TRM_S1040 >> 8); + pEEpromBuf->NvramSubClass = 0x00; + pEEpromBuf->NvramVendorID[0] = (BYTE) PCI_Vendor_ID_TEKRAM; + pEEpromBuf->NvramVendorID[1] = (BYTE) (PCI_Vendor_ID_TEKRAM >> 8); + pEEpromBuf->NvramDeviceID[0] = (BYTE) PCI_Device_ID_TRM_S1040; + pEEpromBuf->NvramDeviceID[1] = (BYTE) (PCI_Device_ID_TRM_S1040 >> 8); + pEEpromBuf->NvramReserved = 0x00; + + for (dAddr = 0, dpEeprom = (DWORD *) pEEpromBuf->NvramTarget; dAddr < 16; dAddr++, dpEeprom++) + { + *dpEeprom = 0x00000077;/* NvmTarCfg3,NvmTarCfg2,NvmTarPeriod,NvmTarCfg0 */ + } + + *dpEeprom++ = 0x04000F07;/* NvramMaxTag,NvramDelayTime,NvramChannelCfg,NvramScsiId */ + *dpEeprom++ = 0x00000015;/* NvramReserved1,NvramBootLun ,NvramBootTarget,NvramReserved0 */ + for (dAddr = 0; dAddr < 12; dAddr++, dpEeprom++) + { + *dpEeprom = 0x00; + } + pEEpromBuf->NvramCheckSum = 0x00; + for (wAddr = 0, wCheckSum = 0, wpEeprom = (WORD *) pEEpromBuf; wAddr < 63; wAddr++, wpEeprom++) + { + wCheckSum += *wpEeprom; + } + *wpEeprom = 0x1234 - wCheckSum; + TRM_S1040_write_all(pEEpromBuf,scsiIOPort); + } + return; +} +/* +********************************************************************** +** +** DC395x_trm_detect +** +** Function : static int DC395x_trm_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 DC395x_trm_init(PSHT psht, DWORD io_port, BYTE Irq, WORD index) +{ + PSH psh; + PACB pACB; + + //$$$$$$$$$$$$$$$$$$$$$$$ EEPROM CHECKSUM $$$$$$$$$$$$$$$$$$$$$$$$$ + DC395x_trm_check_eeprom( &eepromBuf[index], (WORD) io_port); + //$$$$$$$$$$$ MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK $$$$$$$$$$$$ + psh = scsi_register( psht, sizeof(DC395X_TRM_ACB) ); + if( !psh ) + { + printk("DC395x_trm_init : pSH scsi_register ERROR\n"); + + return( -1 ); + } + if( !pSH_start ) + { + pSH_start = psh; + pSH_current = psh; + } + else + { + pSH_current->next = psh; + pSH_current = psh; + } + //$$$$$$$$ INITIAL ADAPTER CONTROL BLOCK $$$$$$$$$$$$ + DC395x_trm_initACB( psh,io_port, Irq, index ); + //$$$$$$$$$$$$$$$$ INITIAL ADAPTER $$$$$$$$$$$$$$$$ + if( !DC395x_trm_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; + } + return( 0 ); + } + else + { + printk("DC395x_trm_initAdapter initial ERROR\n"); + + pSH_start = NULL; + scsi_unregister( psh ); + return( -1 ); + } +} + + +/* +********************************************************************** +** +** SCSI driver entry of Linux +** +** Function : int DC395x_trm_detect(Scsi_Host_Template *psht) +** Purpose : detects and initializes TRM S1040 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 DC395x_trm_detect(Scsi_Host_Template *psht) +{ + BYTE pci_bus, pci_device_fn, irq; +#ifndef VERSION_ELF_1_2_13 + UINT io_port, ram_base; +#else + DWORD io_port, ram_base; +#endif + WORD i; + int error = 0; + WORD chip_ID = 0; + WORD Temp_adaptCnt = 0; /* Number of boards detected */ + WORD pci_index0 = 0; /* Device index to PCI BIOS calls */ + DWORD flags; + + DC395_LOCK_IO; +#ifndef VERSION_ELF_1_2_13 + psht->proc_dir = &proc_scsi_dc395x; +#endif + + InitialTime = 1; //..flag of do....DC395x_trm_ResetSCSIBus2( pACB ) + + pACB_start = NULL; + /* search DC395x SCSI adapter in each slot */ + if ( pcibios_present() ) + { //#define MAX_SUPPORTED_ADAPTERS 4 + for (i = 0; i < MAX_SUPPORTED_ADAPTERS; ++i) + { + if( !pcibios_find_device( PCI_Vendor_ID_TEKRAM,PCI_Device_ID_TRM_S1040,pci_index0, &pci_bus, &pci_device_fn) ) + { + chip_ID = PCI_Device_ID_TRM_S1040; + pci_index0++; + } + + if( chip_ID ) + { /* get adapter io_port ,irq */ + 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("DC395x_trm_detect: reading configuration registers error!\n"); + InitialTime = 0; + DC395_UNLOCK_IO; + return( 0 ); + } + //PCI_BASE_ADDRESS_0 + pcibios_read_config_dword(pci_bus, pci_device_fn,PCI_BASE_ADDRESS_0, &io_port); + + (WORD) io_port = (WORD) io_port & 0xFFFE; + if( !DC395x_trm_init(psht, io_port, irq, i) ) + { + Temp_adaptCnt++; + } + chip_ID = 0; + } + else + { + break; + } + } + } + InitialTime = 0; + adapterCnt = Temp_adaptCnt;//......static WORD adapterCnt = 0; + DC395_UNLOCK_IO; + return( Temp_adaptCnt ); +} + + +#ifndef VERSION_ELF_1_2_13 + +/* +******************************************************************* +** +** Function: DC395x_trm_set_info() +** Purpose: Set adapter info (!) +** Not yet implemented +** +******************************************************************* +*/ + +int DC395x_trm_set_info(char *buffer, int length, struct Scsi_Host *shpnt) +{ + return(-ENOSYS); /* Currently this is a no-op */ +} + +/* +******************************************************************* +** Function: DC395x_trm_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 +** +** return value: length of info in buffer +** +******************************************************************* +*/ + +/* 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 DC395x_trm_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; + DWORD 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(DC395x_trm_set_info(buffer, length, shpnt)); + } + + SPRINTF(DC395_BANNER " PCI SCSI Host Adadpter, "); + SPRINTF("Driver Version " DC395_VERSION "\n"); + + DC395_LOCK_IO; + + SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); + SPRINTF("DC395U/UW/F DC315/U 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 MaxNegoPeriod SyncSpeed SyncOffs\n"); + + dcbpnt = acbpnt->pLinkDCB; + for (dev = 0; dev < acbpnt->DeviceCnt; dev++) + { + SPRINTF("%02i %02i %02i ", dev, dcbpnt->TargetID, dcbpnt->TargetLUN); + YESNO(dcbpnt->DevMode & NTC_DO_PARITY_CHK); + YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE); + YESNO(dcbpnt->DevMode & NTC_DO_DISCONNECT); + YESNO(dcbpnt->DevMode & NTC_DO_SEND_START); + YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING); + SPRINTF(" %03i ns ", (dcbpnt->MaxNegoPeriod) << 2); + if (dcbpnt->SyncOffset & 0x0f) + { + spd = 1000/(dcbpnt->MaxNegoPeriod <<2); + spd1 = 1000%(dcbpnt->MaxNegoPeriod <<2); + spd1 = (spd1 * 10)/(dcbpnt->MaxNegoPeriod <<2); + SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f)); + } + else + { + SPRINTF("\n"); + } + /* Add more info ...*/ + dcbpnt = dcbpnt->pNextDCB; + } + + DC395_UNLOCK_IO; + *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 DC395x_trm_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 DC395x_trm_shutdown (struct Scsi_Host *host) + { + BYTE bval; + WORD ioport; + PACB pACB; + + pACB = (PACB)(host->hostdata); + ioport = (unsigned int) pACB->IOPortBase; + + /* pACB->soft_reset(host); */ + /* + ** disable interrupt + */ + bval = 0x00 ; + outb(bval,ioport+TRM_S1040_DMA_INTEN); + outb(bval,ioport+TRM_S1040_SCSI_INTEN); + + DC395x_trm_ResetSCSIBus( pACB ); + + return( 0 ); + } + + /* + ********************************************************************* + ** + ** + ** + ********************************************************************* + */ + int DC395x_trm_release(struct Scsi_Host *host) + { + int irq_count; + struct Scsi_Host *tmp; + DWORD flags; + + DC395_LOCK_IO; + + DC395x_trm_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) + { + #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); + + DC395_UNLOCK_IO; + return( 1 ); + } + + Scsi_Host_Template driver_template = DC395x_TRMS1040; + #include "scsi_module.c" +#endif /* def MODULE */ +