📄 cpqfctscontrol.c
字号:
// clear the soft reset for( i=0; i<8; i++) writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST)); // clear out our copy of Tach regs, // because they must be invalid now, // since TachLite reset all his regs. CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs cpqfcTSClearLinkStatusCounters(fcChip); // clear our s/w accumulators // lower bits give GBIC info fcChip->Registers.TYstatus.value = readl( fcChip->Registers.TYstatus.address ); break;/* case 2: // freeze SCSI case 3: // reset Outbound command que (ERQ) case 4: // unfreeze OSM (Outbound Seq. Man.) 'er' case 5: // report status break;*/ default: ret_status = -1; // invalid option passed to RESET function break; } LEAVE("ResetTach"); return ret_status;}// 'addrBase' is IOBaseU for both TachLite and (older) Tachyonint CpqTsLaserControl( void* addrBase, int opcode ){ ULONG dwBuff; dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg // (change only bit 4) if( opcode == 1) dwBuff |= ~0xffffffefL; // set - ON else dwBuff &= 0xffffffefL; // clear - OFF writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg return 0;}// Use controller's "Options" field to determine loopback mode (if any)// internal loopback (silicon - no GBIC)// external loopback (GBIC - no FC loop)// no loopback: L_PORT, external cable from GBIC requiredint CpqTsInitializeFrameManager( void *pChip, int opcode){ PTACHYON fcChip; int iStatus; ULONG wwnLo, wwnHi; // for readback verification ENTER("InitializeFrameManager"); fcChip = (PTACHYON)pChip; if( !fcChip->Registers.ReMapMemBase ) // undefined controller? return -1; // TL/TS UG, pg. 184 // 0x0065 = 100ms for RT_TOV // 0x01f5 = 500ms for ED_TOV // 0x07D1 = 2000ms fcChip->Registers.ed_tov.value = 0x006507D1; writel( fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address)); // Set LP_TOV to the FC-AL2 specified 2 secs. // TL/TS UG, pg. 185 writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2); // Now try to read the WWN from the adapter's NVRAM iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ if( iStatus ) // NVRAM read failed? { printk(" WARNING! HBA NVRAM WWN read failed - make alias\n"); // make up a WWN. If NULL or duplicated on loop, FC loop may hang! fcChip->Registers.wwn_hi = (__u32)jiffies; fcChip->Registers.wwn_hi |= 0x50000000L; fcChip->Registers.wwn_lo = 0x44556677L; } writel( fcChip->Registers.wwn_hi, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI); writel( fcChip->Registers.wwn_lo, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO); // readback for verification: wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO); // test for correct chip register WRITE/READ DEBUG_PCI( printk(" WWN %08X%08X\n", fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) ); if( wwnHi != fcChip->Registers.wwn_hi || wwnLo != fcChip->Registers.wwn_lo ) { printk( "cpqfcTS: WorldWideName register load failed\n"); return -1; // FAILED! } // set Frame Manager Initialize command fcChip->Registers.FMcontrol.value = 0x06; // Note: for test/debug purposes, we may use "Hard" address, // but we completely support "soft" addressing, including // dynamically changing our address. if( fcChip->Options.intLoopback == 1 ) // internal loopback fcChip->Registers.FMconfig.value = 0x0f002080L; else if( fcChip->Options.extLoopback == 1 ) // internal loopback fcChip->Registers.FMconfig.value = 0x0f004080L; else // L_Port fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)// fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)// fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start) // write config to FM if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback ) // (also need LASER for real LOOP) fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER writel( fcChip->Registers.FMconfig.value, fcChip->Registers.FMconfig.address); // issue INITIALIZE command to FM - ACTION! writel( fcChip->Registers.FMcontrol.value, fcChip->Registers.FMcontrol.address); LEAVE("InitializeFrameManager"); return 0;}// This "look ahead" function examines the IMQ for occurence of// "type". Returns 1 if found, 0 if not.static int PeekIMQEntry( PTACHYON fcChip, ULONG type){ ULONG CI = fcChip->IMQ->consumerIndex; ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes while( CI != PI ) { // proceed with search if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check switch( type ) { case ELS_LILP_FRAME: { // first, we need to find an Inbound Completion message, // If we find it, check the incoming frame payload (1st word) // for LILP frame if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 ) { TachFCHDR_GCMND* fchs; ULONG ulFibreFrame[2048/4]; // max DWORDS in incoming FC Frame USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL); CpqTsGetSFQEntry( fcChip, SFQpi, // SFQ producer ndx ulFibreFrame, // contiguous dest. buffer FALSE); // DON'T update chip--this is a "lookahead" fchs = (TachFCHDR_GCMND*)&ulFibreFrame; if( fchs->pl[0] == ELS_LILP_FRAME) { return 1; // found the LILP frame! } else { // keep looking... } } } break; case OUTBOUND_COMPLETION: if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 ) { // any OCM errors? if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L ) return 1; // found OCM error } break; default: break; } } return 0; // failed to find "type"} static void SetTachTOV( CPQFCHBA* cpqfcHBAdata){ PTACHYON fcChip = &cpqfcHBAdata->fcChip; // TL/TS UG, pg. 184 // 0x0065 = 100ms for RT_TOV // 0x01f5 = 500ms for ED_TOV // 0x07d1 = 2000ms for ED_TOV // SANMark Level 1 requires an "initialization backoff" // (See "SANMark Test Suite Level 1": // initialization_timeout.fcal.SANMark-1.fc) // We have to use 2sec, 24sec, then 128sec when login/ // port discovery processes fail to complete. // when port discovery completes (logins done), we set // ED_TOV to 500ms -- this is the normal operational case // On the first Link Down, we'll move to 2 secs (7D1 ms) if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5) fcChip->Registers.ed_tov.value = 0x006507D1; // If we get another LST after we moved TOV to 2 sec, // increase to 24 seconds (5DC1 ms) per SANMark! else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1) fcChip->Registers.ed_tov.value = 0x00655DC1; // If we get still another LST, set the max TOV (Tachyon // has only 16 bits for ms timer, so the max is 65.5 sec) else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1) fcChip->Registers.ed_tov.value = 0x0065FFFF; writel( fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address)); // keep the same 2sec LP_TOV writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);} // The IMQ is an array with IMQ_LEN length, each element (QEntry)// with eight 32-bit words. Tachyon PRODUCES a QEntry with each// message it wants to send to the host. The host CONSUMES IMQ entries// This function copies the current// (or oldest not-yet-processed) QEntry to// the caller, clears/ re-enables the interrupt, and updates the// (Host) Consumer Index.// Return value:// 0 message processed, none remain (producer and consumer// indexes match)// 1 message processed, more messages remain// -1 no message processed - none were available to process// Remarks:// TL/TS UG specifices that the following actions for// INTA_L handling:// 1. read PCI Interrupt Status register (0xff)// 2. all IMQ messages should be processed before writing the// IMQ consumer index.int CpqTsProcessIMQEntry(void *host){ struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host; CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; int iStatus; USHORT i, RPCset, DPCset; ULONG x_ID; ULONG ulBuff, dwStatus; TachFCHDR_GCMND* fchs; ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field ENTER("ProcessIMQEntry"); // check TachLite's IMQ producer index - // is a new message waiting for us? // equal indexes means empty que if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex ) { // need to process message#ifdef IMQ_DEBUG printk("PI %X, CI %X type: %X\n", fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex, fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);#endif // Examine Completion Messages in IMQ // what CM_Type? switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type & 0xffL) ) { case OUTBOUND_COMPLETION: // Remarks: // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries // (starting at 0), and SFS entries (starting at // SEST_LEN -- outside the SEST space). // Psuedo code: // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index // range check - x_ID // if x_ID outside 'Transactions' length, error - exit // if any OCM error, copy error status to Exchange slot // if FCP ASSIST transaction (x_ID within SEST), // call fcComplete (to App) // ... ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]; x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID // Range check CM OX/RX_ID value... if( x_ID < TACH_MAX_XID ) // don't go beyond array space { if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete? RPCset = 1; // (SEST transactions only) else RPCset = 0; if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete? DPCset = 1; // (SEST transactions only) else DPCset = 0; // set the status for this Outbound transaction's ID dwStatus = 0L; if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error) dwStatus |= SESTPROG_ERR; ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]; if( ulBuff & 0x7a000000L ) // any other errs? { if( ulBuff & 0x40000000L ) dwStatus |= INV_ENTRY; if( ulBuff & 0x20000000L ) dwStatus |= FRAME_TO; // FTO if( ulBuff & 0x10000000L ) dwStatus |= HOSTPROG_ERR; if( ulBuff & 0x08000000L ) dwStatus |= LINKFAIL_TX; if( ulBuff & 0x02000000L ) dwStatus |= ABORTSEQ_NOTIFY; // ASN } if( dwStatus ) // any errors? { // set the Outbound Completion status Exchanges->fcExchange[ x_ID ].status |= dwStatus; // if this Outbound frame was for a SEST entry, automatically // reque it in the case of LINKFAIL (it will restart on PDISC) if( x_ID < TACH_SEST_LEN ) { printk(" #OCM error %Xh x_ID %X# ", dwStatus, x_ID); Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default // We Q ABTS for each exchange. // NOTE: We can get FRAME_TO on bad alpa (device gone). Since
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -