📄 cpqfctscontrol.c
字号:
// NOTE: according to TL/TS UG, the // "host must return completion messages in sequential order". // Does this mean one at a time, in the order received? We // presume so. writel( fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX)); #if IMQ_DEBUG printk("Process IMQ: writing consumer ndx %d\n ", fcChip->IMQ->consumerIndex); printk("PI %X, CI %X\n", fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );#endif } else { // hmmm... why did we get interrupted/called with no message? iStatus = -1; // nothing to process#if IMQ_DEBUG printk("Process IMQ: no message PI %Xh CI %Xh", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);#endif } LEAVE("ProcessIMQEntry"); return iStatus;}// This routine initializes Tachyon according to the following// options (opcode1):// 1 - RESTART Tachyon, simulate power on condition by shutting// down laser, resetting the hardware, de-allocating all buffers;// continue// 2 - Config Tachyon / PCI registers;// continue// 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);// continue// 4 - Config frame manager registers, initialize, turn on laser//// Returns:// -1 on fatal error// 0 on successint CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2){ CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; PTACHYON fcChip = &cpqfcHBAdata->fcChip; ULONG ulBuff; UCHAR bBuff; int iStatus=-1; // assume failure ENTER("InitializeTachLite"); // verify board's base address (sanity check) if( !fcChip->Registers.ReMapMemBase) // NULL address for card? return -1; // FATAL error! switch( opcode1 ) { case 1: // restore hardware to power-on (hard) restart iStatus = fcChip->ResetTachyon( cpqfcHBAdata, opcode2); // laser off, reset hardware // de-allocate aligned buffers/* TBD // reset FC link Q (producer and consumer = 0) fcLinkQReset(cpqfcHBAdata); */ if( iStatus ) break; case 2: // Config PCI/Tachyon registers // NOTE: For Tach TL/TS, bit 31 must be set to 1. For TS chips, a read // of bit 31 indicates state of M66EN signal; if 1, chip may run at // 33-66MHz (see TL/TS UG, pg 159) ulBuff = 0x80000000; // TachLite Configuration Register writel( ulBuff, fcChip->Registers.TYconfig.address);// ulBuff = 0x0147L; // CpqTs PCI CFGCMD register// WritePCIConfiguration( fcChip->Backplane.bus,// fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);// ulBuff = 0x0L; // test!// ReadPCIConfiguration( fcChip->Backplane.bus,// fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4); // read back for reference... fcChip->Registers.TYconfig.value = readl( fcChip->Registers.TYconfig.address ); // what is the PCI bus width? pci_read_config_byte( cpqfcHBAdata->PciDev, 0x43, // PCIMCTR offset &bBuff); fcChip->Registers.PCIMCTR = bBuff; // set string identifying the chip on the circuit board fcChip->Registers.TYstatus.value = readl( fcChip->Registers.TYstatus.address); {// Now that we are supporting multiple boards, we need to change// this logic to check for PCI vendor/device IDs...// for now, quick & dirty is simply checking Chip rev ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5; UCHAR Minor = (UCHAR)(RevId & 0x3); UCHAR Major = (UCHAR)((RevId & 0x1C) >>2); printk(" HBA Tachyon RevId %d.%d\n", Major, Minor); if( (Major == 1) && (Minor == 2) ) { sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12); } else if( (Major == 1) && (Minor == 3) ) { sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13); } else if( (Major == 2) && (Minor == 1) ) { sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21); } else sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN); } case 3: // allocate mem, set Tachyon Que registers iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2); // now that the Queues exist, Tach can DMA to them, so // we can begin processing INTs // INTEN register - enable INT (TachLite interrupt) writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN); if( iStatus ) break; case 4: // Config Fame Manager, Init Loop Command, laser on // L_PORT or loopback // depending on Options iStatus = CpqTsInitializeFrameManager( fcChip,0 ); if( iStatus ) { // failed to initialize Frame Manager break; } default: break; } LEAVE("InitializeTachLite"); return iStatus;}// Depending on the type of platform memory allocation (e.g. dynamic),// it's probably best to free memory in opposite order as it was allocated.// Order of allocation: see other functionint CpqTsDestroyTachLiteQues( void *pHBA, int opcode){ CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; PTACHYON fcChip = &cpqfcHBAdata->fcChip; USHORT i, j, iStatus=0; void* vPtr; // mem Align manager sets this to the freed address on success unsigned long ulPtr; // for 64-bit pointer cast (e.g. Alpa machine) ENTER("DestroyTachLiteQues"); if( fcChip->SEST ) { // search out and free Pool for Extended S/G list pages for( i=0, j=0; i < TACH_SEST_LEN; i++, j=0) // for each exchange { // It's possible that extended S/G pages were allocated and // not cleared due to error conditions or O/S driver termination. // Make sure they're all gone. while( fcChip->SEST->sgPages[i].PoolPage[j] && (j < TL_MAX_SGPAGES)) kfree( fcChip->SEST->sgPages[i].PoolPage[j++]); } ulPtr = (unsigned long)fcChip->SEST; vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], 0,0, (ULONG)ulPtr ); // 'free' mem fcChip->SEST = 0L; // null invalid ptr if( !vPtr ) { printk("SEST mem not freed\n"); iStatus = -1; } } if( fcChip->SFQ ) { ulPtr = (unsigned long)fcChip->SFQ; vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], 0,0, (ULONG)ulPtr ); // 'free' mem fcChip->SFQ = 0L; // null invalid ptr if( !vPtr ) { printk("SFQ mem not freed\n"); iStatus = -2; } } if( fcChip->IMQ ) { // clear Indexes to show empty Queue fcChip->IMQ->producerIndex = 0; fcChip->IMQ->consumerIndex = 0; ulPtr = (unsigned long)fcChip->IMQ; vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], 0,0, (ULONG)ulPtr ); // 'free' mem fcChip->IMQ = 0L; // null invalid ptr if( !vPtr ) { printk("IMQ mem not freed\n"); iStatus = -3; } } if( fcChip->ERQ ) // release memory blocks used by the queues { ulPtr = (unsigned long)fcChip->ERQ; vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], 0,0, (ULONG)ulPtr ); // 'free' mem fcChip->ERQ = 0L; // null invalid ptr if( !vPtr ) { printk("ERQ mem not freed\n"); iStatus = -4; } } // free up the primary EXCHANGES struct if( fcChip->Exchanges != NULL) {// printk("kfree() on Exchanges @%p\n", fcChip->Exchanges); kfree( fcChip->Exchanges); } // free up Link Q if( cpqfcHBAdata->fcLQ != NULL ) {// printk("kfree() on LinkQ @%p\n", fcChip->fcLQ); kfree( cpqfcHBAdata->fcLQ); } LEAVE("DestroyTachLiteQues"); return iStatus; // non-zero (failed) if any memory not freed}// The SFQ is an array with SFQ_LEN length, each element (QEntry)// with eight 32-bit words. TachLite places incoming FC frames (i.e.// a valid FC frame with our AL_PA ) in contiguous SFQ entries// and sends a completion message telling the host where the frame is// in the que.// This function copies the current (or oldest not-yet-processed) QEntry to// a caller's contiguous buffer and updates the Tachyon chip's consumer index//// NOTE:// An FC frame may consume one or many SFQ entries. We know the total// length from the completion message. The caller passes a buffer large// enough for the complete message (max 2k).static void CpqTsGetSFQEntry( PTACHYON fcChip, USHORT producerNdx, ULONG *ulDestPtr, // contiguous destination buffer BOOLEAN UpdateChip){ ULONG total_bytes=0; ULONG consumerIndex = fcChip->SFQ->consumerIndex; // check passed copy of SFQ producer index - // is a new message waiting for us? // equal indexes means SFS is copied while( producerNdx != consumerIndex ) { // need to process message total_bytes += 64; // maintain count to prevent writing past buffer // don't allow copies over Fibre Channel defined length! if( total_bytes <= 2048 ) { memcpy( ulDestPtr, &fcChip->SFQ->QEntry[consumerIndex], 64 ); // each SFQ entry is 64 bytes ulDestPtr += 16; // advance pointer to next 64 byte block } // Tachyon is producing, // and we are consuming if( ++consumerIndex >= SFQ_LEN)// check for rollover consumerIndex = 0L; // reset it } // if specified, update the Tachlite chip ConsumerIndex... if( UpdateChip ) { fcChip->SFQ->consumerIndex = consumerIndex; writel( fcChip->SFQ->consumerIndex, fcChip->Registers.SFQconsumerIndex.address); }}// TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,// and Exchange Request Queue (ERQ) on error recover - // (e.g. whenever a LIP occurs). Here// we routinely RESUME by clearing these bits, but only if the loop is up// to avoid ERROR IDLE messages forever.void CpqTsUnFreezeTachlite( void *pChip, int type ){ PTACHYON fcChip = (PTACHYON)pChip; fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address); // (bit 4 of value is GBIC LASER) // if we 'unfreeze' the core machines before the loop is healthy // (i.e. FLT, OS, LS failure bits set in FMstatus) // we can get 'error idle' messages forever. Verify that // FMstatus (Link Status) is OK before unfreezing. if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear? !(fcChip->Registers.FMstatus.value & 0x80 )) // Active LPSM? { fcChip->Registers.TYcontrol.value &= ~0x300L; // clear FEQ, FFA if( type == 1 ) // unfreeze ERQ only {// printk("Unfreezing ERQ\n"); fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ } else // unfreeze both ERQ and FCP-ASSIST (SEST) {// printk("Unfreezing ERQ & FCP-ASSIST\n"); // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ } writel( fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address); } // readback for verify (TachLite still frozen?) fcChip->Register
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -