📄 tmscsim.c
字号:
/*********************************************************************** * FILE NAME : TMSCSIM.C * * BY : C.L. Huang, ching@tekram.com.tw * * Description: Device Driver for Tekram DC-390(T) PCI SCSI * * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************//* Minor enhancements and bugfixes by * * Kurt Garloff <K.Garloff@ping.de> * ***********************************************************************//* HISTORY: * * * * REV# DATE NAME DESCRIPTION * * 1.00 04/24/96 CLH First release * * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable * * Device, scan all LUN. Support Pre2.0.10 * * 1.02 06/18/96 CLH Fixed bug of Command timeout ... * * 1.03 09/25/96 KG Added tmscsim_proc_info() * * 1.04 10/11/96 CLH Updating for support KV 2.0.x * * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)* * 1.06 10/25/96 KG Fixed module support * * 1.07 11/09/96 KG Fixed tmscsim_proc_info() * * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() * * 1.09 11/30/96 KG Added register the allocated IO space * * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset * * pending interrupt in DC390_detect() * * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater * * than 1GB * ***********************************************************************/#define DC390_DEBUG#define SCSI_MALLOC#ifdef MODULE#include <linux/module.h>#endif#include <asm/dma.h>#include <asm/io.h>#include <asm/system.h>#include <linux/delay.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/bios32.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/config.h>#include <linux/version.h>#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */#include "../block/blk.h"#else#include <linux/blk.h>#endif#include "scsi.h"#include "hosts.h"#include "tmscsim.h"#include "constants.h"#include "sd.h"#include <linux/stat.h>#include "dc390.h"#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI#ifndef VERSION_ELF_1_2_13struct proc_dir_entry proc_scsi_tmscsim ={ PROC_SCSI_DC390T, 7 ,"tmscsim", S_IFDIR | S_IRUGO | S_IXUGO, 2 };#endifstatic USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);static void SetXferRate( PACB pACB, PDCB pDCB );static void DC390_Disconnect( PACB pACB );static void DC390_Reselect( PACB pACB );static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );static void DoingSRB_Done( PACB pACB );static void DC390_ScsiRstDetect( PACB pACB );static void DC390_ResetSCSIBus( PACB pACB );static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );static void EnableMsgOut2( PACB pACB, PSRB pSRB );static void EnableMsgOut( PACB pACB, PSRB pSRB );static void DC390_InvalidCmd( PACB pACB );int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );#ifdef MODULEstatic int DC390_release(struct Scsi_Host *host);static int DC390_shutdown (struct Scsi_Host *host);#endifstatic PSHT pSHT_start = NULL;static PSH pSH_start = NULL;static PSH pSH_current = NULL;static PACB pACB_start= NULL;static PACB pACB_current = NULL;static PDCB pPrevDCB = NULL;static USHORT adapterCnt = 0;static USHORT InitialTime = 0;static USHORT CurrSyncOffset = 0;static ULONG mech1addr;static UCHAR mech2bus, mech2Agent, mech2CfgSPenR;static PVOID DC390_phase0[]={ DC390_DataOut_0, DC390_DataIn_0, DC390_Command_0, DC390_Status_0, DC390_Nop_0, DC390_Nop_0, DC390_MsgOut_0, DC390_MsgIn_0, DC390_Nop_1 };static PVOID DC390_phase1[]={ DC390_DataOutPhase, DC390_DataInPhase, DC390_CommandPhase, DC390_StatusPhase, DC390_Nop_0, DC390_Nop_0, DC390_MsgOutPhase, DC390_MsgInPhase, DC390_Nop_1, };UCHAR eepromBuf[MAX_ADAPTER_NUM][128];UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};UCHAR baddevname1[2][28] ={ "SEAGATE ST3390N 9546", "HP C3323-300 4269"};#define BADDEVCNT 2/*********************************************************************** * * * **********************************************************************/static voidQLinkcmd( PSCSICMD cmd, PDCB pDCB ){ ULONG flags; PSCSICMD pcmd; save_flags(flags); cli(); if( !pDCB->QIORBCnt ) { pDCB->pQIORBhead = cmd; pDCB->pQIORBtail = cmd; pDCB->QIORBCnt++; cmd->next = NULL; } else { pcmd = pDCB->pQIORBtail; pcmd->next = cmd; pDCB->pQIORBtail = cmd; pDCB->QIORBCnt++; cmd->next = NULL; } restore_flags(flags);}static PSCSICMDGetcmd( PDCB pDCB ){ ULONG flags; PSCSICMD pcmd; save_flags(flags); cli(); pcmd = pDCB->pQIORBhead; pDCB->pQIORBhead = pcmd->next; pcmd->next = NULL; pDCB->QIORBCnt--; restore_flags(flags); return( pcmd );}static PSRBGetSRB( PACB pACB ){ ULONG flags; PSRB pSRB; save_flags(flags); cli(); pSRB = pACB->pFreeSRB; if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } restore_flags(flags); return( pSRB );}static voidRewaitSRB0( PDCB pDCB, PSRB pSRB ){ PSRB psrb1; ULONG flags; save_flags(flags); cli(); if( (psrb1 = pDCB->pWaitingSRB) ) { pSRB->pNextSRB = psrb1; pDCB->pWaitingSRB = pSRB; } else { pSRB->pNextSRB = NULL; pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; } restore_flags(flags);}static voidRewaitSRB( PDCB pDCB, PSRB pSRB ){ PSRB psrb1; ULONG flags; UCHAR bval; save_flags(flags); cli(); pDCB->GoingSRBCnt--; psrb1 = pDCB->pGoingSRB; if( pSRB == psrb1 ) { pDCB->pGoingSRB = psrb1->pNextSRB; } else { while( pSRB != psrb1->pNextSRB ) psrb1 = psrb1->pNextSRB; psrb1->pNextSRB = pSRB->pNextSRB; if( pSRB == pDCB->pGoingLast ) pDCB->pGoingLast = psrb1; } if( (psrb1 = pDCB->pWaitingSRB) ) { pSRB->pNextSRB = psrb1; pDCB->pWaitingSRB = pSRB; } else { pSRB->pNextSRB = NULL; pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; } bval = pSRB->TagNumber; pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ restore_flags(flags);}static voidDoWaitingSRB( PACB pACB ){ ULONG flags; PDCB ptr, ptr1; PSRB pSRB; save_flags(flags); cli(); if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) { ptr = pACB->pDCBRunRobin; if( !ptr ) { ptr = pACB->pLinkDCB; pACB->pDCBRunRobin = ptr; } ptr1 = ptr; for( ;ptr1; ) { pACB->pDCBRunRobin = ptr1->pNextDCB; if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || !( pSRB = ptr1->pWaitingSRB ) ) { if(pACB->pDCBRunRobin == ptr) break; ptr1 = ptr1->pNextDCB; } else { if( !DC390_StartSCSI(pACB, ptr1, pSRB) ) { ptr1->GoingSRBCnt++; if( ptr1->pWaitLast == pSRB ) { ptr1->pWaitingSRB = NULL; ptr1->pWaitLast = NULL; } else { ptr1->pWaitingSRB = pSRB->pNextSRB; } pSRB->pNextSRB = NULL; if( ptr1->pGoingSRB ) ptr1->pGoingLast->pNextSRB = pSRB; else ptr1->pGoingSRB = pSRB; ptr1->pGoingLast = pSRB; } break; } } } restore_flags(flags); return;}static voidSRBwaiting( PDCB pDCB, PSRB pSRB){ if( pDCB->pWaitingSRB ) { pDCB->pWaitLast->pNextSRB = pSRB; pDCB->pWaitLast = pSRB; pSRB->pNextSRB = NULL; } else { pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; }}static voidSendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ){ ULONG flags; PDCB pDCB; save_flags(flags); cli(); pDCB = pSRB->pSRBDCB; if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { SRBwaiting(pDCB, pSRB); goto SND_EXIT; } if( pDCB->pWaitingSRB ) { SRBwaiting(pDCB, pSRB);/* pSRB = GetWaitingSRB(pDCB); */ pSRB = pDCB->pWaitingSRB; pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } if( !DC390_StartSCSI(pACB, pDCB, pSRB) ) { pDCB->GoingSRBCnt++; if( pDCB->pGoingSRB ) { pDCB->pGoingLast->pNextSRB = pSRB; pDCB->pGoingLast = pSRB; } else { pDCB->pGoingSRB = pSRB; pDCB->pGoingLast = pSRB; } } else RewaitSRB0( pDCB, pSRB );SND_EXIT: restore_flags(flags); return;}/*********************************************************************** * Function : static int DC390_queue_command (Scsi_Cmnd *cmd, * void (*done)(Scsi_Cmnd *)) * * Purpose : enqueues a SCSI command * * Inputs : cmd - SCSI command, done - function called on completion, with * a pointer to the command descriptor. * * Returns : 0 * ***********************************************************************/intDC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)){ USHORT ioport, i; Scsi_Cmnd *pcmd; struct Scsi_Host *psh; PACB pACB; PDCB pDCB; PSRB pSRB; ULONG flags; PUCHAR ptr,ptr1; psh = cmd->host; pACB = (PACB ) psh->hostdata; ioport = pACB->IOPortBase;#ifdef DC390_DEBUG0/* if(pACB->scan_devices) */ printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);#endif if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) ) { pACB->scan_devices = 0; pPrevDCB->pNextDCB = pACB->pLinkDCB; } else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) ) { pACB->scan_devices = 0; pPrevDCB->pNextDCB = pACB->pLinkDCB; } if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) ) {/* printk("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return( 0 ); } if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { if( pACB->DeviceCnt < MAX_DEVICES ) { pACB->DCBmap[cmd->target] |= (1 << cmd->lun); pDCB = pACB->pDCB_free;#ifdef DC390_DEBUG0 printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);#endif DC390_initDCB( pACB, pDCB, cmd ); } else /* ???? */ {/* printk("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return(0); } } else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) {/* printk("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return(0); } else { pDCB = pACB->pLinkDCB; while( (pDCB->UnitSCSIID != cmd->target) || (pDCB->UnitSCSILUN != cmd->lun) ) { pDCB = pDCB->pNextDCB; }#ifdef DC390_DEBUG0 printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);#endif } cmd->scsi_done = done; cmd->result = 0; save_flags(flags); cli(); if( pDCB->QIORBCnt ) { QLinkcmd( cmd, pDCB ); pcmd = Getcmd( pDCB ); } else pcmd = cmd; pSRB = GetSRB( pACB ); if( !pSRB ) { QLinkcmd( pcmd, pDCB ); restore_flags(flags); return(0); }/* BuildSRB(pSRB); */ pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; ptr = (PUCHAR) pSRB->CmdBlock; ptr1 = (PUCHAR) pcmd->cmnd; pSRB->ScsiCmdLen = pcmd->cmd_len; for(i=0; i< pcmd->cmd_len; i++) { *ptr = *ptr1; ptr++; ptr1++; } if( pcmd->use_sg ) { pSRB->SGcount = (UCHAR) pcmd->use_sg; pSRB->pSegmentList = (PSGL) pcmd->request_buffer; } else if( pcmd->request_buffer ) { pSRB->SGcount = 1; pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } else pSRB->SGcount = 0; pSRB->SGIndex = 0; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; pSRB->MsgCnt = 0; if( pDCB->DevType != TYPE_TAPE ) pSRB->RetryCnt = 1; else pSRB->RetryCnt = 0; pSRB->SRBStatus = 0; pSRB->SRBFlag = 0; pSRB->SRBState = 0; pSRB->TotalXferredLen = 0; pSRB->SGPhysAddr = 0; pSRB->SGToBeXferLen = 0; pSRB->ScsiPhase = 0; pSRB->EndMessage = 0; SendSRB( pcmd, pACB, pSRB ); restore_flags(flags); return(0);}static voidDoNextCmd( PACB pACB, PDCB pDCB ){ Scsi_Cmnd *pcmd; PSRB pSRB; ULONG flags; PUCHAR ptr,ptr1; USHORT i; if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) return; save_flags(flags); cli(); pcmd = Getcmd( pDCB ); pSRB = GetSRB( pACB ); if( !pSRB ) { QLinkcmd( pcmd, pDCB ); restore_flags(flags); return; } pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; ptr = (PUCHAR) pSRB->CmdBlock; ptr1 = (PUCHAR) pcmd->cmnd; pSRB->ScsiCmdLen = pcmd->cmd_len; for(i=0; i< pcmd->cmd_len; i++) { *ptr = *ptr1; ptr++; ptr1++; } if( pcmd->use_sg ) { pSRB->SGcount = (UCHAR) pcmd->use_sg; pSRB->pSegmentList = (PSGL) pcmd->request_buffer; } else if( pcmd->request_buffer ) { pSRB->SGcount = 1; pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -