/*********************************************************************** * FILE NAME : TMSCSIW.C * * BY : C.L. Huang (ching@tekram.com.tw) * * Description: Device Driver for Tekram DC-390W/U/F (T) PCI SCSI * * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************/ /* Minor enhancements and bugfixes by * * Kurt Garloff * ***********************************************************************/ /* HISTORY: * * * * REV# DATE NAME DESCRIPTION * * 1.00 04/03/96 CLH First release * * 1.01 04/11/96 CLH Maximum support up to 4 Adapters, * * support KV 1_3_85 * * 1.02 04/26/96 CLH fixed bug about EEpromBuf when >1 HA * * 1.03 06/12/96 CLH fixed bug of Media Change for Removable * * Device, scan all LUN. Support Pre2.0.10 * * 1.04 06/18/96 CLH fixed bug of Command timeout .... * * 1.05 10/04/96 CLH Updating for support KV 2.0.0, 2.0.20 * * 1.06 10/30/96 KG Fixed bug in DC390W_abort(), module * * support, added tmscsiw_proc_info() * * 1.07 11/09/96 KG Fixed bug in tmscsiw_proc_info() * * 1.08 11/18/96 CLH/KG ditto, null ptr in DC390W_Disconnect() * * 1.09 11/30/96 KG Fixed bug in CheckEEpromCheckSum(), * * add register the allocated IO space * * 1.10 12/05/96 CLH Modify in tmscsiw_proc_info() and add * * in DC390W_initAdapter() for 53C875 * * Rev. F with double clock. * * 1.11 02/04/97 CLH Fixed bug of Formatting a partition that* * across 1GB boundary, with bad sector * * checking. * * 1.12 02/17/97 CLH Fixed bug in CheckEEpromCheckSum() * ***********************************************************************/ #define DC390W_DEBUG /* #define CHK_UNDER_RUN */ #define SCSI_MALLOC #ifdef MODULE #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE < 66354 /* 1.3.50 */ #include "../block/blk.h" #else #include #endif #include "scsi.h" #include "hosts.h" #include "tmscsiw.h" #include "constants.h" #include "sd.h" #include "scripts.h" #include #include "dc390w.h" #ifndef VERSION_ELF_1_2_13 struct proc_dir_entry proc_scsi_tmscsiw ={ PROC_SCSI_DC390WUF, 7 ,"tmscsiw", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #endif static void DC390W_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); static void PrepareSG( PACB pACB, PDCB pDCB, PSRB pSRB ); static void DoingSRB_Done( PACB pACB ); static void ExceptionHandler(ULONG wlval, PACB pACB, PDCB pDCB); static void ParityError( PACB pACB, PDCB pDCB ); static void PhaseMismatch( PACB pACB ); static void DC390W_ScsiRstDetect( PACB pACB ); static void DC390W_ResetSCSIBus( PACB pACB ); static void DC390W_ResetSCSIBus2( PACB pACB ); static void AdjustTemp( PACB pACB, PDCB pDCB, PSRB pSRB ); static void SetXferRate( PACB pACB, PDCB pDCB ); static void DataIOcommon( PACB pACB, ULONG Swlval, ULONG Cwlval ); static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); static void DC390W_CmdCompleted( PACB pACB ); static void DC390W_Reselected( PACB pACB ); static void DC390W_Reselected1( PACB pACB ); static void DC390W_ReselectedT( PACB pACB ); static void DC390W_Disconnected( PACB pACB ); static void DC390W_MessageExtnd( PACB pACB ); static void DC390W_Signal( PACB pACB ); static void DC390W_UnknownMsg( PACB pACB ); static void DC390W_MessageOut( PACB pACB ); static void DC390W_FatalError( PACB pACB ); static void DC390W_MessageSync( PACB pACB ); static void DC390W_MessageWide( PACB pACB ); static void DC390W_RestorePtr( PACB pACB ); static void DC390W_MsgReject( PACB pACB ); static void DC390W_Debug( PACB pACB ); static void DC390W_download_script (struct Scsi_Host *host); int DC390W_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index); void DC390W_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); void MyDelay( void ); void EnDisableCE( UCHAR Flag, USHORT scsiIOPort ); void EEpromOutDI( USHORT Carry, USHORT scsiIOPort ); void EEpromPrepare( UCHAR EEpromCmd, USHORT scsiIOPort ); void ReadEEprom( PUCHAR EEpromBuf, USHORT scsiIOPort ); UCHAR EEpromInDo(USHORT scsiIOPort); USHORT EEpromGetData(USHORT scsiIOPort); USHORT CheckEEpromCheckSum( PUCHAR EEpromBuf, USHORT scsiIOPort); #ifdef MODULE static int DC390W_release(struct Scsi_Host *host); static int DC390W_shutdown (struct Scsi_Host *host); #endif static ULONG jmp_table16; static ULONG jmp_din16; static ULONG jmp_dout16; static PSHT pSHT_start = NULL; static PSH pSH_start = NULL; static PSH pSH_current = NULL; static PACB pACB_start= NULL; static PACB pACB_current = NULL; static PDCB pPrevDCB = NULL; static USHORT adapterCnt = 0; static USHORT InitialTime = 0; static USHORT CurrDCBscntl3 = 0; static UCHAR pad_buffer[128]; static PVOID IntVector[]={ DC390W_CmdCompleted, DC390W_Reselected, DC390W_Reselected1, DC390W_ReselectedT, DC390W_Disconnected, DC390W_MessageExtnd, DC390W_Signal, DC390W_UnknownMsg, DC390W_MessageOut, DC390W_FatalError, DC390W_MessageSync, DC390W_MessageWide, DC390W_RestorePtr, DC390W_MsgReject, DC390W_Debug, DC390W_FatalError }; UCHAR eepromBuf[MAX_ADAPTER_NUM][128]; UCHAR clock_period[12] = {25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21}; UCHAR baddevname[2][28] ={ "SEAGATE ST3390N 9546", "SEAGATE ST3390N ??? 0399"}; #define BADDEVCNT 2 /*********************************************************************** * * * **********************************************************************/ static void QLinkcmd( PSCSICMD cmd, PDCB pDCB ) { ULONG flags; PSCSICMD pcmd; save_flags(flags); cli(); if( !pDCB->QIORBCnt ) { pDCB->pQIORBhead = cmd; pDCB->pQIORBtail = cmd; pDCB->QIORBCnt++; cmd->next = NULL; } else { pcmd = pDCB->pQIORBtail; pcmd->next = cmd; pDCB->pQIORBtail = cmd; pDCB->QIORBCnt++; cmd->next = NULL; } restore_flags(flags); } static PSCSICMD Getcmd( PDCB pDCB ) { ULONG flags; PSCSICMD pcmd; save_flags(flags); cli(); pcmd = pDCB->pQIORBhead; pDCB->pQIORBhead = pcmd->next; pcmd->next = NULL; pDCB->QIORBCnt--; restore_flags(flags); return( pcmd ); } static PSRB GetSRB( PACB pACB ) { ULONG flags; PSRB pSRB; save_flags(flags); cli(); pSRB = pACB->pFreeSRB; if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } restore_flags(flags); return( pSRB ); } static void RewaitSRB( PDCB pDCB, PSRB pSRB ) { PSRB psrb1; ULONG flags; UCHAR bval; save_flags(flags); cli(); pDCB->GoingSRBCnt--; psrb1 = pDCB->pGoingSRB; if( pSRB == psrb1 ) { pDCB->pGoingSRB = psrb1->pNextSRB; } else { while( pSRB != psrb1->pNextSRB ) psrb1 = psrb1->pNextSRB; psrb1->pNextSRB = pSRB->pNextSRB; if( pSRB == pDCB->pGoingLast ) pDCB->pGoingLast = psrb1; } if( (psrb1 = pDCB->pWaitingSRB) ) { pSRB->pNextSRB = psrb1; pDCB->pWaitingSRB = pSRB; } else { pSRB->pNextSRB = NULL; pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; } bval = pSRB->TagNumber; pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ restore_flags(flags); } static void DoWaitingSRB( PACB pACB ) { ULONG flags; PDCB ptr, ptr1; PSRB pSRB; save_flags(flags); cli(); if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) { ptr = pACB->pDCBRunRobin; if( !ptr ) { ptr = pACB->pLinkDCB; pACB->pDCBRunRobin = ptr; } ptr1 = ptr; for( ;ptr1; ) { pACB->pDCBRunRobin = ptr1->pNextDCB; if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || !( pSRB = ptr1->pWaitingSRB ) ) { if(pACB->pDCBRunRobin == ptr) break; ptr1 = ptr1->pNextDCB; } else { DC390W_StartSCSI(pACB, ptr1, pSRB); ptr1->GoingSRBCnt++; if( ptr1->pWaitLast == pSRB ) { ptr1->pWaitingSRB = NULL; ptr1->pWaitLast = NULL; } else { ptr1->pWaitingSRB = pSRB->pNextSRB; } pSRB->pNextSRB = NULL; if( ptr1->pGoingSRB ) ptr1->pGoingLast->pNextSRB = pSRB; else ptr1->pGoingSRB = pSRB; ptr1->pGoingLast = pSRB; break; } } } restore_flags(flags); return; } static void SRBwaiting( PDCB pDCB, PSRB pSRB) { if( pDCB->pWaitingSRB ) { pDCB->pWaitLast->pNextSRB = pSRB; pDCB->pWaitLast = pSRB; pSRB->pNextSRB = NULL; } else { pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; } } static void SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) { ULONG flags; PDCB pDCB; save_flags(flags); cli(); pDCB = pSRB->pSRBDCB; PrepareSG( pACB, pDCB, pSRB ); if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { SRBwaiting(pDCB, pSRB); goto SND_EXIT; } if( pDCB->pWaitingSRB ) { SRBwaiting(pDCB, pSRB); /* pSRB = GetWaitingSRB(pDCB); */ pSRB = pDCB->pWaitingSRB; pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } DC390W_StartSCSI(pACB, pDCB, pSRB); pDCB->GoingSRBCnt++; if( pDCB->pGoingSRB ) { pDCB->pGoingLast->pNextSRB = pSRB; pDCB->pGoingLast = pSRB; } else { pDCB->pGoingSRB = pSRB; pDCB->pGoingLast = pSRB; } SND_EXIT: restore_flags(flags); return; } /*********************************************************************** * Function : static int DC390W_queue_command (Scsi_Cmnd *cmd, * void (*done)(Scsi_Cmnd *)) * * Purpose : enqueues a SCSI command * * Inputs : cmd - SCSI command, done - function called on completion, with * a pointer to the command descriptor. * * Returns : 0 * ***********************************************************************/ int DC390W_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { USHORT ioport, i; Scsi_Cmnd *pcmd; struct Scsi_Host *psh; PACB pACB; PDCB pDCB; PSRB pSRB; ULONG flags; PUCHAR ptr,ptr1; psh = cmd->host; pACB = (PACB ) psh->hostdata; ioport = pACB->IOPortBase; #ifdef DC390W_DEBUG0 printk("Cmd=%x,",cmd->cmnd[0]); #endif if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) ) { pACB->scan_devices = 0; pPrevDCB->pNextDCB = pACB->pLinkDCB; } else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) ) { pACB->scan_devices = 0; pPrevDCB->pNextDCB = pACB->pLinkDCB; } if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) ) { /* printk("DC390W: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return( 0 ); } if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { if( pACB->DeviceCnt < MAX_DEVICES ) { pACB->DCBmap[cmd->target] |= (1 << cmd->lun); pDCB = pACB->pDCB_free; #ifdef DC390W_DEBUG0 printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target); #endif DC390W_initDCB( pACB, pDCB, cmd ); } else /* ???? */ { /* printk("DC390W: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return(0); } } else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { /* printk("DC390W: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return(0); } else { pDCB = pACB->pLinkDCB; while( (pDCB->UnitSCSIID != cmd->target) || (pDCB->UnitSCSILUN != cmd->lun) ) { pDCB = pDCB->pNextDCB; } #ifdef DC390W_DEBUG0 printk("pDCB=%8x,ID=%2x,Scan=%1x", (UINT) pDCB, cmd->target, pACB->scan_devices); #endif } cmd->scsi_done = done; cmd->result = 0; save_flags(flags); cli(); if( pDCB->QIORBCnt ) { QLinkcmd( cmd, pDCB ); pcmd = Getcmd( pDCB ); } else pcmd = cmd; pSRB = GetSRB( pACB ); if( !pSRB ) { QLinkcmd( pcmd, pDCB ); restore_flags(flags); return(0); } /* BuildSRB(pSRB); */ pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; ptr = (PUCHAR) pSRB->CmdBlock; ptr1 = (PUCHAR) pcmd->cmnd; (UCHAR) pSRB->__command[0] = pcmd->cmd_len; for(i=0; i< pcmd->cmd_len; i++) { *ptr = *ptr1; ptr++; ptr1++; } if( pcmd->use_sg ) { pSRB->SGcount = (UCHAR) pcmd->use_sg; pSRB->pSegmentList = (PSGL) pcmd->request_buffer; } else if( pcmd->request_buffer ) { pSRB->SGcount = 1; pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } else pSRB->SGcount = 0; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; pSRB->MsgCnt = 0; if( pDCB->DevType != TYPE_TAPE ) pSRB->RetryCnt = 1; else pSRB->RetryCnt = 0; pSRB->SRBStatus = 0; pSRB->SRBFlag = 0; pSRB->ScratchABuf = 0; pSRB->SRBState = 0; pSRB->RemainSegPtr = 0; pSRB->XferredLen = 0; SendSRB( pcmd, pACB, pSRB ); restore_flags(flags); return(0); } static void DoNextCmd( PACB pACB, PDCB pDCB ) { Scsi_Cmnd *pcmd; PSRB pSRB; ULONG flags; PUCHAR ptr,ptr1; USHORT i; if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) return; save_flags(flags); cli(); pcmd = Getcmd( pDCB ); pSRB = GetSRB( pACB ); if( !pSRB ) { QLinkcmd( pcmd, pDCB ); restore_flags(flags); return; } pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; ptr = (PUCHAR) pSRB->CmdBlock; ptr1 = (PUCHAR) pcmd->cmnd; (UCHAR) pSRB->__command[0] = pcmd->cmd_len; for(i=0; i< pcmd->cmd_len; i++) { *ptr = *ptr1; ptr++; ptr1++; } if( pcmd->use_sg ) { pSRB->SGcount = (UCHAR) pcmd->use_sg; pSRB->pSegmentList = (PSGL) pcmd->request_buffer; } else if( pcmd->request_buffer ) { pSRB->SGcount = 1; pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } else pSRB->SGcount = 0; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; pSRB->MsgCnt = 0; if( pDCB->DevType != TYPE_TAPE ) pSRB->RetryCnt = 1; else pSRB->RetryCnt = 0; pSRB->SRBStatus = 0; pSRB->SRBFlag = 0; pSRB->ScratchABuf = 0; pSRB->SRBState = 0; SendSRB( pcmd, pACB, pSRB ); restore_flags(flags); return; } /*********************************************************************** * Function: * DC390W_bios_param * * Description: * Return the disk geometry for the given SCSI device. ***********************************************************************/ #ifdef VERSION_ELF_1_2_13 int DC390W_bios_param(Disk *disk, int devno, int geom[]) #else int DC390W_bios_param(Disk *disk, kdev_t devno, int geom[]) #endif { int heads, sectors, cylinders; PACB pACB; pACB = (PACB) disk->device->host->hostdata; heads = 64; sectors = 32; cylinders = disk->capacity / (heads * sectors); if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) { heads = 255; sectors = 63; cylinders = disk->capacity / (heads * sectors); } geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return (0); } /*********************************************************************** * Function : int DC390W_abort (Scsi_Cmnd *cmd) * * Purpose : Abort an errant SCSI command * * Inputs : cmd - command to abort * * Returns : 0 on success, -1 on failure. ***********************************************************************/ int DC390W_abort (Scsi_Cmnd *cmd) { ULONG flags; PACB pACB; PDCB pDCB, pdcb; PSRB pSRB, psrb; USHORT count, i; PSCSICMD pcmd, pcmd1; int status; #ifdef DC390W_DEBUG0 printk("DC390W : Abort Cmd."); #endif save_flags(flags); cli(); pACB = (PACB) cmd->host->hostdata; pDCB = pACB->pLinkDCB; pdcb = pDCB; while( (pDCB->UnitSCSIID != cmd->target) || (pDCB->UnitSCSILUN != cmd->lun) ) { pDCB = pDCB->pNextDCB; if( pDCB == pdcb ) goto NOT_RUN; } if( pDCB->QIORBCnt ) { pcmd = pDCB->pQIORBhead; if( pcmd == cmd ) { pDCB->pQIORBhead = pcmd->next; pcmd->next = NULL; pDCB->QIORBCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } for( count = pDCB->QIORBCnt, i=0; 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 { psrb = pSRB; if( !(psrb->pNextSRB) ) goto ON_GOING; while( psrb->pNextSRB->pcmd != cmd ) { psrb = psrb->pNextSRB; if( !(psrb->pNextSRB) ) goto ON_GOING; } pSRB = psrb->pNextSRB; psrb->pNextSRB = pSRB->pNextSRB; if( pSRB == pDCB->pWaitLast ) pDCB->pWaitLast = psrb; IN_WAIT: pSRB->pNextSRB = pACB->pFreeSRB; pACB->pFreeSRB = pSRB; cmd->next = NULL; status = SCSI_ABORT_SUCCESS; goto ABO_X; } ON_GOING: pSRB = pDCB->pGoingSRB; for( count = pDCB->GoingSRBCnt, i=0; 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); restore_flags(flags); return( status ); } static void ResetDevParam( PACB pACB ) { PDCB pDCB, pdcb; pDCB = pACB->pLinkDCB; if( pDCB == NULL ) return; pdcb = pDCB; do { if( pACB->AdaptType == DC390W ) pdcb->DCBscntl3 = SYNC_CLK_F2+ASYNC_CLK_F2; else pdcb->DCBscntl3 = SYNC_CLK_F4+ASYNC_CLK_F4; pdcb->DCBsxfer = 0; pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); } static void RecoverSRB( PACB pACB ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; USHORT cnt, i; pDCB = pACB->pLinkDCB; if( pDCB == NULL ) return; pdcb = pDCB; do { cnt = pdcb->GoingSRBCnt; psrb = pdcb->pGoingSRB; for (i=0; ipNextSRB; /* RewaitSRB( pDCB, psrb ); */ if( pdcb->pWaitingSRB ) { psrb2->pNextSRB = pdcb->pWaitingSRB; pdcb->pWaitingSRB = psrb2; } else { pdcb->pWaitingSRB = psrb2; pdcb->pWaitLast = psrb2; psrb2->pNextSRB = NULL; } } pdcb->GoingSRBCnt = 0; pdcb->pGoingSRB = NULL; pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); } /*********************************************************************** * Function : int DC390W_reset (Scsi_Cmnd *cmd, ...) * * Purpose : perform a hard reset on the SCSI bus( and NCR chip). * * Inputs : cmd - command which caused the SCSI RESET * * Returns : 0 on success. ***********************************************************************/ #ifdef VERSION_2_0_0 int DC390W_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) #else int DC390W_reset (Scsi_Cmnd *cmd) #endif { USHORT ioport; unsigned long flags; PACB pACB; ULONG wlval; UCHAR bval; USHORT wval; USHORT i; #ifdef DC390W_DEBUG0 printk("DC390W : Reset Cmd0,"); #endif pACB = (PACB ) cmd->host->hostdata; ioport = pACB->IOPortBase; save_flags(flags); cli(); bval = inb(ioport+DCNTL); bval |= IRQ_DISABLE; outb(bval,ioport+DCNTL); /* disable interrupt */ DC390W_ResetSCSIBus( pACB ); for( i=0; i<500; i++ ) udelay(1000); for(;;) { bval = inb(ioport+ISTAT); if( bval & SCSI_INT_PENDING ) { wval = inw( ioport+SIST0 ); if( wval & (SCSI_RESET+SCSI_GERROR) ) break; } if(bval & DMA_INT_PENDING) { bval = inb(ioport+DSTAT); if(bval & ABORT_) { wval = inw( ioport+SIST0 ); break; } } } bval = inb(ioport+DCNTL); bval &= ~IRQ_DISABLE; outb(bval,ioport+DCNTL); /* re-enable interrupt */ ioport = pACB->IOPortBase; bval = inb(ioport+STEST3); bval |= CLR_SCSI_FIFO; outb(bval,ioport+STEST3); bval = CLR_DMA_FIFO; outb(bval,ioport+CTEST3); ResetDevParam( pACB ); DoingSRB_Done( pACB ); pACB->pActiveDCB = NULL; wlval = pACB->jmp_reselect; outl(wlval,(ioport+DSP)); pACB->ACBFlag = 0; DoWaitingSRB( pACB ); restore_flags(flags); return( SCSI_RESET_SUCCESS ); } #include "scsiio.c" /*********************************************************************** * Function : static void DC390W_initDCB * * Purpose : initialize the internal structures for a given DCB * * Inputs : cmd - pointer to this scsi cmd request block structure * ***********************************************************************/ void DC390W_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) { PEEprom prom; UCHAR bval; USHORT index; if( pACB->DeviceCnt == 0 ) { pACB->pLinkDCB = pDCB; pACB->pDCBRunRobin = pDCB; pDCB->pNextDCB = pDCB; pPrevDCB = pDCB; } else pPrevDCB->pNextDCB = pDCB; pDCB->pDCBACB = pACB; pDCB->QIORBCnt = 0; pDCB->DCBselect = 0; pDCB->DCBsxfer = 0; pDCB->DCBsdid = cmd->target; pDCB->UnitSCSIID = cmd->target; pDCB->UnitSCSILUN = cmd->lun; pDCB->pWaitingSRB = NULL; pDCB->GoingSRBCnt = 0; pDCB->TagMask = 0; pDCB->MaxCommand = 1; pDCB->AdaptIndex = pACB->AdapterIndex; index = pACB->AdapterIndex; prom = (PEEprom) &eepromBuf[index][cmd->target << 2]; pDCB->DevMode = prom->EE_MODE1; pDCB->NegoPeriod = clock_period[prom->EE_SPEED]; if( pACB->AdaptType == DC390W ) pDCB->DCBscntl3 = SYNC_CLK_F2+ASYNC_CLK_F2; else pDCB->DCBscntl3 = SYNC_CLK_F4+ASYNC_CLK_F4; if( pDCB->DevMode & PARITY_CHK_ ) pDCB->DCBscntl0 = EN_PARITY_CHK+SATN_IF_PARITY_ERR+FULL_ARBITRATION; else pDCB->DCBscntl0 = FULL_ARBITRATION; pDCB->AdpMode = eepromBuf[index][EE_MODE2]; if( pDCB->DevMode & EN_DISCONNECT_ ) bval = 0xC0; else bval = 0x80; bval |= cmd->lun; pDCB->IdentifyMsg = bval; if( pDCB->DevMode & SYNC_NEGO_ ) { pDCB->SyncMode = SYNC_ENABLE; pDCB->SyncOffset = SYNC_NEGO_OFFSET; } if( pDCB->DevMode & WIDE_NEGO_ ) { if( cmd->lun ) { if( !(CurrDCBscntl3 & EN_WIDE_SCSI) ) pDCB->DevMode &= ~WIDE_NEGO_; } else CurrDCBscntl3 = 0; } pDCB->DCBFlag = 0; } /*********************************************************************** * Function : static void DC390W_initSRB * * Purpose : initialize the internal structures for a given SRB * * Inputs : psrb - pointer to this scsi request block structure * ***********************************************************************/ void DC390W_initSRB( PSRB psrb ) { #ifndef VERSION_ELF_1_2_13 psrb->PhysSRB = virt_to_phys( psrb ); psrb->__command[1] = virt_to_phys( psrb->CmdBlock ); psrb->__msgout0[0] = 1; psrb->__msgout0[1] = virt_to_phys( psrb->MsgOutBuf ); psrb->SegmentPad[0] = 16; psrb->SegmentPad[1] = virt_to_phys( pad_buffer ); #else psrb->PhysSRB = (ULONG) psrb; psrb->__command[1] = (ULONG) psrb->CmdBlock; psrb->__msgout0[0] = 1; psrb->__msgout0[1] = (ULONG) psrb->MsgOutBuf; psrb->SegmentPad[0] = 16; psrb->SegmentPad[1] = (ULONG) pad_buffer; #endif } void DC390W_linkSRB( PACB pACB ) { USHORT count, i; PSRB psrb; count = pACB->SRBCount; for( i=0; i< count; i++) { if( i != count - 1) pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; else pACB->SRB_array[i].pNextSRB = NULL; psrb = (PSRB) &pACB->SRB_array[i]; DC390W_initSRB( psrb ); } } /*********************************************************************** * Function : static void DC390W_initACB * * Purpose : initialize the internal structures for a given SCSI host * * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ void DC390W_initACB( PSH psh, USHORT chipType, ULONG io_port, UCHAR Irq, USHORT index ) { PACB pACB; USHORT i; UCHAR adaptType, bval; psh->can_queue = MAX_CMD_QUEUE; psh->cmd_per_lun = MAX_CMD_PER_LUN; psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID]; psh->io_port = io_port; psh->n_io_port = 0x80; psh->irq = Irq; if( chipType == PCI_DEVICE_ID_NCR53C825A ) adaptType = DC390W; else { outb( 2, io_port+GPREG ); bval = inb( io_port+GPREG ); if( bval & 8 ) adaptType = DC390U; else adaptType = DC390F; } pACB = (PACB) psh->hostdata; #ifndef VERSION_ELF_1_2_13 if( adaptType == DC390U ) { psh->max_id = 8; pACB->max_id = 7; } else { psh->max_id = 16; pACB->max_id = 15; } #ifdef CONFIG_SCSI_MULTI_LUN if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) psh->max_lun = 8; else #endif psh->max_lun = 1; #else pACB->max_id = 7; #endif if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] ) pACB->max_id--; #ifdef CONFIG_SCSI_MULTI_LUN if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) pACB->max_lun = 7; else #endif pACB->max_lun = 0; pACB->pScsiHost = psh; pACB->IOPortBase = (USHORT) io_port; pACB->pLinkDCB = NULL; pACB->pDCBRunRobin = NULL; pACB->pActiveDCB = NULL; pACB->pFreeSRB = pACB->SRB_array; pACB->SRBCount = MAX_SRB_CNT; pACB->AdapterIndex = index; pACB->status = 0; pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID]; pACB->AdaptSCSILUN = 0; pACB->DeviceCnt = 0; pACB->IRQLevel = Irq; pACB->AdaptType = adaptType; pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2; pACB->ACBFlag = 0; pACB->scan_devices = 1; pACB->Gmode2 = eepromBuf[index][EE_MODE2]; if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) pACB->LUNchk = 1; pACB->pDCB_free = &pACB->DCB_array[0]; DC390W_linkSRB( pACB ); for(i=0; iDCBmap[i] = 0; } /*********************************************************************** * Function : static int DC390W_initAdapter * * Purpose : initialize the SCSI chip ctrl registers * * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ int DC390W_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ) { USHORT ioport, wval; UCHAR bval; PACB pACB, pacb; USHORT used_irq = 0; pacb = pACB_start; if( pacb != NULL ) { for ( ; (pacb != (PACB) -1) ; ) { if( pacb->IRQLevel == Irq ) { used_irq = 1; break; } else pacb = pacb->pNextACB; } } if( !used_irq ) { #ifdef VERSION_ELF_1_2_13 if( request_irq(Irq, DC390W_Interrupt, SA_INTERRUPT, "tmscsiw")) #else if( request_irq(Irq, DC390W_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsiw", NULL)) #endif { printk("DC390W : register IRQ error!\n"); return( -1 ); } } request_region(io_port,psh->n_io_port,"tmscsiw"); ioport = (USHORT) io_port; outb(IRQ_DISABLE, ioport+DCNTL); outb(ABORT_OP, ioport+ISTAT); udelay(100000); outb(0, ioport+ISTAT); bval = inb(ioport+DSTAT); bval = inb(ioport+ISTAT); wval = inw(ioport+SIST0); pACB = (PACB) psh->hostdata; bval = pACB->AdaptSCSIID; bval |= ENABLE_RESEL; outb(bval,ioport+SCID); if(pACB->AdaptType == DC390W) bval = SYNC_CLK_F2+ASYNC_CLK_F2; else { /* @1.09 */ bval = inb(ioport+CTEST3); if( (bval & CHIP_REV_MASK) < 0x30 ) /* 53C875 Rev. F or later ? */ goto REVF; bval = inb(ioport+STEST1); if( (bval & 0x0C) == 0x0C ) /* double clock already enable ? */ goto REVF; outb(8,ioport+STEST1); /* enable clock doubler */ udelay(20); outb(HALT_SCSI_CLK,ioport+STEST3); /* halt clock */ outb(0x0C,ioport+STEST1); /* select double SCSI clock */ outb(0,ioport+STEST3); /* re-enable clock */ REVF: bval = SYNC_CLK_F4+ASYNC_CLK_F4; } outb(bval,ioport+SCNTL3); bval = SYNC_PERIOD_F4+ASYNCHRONOUS; /* set to async */ outb(bval,ioport+SXFER); bval = WRT_EN_INVALIDATE; /* Enable write and invalidate */ outb(bval,ioport+CTEST3); bval = EN_DMA_FIFO_536+BURST_LEN_MSB; /* select 536 bytes DMA FIFO, burst len bit2=1 */ outb(bval,ioport+CTEST5); bval = BURST_LEN8+EN_READ_LINE+EN_READ_MULTIPLE+BURST_OPCODE_FETCH+AUTO_START; /* set DMA parameter */ outb(bval,ioport+DMODE); bval = EN_ABORTED+EN_SCRIPT_INT+EN_ILLEGAL_INST; /* enable DMA interrupt */ outb(bval,ioport+DIEN); bval = EN_CACHE_LINE_SIZE+EN_PRE_FETCH+TOTEM_POLE_IRQ+COMPATIBLE_700; outb(bval,ioport+DCNTL); bval = EN_PHASE_MISMATCH+EN_SCSI_GERROR+EN_UNEXPECT_DISC+EN_SCSI_RESET+EN_PARITY_ERROR; outb(bval,ioport+SIEN0); bval = EN_SEL_TIMEOUT+EN_GENERAL_TIMEOUT; outb(bval,ioport+SIEN1); bval = SEL_TO_204ms; /* 250ms selection timeout */ outb(bval,ioport+STIME0); wval = 1 << (eepromBuf[index][EE_ADAPT_SCSI_ID]); /* @1.11 */ outw(wval,ioport+RESPID0); bval = DIS_SINGLE_INIT; if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION ) bval |= ACTIVE_NEGATION_; outb(bval,ioport+STEST3); return(0); } /*********************************************************************** * Function : static int DC390W_init (struct Scsi_Host *host) * * Purpose : initialize the internal structures for a given SCSI host * * Inputs : host - pointer to this host adapter's structure/ * * Preconditions : when this function is called, the chip_type * field of the pACB structure MUST have been set. ***********************************************************************/ static int DC390W_init (PSHT psht, USHORT chipType, ULONG io_port, UCHAR Irq, USHORT index) { PSH psh; PACB pACB; if( ! CheckEEpromCheckSum( &eepromBuf[index][0], (USHORT) io_port) ) { psh = scsi_register( psht, sizeof(DC390W_ACB) ); if( !psh ) return( -1 ); if( !pSH_start ) { pSH_start = psh; pSH_current = psh; } else { pSH_current->next = psh; pSH_current = psh; } #ifdef DC390W_DEBUG0 printk("DC390W : pSH = %8x,", (UINT) psh); #endif DC390W_initACB( psh, chipType, io_port, Irq, index ); if( !DC390W_initAdapter( psh, io_port, Irq, index ) ) { pACB = (PACB) psh->hostdata; if( !pACB_start ) { pACB_start = pACB; pACB_current = pACB; pACB->pNextACB = (PACB) -1; } else { pACB_current->pNextACB = pACB; pACB_current = pACB; pACB->pNextACB = (PACB) -1; } #ifdef DC390W_DEBUG0 printk("DC390W : pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n", (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array); printk("DC390W : ACB size= %4x, DCB size= %4x, SRB size= %4x\n", sizeof(DC390W_ACB), sizeof(DC390W_DCB), sizeof(DC390W_SRB) ); #endif } else { pSH_start = NULL; scsi_unregister( psh ); return( -1 ); } DC390W_download_script( psh ); return( 0 ); } else { printk("DC390W_init: EEPROM reading error!\n"); return( -1 ); } } void MyDelay( void ) { UCHAR i,j; j = inb(0x61) & 0x10; for(;;) { i = inb(0x61) & 0x10; if( j ^ i) break; } } void EnDisableCE( UCHAR Flag, USHORT scsiIOPort ) { UCHAR bval; USHORT port; port = (scsiIOPort & 0xff00) + GPREG; if(Flag == ENABLE_CE) bval = 0x10; else bval = 0x00; outb(bval,port); udelay(8); /* Delay();*/ } void EEpromOutDI( USHORT Carry, USHORT scsiIOPort ) { UCHAR bval; USHORT port; port = (scsiIOPort & 0xff00) + GPREG; bval = 0x10; if(Carry) bval |= 0x02; /* SK=0, DI */ outb(bval,port); udelay(8); /* Delay();*/ bval |= 0x04; /* SK=1, DI */ outb(bval,port); udelay(8); /* Delay();*/ bval &= 0xfb; /* SK=0, DI */ outb(bval,port); udelay(8); /* Delay();*/ } void EEpromPrepare( UCHAR EEpromCmd, USHORT scsiIOPort ) { UCHAR i,j; USHORT carryFlag; carryFlag = 1; j = 0x80; for(i=0;i<9;i++) { EEpromOutDI(carryFlag,scsiIOPort); carryFlag = (EEpromCmd & j) ? 1 : 0; j >>= 1; } } UCHAR EEpromInDo(USHORT scsiIOPort) { UCHAR bval; USHORT port; port = (scsiIOPort & 0xff00) + GPREG; bval = 0x14; /* SK=1 */ outb(bval,port); udelay(8); /* Delay();*/ bval = 0x10; /* SK=0 */ outb(bval,port); udelay(8); /* Delay();*/ bval = inb(port); if(bval & 0x01) return( 1 ); else return( 0 ); } USHORT EEpromGetData(USHORT scsiIOPort) { UCHAR i; UCHAR carryFlag; USHORT wval; wval = 0; for(i=0;i<16;i++) { wval <<= 1; carryFlag = EEpromInDo(scsiIOPort); wval |= carryFlag; } return( wval ); } void ReadEEprom( PUCHAR EEpromBuf, USHORT scsiIOPort ) { UCHAR cmd; cmd = EEPROM_READ; loop_rd: EnDisableCE(ENABLE_CE, scsiIOPort); EEpromPrepare(cmd, scsiIOPort); *((PUSHORT)EEpromBuf) = EEpromGetData(scsiIOPort); EEpromBuf++; EEpromBuf++; cmd++; EnDisableCE(DISABLE_CE, scsiIOPort); if(cmd & 0x3f) goto loop_rd; } USHORT CheckEEpromCheckSum( PUCHAR EEpromBuf, USHORT scsiIOPort) { USHORT wval,port, *ptr; UCHAR i,bval; port = (scsiIOPort & 0xff00) + GPCNTL; bval = 0x09; /* configure IO Pin */ outb(bval,port); ReadEEprom(EEpromBuf,scsiIOPort); /* read eeprom data */ wval = 0; ptr = (PUSHORT) EEpromBuf; for(i=0; i<128 ;i+=2, ptr++) wval += *ptr; return( (wval == 0x1234) ? 0 : -1); } static void DC390W_download_script (struct Scsi_Host *host) { ULONG wlval, wlval1, length, alignm; USHORT j, k, m; USHORT ioport; UCHAR bval; PACB pACB; PSRB pSRB; void *pSrc, *pSrc1; ULONG *pStart; ULONG Ent_reselected; ULONG Ent_reselecttag; ULONG Ent_select0; ULONG Ent_select1; ULONG Ent_check_phase; ULONG Ent_status1_phase; ULONG Ent_command_phase; ULONG Ent_jump_table0; ULONG Ent_din_phaseB; ULONG Ent_dout_phaseB; ULONG Ent_din_pad_0; ULONG Ent_dout_pad_0; ULONG Ent_jump_tablew; ULONG Ent_din_pad_1; ULONG Ent_dout_pad_1; ULONG Ent_mout_phase; ULONG Ent_status_phase; ULONG Ent_min_phase; ULONG Ent_jump_msgok; ULONG Ent_msg__1; ULONG Ent_msg___3; ULONG Ent_msg___2; ULONG Ent_set_atn; ULONG Ent_msg__a; ULONG Ent_msg__23; ULONG Ent_msg__3; ULONG Ent_msg__4; ULONG Ent_clr_atn; ULONG Ent_din_phaseW; ULONG Ent_dout_phaseW; ULONG Ent_din_pad_addrB; ULONG Ent_dout_pad_addrB; ULONG Ent_din_pad_addrW; ULONG Ent_dout_pad_addrW; pACB = (PACB) host->hostdata; ioport = pACB->IOPortBase; bval = SCRATCHAB_AS_BASE; /* set scratchB contains 4K RAM base address */ outb(bval,ioport+CTEST2); wlval = inl((ioport+SCRATCHB)); /* get starting address of 4K RAM */ /* wlval += 0x800; */ /* point to Upper 2K RAM */ DesPhysAddr[0] = wlval; /* destination address */ #ifdef DC390W_DEBUG0 printk("DesAddr=%8x,",(UINT) wlval); #endif bval = 0; /* set Scratch_A and Scratch_B to normal mode */ outb(bval,ioport+CTEST2); /*------------------------------------------------------------------- * patch the label in jump instruction: using offset relative * to start_script *------------------------------------------------------------------*/ Ent_reselected = (ULONG) reselected - (ULONG) start_script; Ent_reselecttag = (ULONG) reselecttag - (ULONG) start_script; Ent_select0 = (ULONG) select0 - (ULONG) start_script; Ent_select1 = (ULONG) select1 - (ULONG) start_script; Ent_check_phase = (ULONG) check_phase - (ULONG) start_script; Ent_status1_phase = (ULONG) status1_phase - (ULONG) start_script; Ent_command_phase = (ULONG) command_phase - (ULONG) start_script; Ent_din_phaseB = (ULONG) din_phaseB - (ULONG) start_script; Ent_dout_phaseB = (ULONG) dout_phaseB - (ULONG) start_script; Ent_din_phaseW = (ULONG) din_phaseW - (ULONG) start_script; Ent_dout_phaseW = (ULONG) dout_phaseW - (ULONG) start_script; Ent_jump_table0 = (ULONG) jump_table0 - (ULONG) start_script; Ent_din_pad_0 = (ULONG) din_pad_0 - (ULONG) start_script; Ent_din_pad_addrB = (ULONG) din_pad_addrB - (ULONG) start_script; Ent_dout_pad_0 = (ULONG) dout_pad_0 - (ULONG) start_script; Ent_dout_pad_addrB = (ULONG) dout_pad_addrB - (ULONG) start_script; Ent_jump_tablew = (ULONG) jump_tablew - (ULONG) start_script; Ent_din_pad_1 = (ULONG) din_pad_1 - (ULONG) start_script; Ent_din_pad_addrW = (ULONG) din_pad_addrW - (ULONG) start_script; Ent_dout_pad_1 = (ULONG) dout_pad_1 - (ULONG) start_script; Ent_dout_pad_addrW = (ULONG) dout_pad_addrW - (ULONG) start_script; Ent_mout_phase = (ULONG) mout_phase - (ULONG) start_script; Ent_status_phase = (ULONG) status_phase - (ULONG) start_script; Ent_min_phase = (ULONG) min_phase - (ULONG) start_script; Ent_jump_msgok = (ULONG) jump_msgok - (ULONG) start_script; Ent_msg__1 = (ULONG) msg__1 - (ULONG) start_script; Ent_msg___3 = (ULONG) msg___3 - (ULONG) start_script; Ent_msg___2 = (ULONG) msg___2 - (ULONG) start_script; Ent_set_atn = (ULONG) set_atn - (ULONG) start_script; Ent_msg__a = (ULONG) msg__a - (ULONG) start_script; Ent_msg__23 = (ULONG) msg__23 - (ULONG) start_script; Ent_msg__3 = (ULONG) msg__3 - (ULONG) start_script; Ent_msg__4 = (ULONG) msg__4 - (ULONG) start_script; Ent_clr_atn = (ULONG) clr_atn - (ULONG) start_script; jmp_select0[0] = Ent_select0 + wlval; jmp_reselected[0] = Ent_reselected + wlval; jmp_check_phase[0] = Ent_check_phase + wlval; jmp_check_phase1[0] = Ent_check_phase + wlval; jmp_check_phase2[0] = Ent_check_phase + wlval; jmp_check_phase3[0] = Ent_check_phase + wlval; jmp_check_phase4[0] = Ent_check_phase + wlval; jmp_check_phase5[0] = Ent_check_phase + wlval; jmp_check_phase6[0] = Ent_check_phase + wlval; jmp_status1_phase[0] = Ent_status1_phase + wlval; jmp_status1_phase1[0] = Ent_status1_phase + wlval; jmp_status1_phase2[0] = Ent_status1_phase + wlval; jmp_status1_phase3[0] = Ent_status1_phase + wlval; jmp_command_phase[0] = Ent_command_phase + wlval; for(j=0,k=1,m=0; j< (MAX_SG_LIST_BUF+1); j++) { jmp_dio_phaseB[k] = Ent_din_phaseB + m + wlval; jmp_dio_phaseW[k] = Ent_din_phaseW + m + wlval; k += 2; jmp_dio_phaseB[k] = Ent_dout_phaseB + m + wlval; jmp_dio_phaseW[k] = Ent_dout_phaseW + m + wlval; k += 2; m += 8; } jmp_din_pad_0[0] = Ent_din_pad_0 + wlval; jmp_dout_pad_0[0] = Ent_dout_pad_0 + wlval; jmp_din_pad_addrB[0] = Ent_din_pad_addrB + wlval; jmp_dout_pad_addrB[0] = Ent_dout_pad_addrB + wlval; jmp_din_pad_addrW[0] = Ent_din_pad_addrW + wlval; jmp_dout_pad_addrW[0] = Ent_dout_pad_addrW + wlval; jmp_din_pad_1[0] = Ent_din_pad_1 + wlval; jmp_dout_pad_1[0] = Ent_dout_pad_1 + wlval; jmp_status_phase[0] = Ent_status_phase + wlval; jmp_min_phase[0] = Ent_min_phase + wlval; jmp_mout_phase[0] = Ent_mout_phase + wlval; jmp_jump_msgok[0] = Ent_jump_msgok + wlval; jmp_msg__1[0] = Ent_msg__1 + wlval; jmp_msg___3[0] = Ent_msg___3 + wlval; jmp_msg___2[0] = Ent_msg___2 + wlval; jmp_msg__a[0] = Ent_msg__a + wlval; jmp_msg__a1[0] = Ent_msg__a + wlval; jmp_msg__a2[0] = Ent_msg__a + wlval; jmp_msg__23[0] = Ent_msg__23 + wlval; jmp_msg__3[0] = Ent_msg__3 + wlval; jmp_msg__4[0] = Ent_msg__4 + wlval; /*-------------------------------------------------------------------- // patch the element in ACB struct: using Physical address //-------------------------------------------------------------------*/ #ifndef VERSION_ELF_1_2_13 wlval1 = virt_to_phys( pACB->msgin123 ); #else wlval1 = (ULONG) pACB->msgin123; #endif ACB_msgin123_1[0] = wlval1; ACB_msgin123_2[0] = wlval1; ACB_msgin123_3[0] = wlval1; ACB_msgin123_4[0] = wlval1; ACB_msgin123_5[0] = wlval1; ACB_msgin123_6[0] = wlval1; ACB_msgin123_7[0] = wlval1; #ifndef VERSION_ELF_1_2_13 ACB_status[0] = virt_to_phys( &pACB->status ); #else ACB_status[0] = (ULONG) &pACB->status; #endif /*-------------------------------------------------------------------- // patch the element in SRB struct: using offset in struct //-------------------------------------------------------------------*/ pSRB = (PSRB) pACB->SRB_array; select1[0] = (select1[0] & 0xffff0000) + ((ULONG) &pSRB->__select - (ULONG) &pSRB->CmdBlock); SRB_msgout0[0] = (ULONG) &pSRB->__msgout0 - (ULONG) &pSRB->CmdBlock; SRB_msgout01[0] = (ULONG) &pSRB->__msgout0 - (ULONG) &pSRB->CmdBlock; SRB_command[0] = (ULONG) &pSRB->__command - (ULONG) &pSRB->CmdBlock; SRB_SegmentPad[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock; SRB_SegmentPad1[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock; SRB_SegmentPad2[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock; SRB_SegmentPad3[0] = (ULONG) &pSRB->SegmentPad - (ULONG) &pSRB->CmdBlock; wlval = (ULONG) &pSRB->Segment0 - (ULONG) &pSRB->CmdBlock; for(j=0,k=1; j<(MAX_SG_LIST_BUF+1); j++) { din_phaseB[k] = wlval; dout_phaseB[k] = wlval; din_phaseW[k] = wlval; dout_phaseW[k] = wlval; k += 2; wlval += 8; } bval = inb(ioport+DCNTL); bval |= IRQ_DISABLE; outb(bval,ioport+DCNTL); /* disable interrupt */ /* pSrc = scsi_init_malloc( 2048, GFP_ATOMIC); */ pSrc = scsi_init_malloc( 4096, GFP_ATOMIC); /* 1.11 */ #ifdef DC390W_DEBUG0 printk("SrcAlloc=%8x,",(UINT) pSrc); #endif alignm = 4 - (((ULONG) pSrc) & 3); pSrc1 = (void *)(((ULONG) pSrc) + alignm); length = (ULONG) end_script - (ULONG) start_script; memcpy( pSrc1, (void *) start_script, length); pStart = (ULONG *) ((ULONG) start_mov - (ULONG) start_script); pStart =(ULONG *) (((ULONG) pStart) + ((ULONG) pSrc1)); #ifdef DC390W_DEBUG0 printk("SrcAddr=%8x,\n",(UINT) pSrc1); #endif #ifndef VERSION_ELF_1_2_13 (ULONG *)pStart[1] = virt_to_phys( pSrc1 ); #else (ULONG *)pStart[1] = (ULONG) pSrc1; #endif /* wlval = virt_to_phys( start_script ); */ /* physical address of start_script */ /* SrcPhysAddr[0] = wlval; */ /* sources address */ /* start to download SCRIPT instruction to the RAM of NCR53c825A,875 */ /* wlval = virt_to_phys( start_mov ); */ #ifndef VERSION_ELF_1_2_13 wlval = virt_to_phys( pStart ); #else wlval = (ULONG) pStart; #endif outl(wlval,ioport+DSP); bval = inb(ioport+ISTAT); while(!(bval & DMA_INT_PENDING)) /* check load start_script is finished? */ bval = inb(ioport+ISTAT); bval = inb(ioport+DSTAT); /* clear interrupt */ bval = inb(ioport+DCNTL); bval &= ~IRQ_DISABLE; outb(bval,ioport+DCNTL); /* re-enable interrupt */ scsi_init_free((char *) pSrc, 4096); wlval = DesPhysAddr[0]; /* starting addr of RAM */ wlval -= (ULONG) start_script; pACB->jmp_reselect = wlval + (ULONG) start_script; pACB->jmp_select = wlval + (ULONG) select1; pACB->jmp_table8 = wlval + (ULONG) jump_table0; pACB->jmp_set_atn = wlval + (ULONG) set_atn; pACB->jmp_clear_ack = wlval + (ULONG) msg__a; pACB->jmp_next = wlval + (ULONG) check_phase; pACB->jmp_din8 = wlval + (ULONG) din_phaseB+8; pACB->jmp_dout8 = wlval + (ULONG) dout_phaseB+8; pACB->jmp_clear_atn = wlval + (ULONG) clr_atn; pACB->jmp_reselecttag = wlval + (ULONG) reselecttag; wlval = pACB->jmp_reselect; outl(wlval,(ioport+DSP)); return; } /*********************************************************************** * Function : int DC390W_detect(Scsi_Host_Template *psht) * * Purpose : detects and initializes NCR53c825A,875 SCSI chips * that were autoprobed, overridden on the LILO command line, * or specified at compile time. * * Inputs : psht - template for this SCSI adapter * * Returns : number of host adapters detected * ***********************************************************************/ int DC390W_detect(Scsi_Host_Template *psht) { UCHAR pci_bus, pci_device_fn, irq; #ifndef VERSION_ELF_1_2_13 UINT io_port, ram_base; #else ULONG io_port, ram_base; #endif USHORT i; int error = 0; USHORT adaptCnt = 0; /* Number of boards detected */ USHORT pci_index = 0; /* Device index to PCI BIOS calls */ USHORT pci_index2 = 0; /* Device index to PCI BIOS calls */ USHORT chipType = 0; #ifndef VERSION_ELF_1_2_13 psht->proc_dir = &proc_scsi_tmscsiw; #endif InitialTime = 1; pSHT_start = psht; jmp_table16 = (ULONG) jump_tablew - (ULONG) jump_table0; jmp_din16 = (ULONG) din_phaseW - (ULONG) din_phaseB; jmp_dout16 = (ULONG) dout_phaseW - (ULONG) dout_phaseB; pACB_start = NULL; if ( pcibios_present() ) { for (i = 0; i < MAX_ADAPTER_NUM; ++i) { if( !pcibios_find_device( PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR53C825A, pci_index, &pci_bus, &pci_device_fn) ) { chipType = PCI_DEVICE_ID_NCR53C825A; pci_index++; } else if( !pcibios_find_device( PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR53C875, pci_index2, &pci_bus, &pci_device_fn) ) { chipType = PCI_DEVICE_ID_NCR53C875; pci_index2++; } if( chipType ) { error = pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &io_port); error |= pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &ram_base); error |= pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &irq); if( error ) { printk("DC390W_detect: reading configuration registers error!\n"); InitialTime = 0; return( 0 ); } (USHORT) io_port = (USHORT) io_port & 0xFFFE; #ifdef DC390W_DEBUG0 printk("DC390W : IO_PORT=%4x,RAM_BASE=%8x,IRQ=%x,CHIPID=%x,\n", (UINT) io_port, (UINT) ram_base, irq, (UCHAR)chipType); #endif if( !DC390W_init(psht, chipType, io_port, irq, i) ) adaptCnt++; chipType = 0; } else break; } } InitialTime = 0; adapterCnt = adaptCnt; return( adaptCnt ); } #ifndef VERSION_ELF_1_2_13 /******************************************************************** * Function: tmscsiw_set_info() * * Purpose: Set adapter info (!) * * Not yet implemented * *******************************************************************/ int tmscsiw_set_info(char *buffer, int length, struct Scsi_Host *shpnt) { return(-ENOSYS); /* Currently this is a no-op */ } /******************************************************************** * Function: tmscsiw_proc_info(char* buffer, char **start, * off_t offset, int length, int hostno, int inout) * * Purpose: return SCSI Adapter/Device Info * * Input: buffer: Pointer to a buffer where to write info * start : * offset: * hostno: Host adapter index * inout : Read (=0) or set(!=0) info * * Output: buffer: contains info * length; length of info in buffer * * return value: length * ********************************************************************/ /* KG: proc_info taken from driver aha152x.c */ #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, ## args) #define YESNO(YN)\ if (YN) SPRINTF(" Yes ");\ else SPRINTF(" No ") int tmscsiw_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { int dev, spd, spd1; char *pos = buffer; PSH shpnt; PACB acbpnt; PDCB dcbpnt; unsigned long flags; /* Scsi_Cmnd *ptr; */ acbpnt = pACB_start; while(acbpnt != (PACB)-1) { shpnt = acbpnt->pScsiHost; if (shpnt->host_no == hostno) break; acbpnt = acbpnt->pNextACB; } if (acbpnt == (PACB)-1) return(-ESRCH); if (!shpnt) return(-ESRCH); if(inout) /* Has data been written to the file ? */ return(tmscsiw_set_info(buffer, length, shpnt)); SPRINTF("Tekram DC390W/U/F (T) PCI SCSI Host Adadpter, "); SPRINTF("Driver Version 1.12, 1997/02/17\n"); save_flags(flags); cli(); SPRINTF("SCSI Host Nr %i, ", hostno); SPRINTF("DC390WUF Adapter Nr %i\n", acbpnt->AdapterIndex); SPRINTF("IOPortBase 0x%04x, ", acbpnt -> IOPortBase); SPRINTF("IRQLevel 0x%02x\n",acbpnt -> IRQLevel); SPRINTF("Adapter Type: "); switch(acbpnt->AdaptType) { case DC390W: SPRINTF("DC390W, Fast Wide SCSI \n"); break; case DC390U: SPRINTF("DC390U, Ultra SCSI\n"); break; case DC390F: SPRINTF("DC390F, Ultra Wide SCSI\n"); break; default: SPRINTF("Unknown !\n"); } SPRINTF("MaxID %i, MaxLUN %i, ", acbpnt->max_id, acbpnt->max_lun); SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN); SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status); SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt); SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ Wide NegoPeriod SyncSpeed SyncOffs\n"); dcbpnt = acbpnt->pLinkDCB; for (dev = 0; dev < acbpnt->DeviceCnt; dev++) { SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN); YESNO(dcbpnt->DevMode & PARITY_CHK_); YESNO(dcbpnt->DCBsxfer & OFFSET_MASK); YESNO(dcbpnt->DevMode & EN_DISCONNECT_); YESNO(dcbpnt->DevMode & SEND_START_); YESNO(dcbpnt->MaxCommand > 1); YESNO(dcbpnt->DCBscntl3 & EN_WIDE_SCSI); SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2); if (dcbpnt->DCBsxfer & OFFSET_MASK) { spd = 1000/(dcbpnt->SyncPeriod <<2); spd1 = 1000%(dcbpnt->SyncPeriod <<2); spd1 = (spd1 * 10)/(dcbpnt->SyncPeriod <<2); SPRINTF(" %2i.%1i M %02i\n", spd, spd1, dcbpnt->DCBsxfer & OFFSET_MASK); } else SPRINTF("\n"); /* Add more info ...*/ dcbpnt = dcbpnt->pNextDCB; } restore_flags(flags); *start = buffer + offset; if (pos - buffer < offset) return 0; else if (pos - buffer - offset < length) return pos - buffer - offset; else return length; } #endif /* VERSION_ELF_1_2_13 */ #ifdef MODULE /*********************************************************************** * Function : static int DC390W_shutdown (struct Scsi_Host *host) * * Purpose : does a clean (we hope) shutdown of the NCR SCSI chip. * Use prior to dumping core, unloading the NCR driver, etc. * * Returns : 0 on success ***********************************************************************/ static int DC390W_shutdown (struct Scsi_Host *host) { USHORT ioport; unsigned long flags; PACB pACB = (PACB) host->hostdata; ioport = (unsigned int) pACB->IOPortBase; save_flags (flags); cli(); /* pACB->soft_reset(host); */ /* * For now, we take the simplest solution : reset the SCSI bus. Eventually, * - If a command is connected, kill it with an ABORT message * - If commands are disconnected, connect to each target/LUN and * do a ABORT, followed by a SOFT reset, followed by a hard * reset. */ #ifdef DC390W_DEBUG0 printk("DC390W: shutdown,"); #endif outb(ASSERT_RST, ioport+SCNTL1); udelay(25); /* Minimum amount of time to assert RST */ outb(0, ioport+SCNTL1); restore_flags (flags); return( 0 ); } int DC390W_release(struct Scsi_Host *host) { int irq_count; struct Scsi_Host *tmp; DC390W_shutdown (host); if (host->irq != IRQ_NONE) { for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next) { if ( tmp->irq == host->irq ) ++irq_count; } if (irq_count == 1) { #ifdef DC390W_DEBUG0 printk("DC390W: Free IRQ %i.",host->irq); #endif #ifndef VERSION_ELF_1_2_13 free_irq(host->irq,NULL); #else free_irq(host->irq); #endif } } release_region(host->io_port,host->n_io_port); return( 1 ); } Scsi_Host_Template driver_template = DC390WUF; #include "scsi_module.c" #endif /* def MODULE */