📄 cpqfctscontrol.c
字号:
// bad alpa is reported before FRAME_TO, examine the status // flags to see if the device is removed. If so, DON'T // post an ABTS, since it will be terminated by the bad alpa // message. if( dwStatus & FRAME_TO ) // check for device removed... { if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) ) { // presumes device is still there: send ABTS. cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID); } } else // Abort all other errors { cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID); } // if the HPE bit is set, we have to CLose the LOOP // (see TL/TS UG, pg. 239) if( dwStatus &= HOSTPROG_ERR ) // set CL bit (see TL/TS UG, pg. 172) writel( 4, fcChip->Registers.FMcontrol.address); } } // NOTE: we don't necessarily care about ALL completion messages... // SCSI resp. complete OR if( ((x_ID < TACH_SEST_LEN) && RPCset)|| (x_ID >= TACH_SEST_LEN) ) // non-SCSI command { // exchange done; complete to upper levels with status // (if necessary) and free the exchange slot if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame? // A Request or Reply has been sent { // signal waiting WorkerThread up( cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach // WorkerThread will complete Xchng } else // X_ID is for FCP assist (SEST) { // TBD (target mode)// fcCompleteExchange( fcChip, x_ID); // TRE completed } } } else // ERROR CONDITION! bogus x_ID in completion message { printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID); } // Load the Frame Manager's error counters. We check them here // because presumably the link is up and healthy enough for the // counters to be meaningful (i.e., don't check them while loop // is initializing). fcChip->Registers.FMLinkStatus1.value = // get TL's counter readl(fcChip->Registers.FMLinkStatus1.address); fcChip->Registers.FMLinkStatus2.value = // get TL's counter readl(fcChip->Registers.FMLinkStatus2.address); fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators break; case ERROR_IDLE_COMPLETION: // TachLite Error Idle... // We usually get this when the link goes down during heavy traffic. // For now, presume that if SEST Exchanges are open, we will // get this as our cue to INVALIDATE all SEST entries // (and we OWN all the SEST entries). // See TL/TS UG, pg. 53 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) { // Does this VALid SEST entry need to be invalidated for Abort? fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; } CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK break; case INBOUND_SFS_COMPLETION: //0x04 // NOTE! we must process this SFQ message to avoid SFQ filling // up and stopping TachLite. Incoming commands are placed here, // as well as 'unknown' frames (e.g. LIP loop position data) // write this CM's producer index to global... // TL/TS UG, pg 234: // Type: 0 - reserved // 1 - Unassisted FCP // 2 - BAD FCP // 3 - Unkown Frame // 4-F reserved fcChip->SFQ->producerIndex = (USHORT) (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL); ucInboundMessageType = 0; // default to useless frame // we can only process two Types: 1, Unassisted FCP, and 3, Unknown // Also, we aren't interested in processing frame fragments // so don't Que anything with 'LKF' bit set if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x40000000) ) // 'LKF' link failure bit clear? { ucInboundMessageType = (UCHAR) // ICM DWord3, "Type" (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL); } else { fcChip->fcStats.linkFailRX++;// printk("LKF (link failure) bit set on inbound message\n"); } // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff CpqTsGetSFQEntry( fcChip, // i.e. this Device Object (USHORT)fcChip->SFQ->producerIndex, // SFQ producer ndx ulFibreFrame, TRUE); // contiguous destination buffer, update chip // analyze the incoming frame outside the INT handler... // (i.e., Worker) if( ucInboundMessageType == 1 ) { fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame // don't fill up our Q with garbage - only accept FCP-CMND // or XRDY frames if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND { // someone sent us a SCSI command // fcPutScsiQue( cpqfcHBAdata, // SFQ_UNASSISTED_FCP, ulFibreFrame); } else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status) (fchs->d_id & 0xFF000000) == 0x05000000 ) // XRDY { ULONG x_ID; // Unfortunately, ABTS requires a Freeze on the chip so // we can modify the shared memory SEST. When frozen, // any received Exchange frames cannot be processed by // Tachyon, so they will be dumped in here. It is too // complex to attempt the reconstruct these frames in // the correct Exchange context, so we simply seek to // find status or transfer ready frames, and cause the // exchange to complete with errors before the timeout // expires. We use a Linux Scsi Cmnd result code that // causes immediate retry. // Do we have an open exchange that matches this s_id // and ox_id? for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) { if( (fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) && (fchs->ox_rx_id & 0xFFFF0000) == (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) ) { // printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id ); // simulate the anticipated error - since the // SEST was frozen, frames were lost... Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME; // presumes device is still there: send ABTS. cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID); break; // done } } } } else if( ucInboundMessageType == 3) { // FC Link Service frames (e.g. PLOGI, ACC) come in here. cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); } else if( ucInboundMessageType == 2 ) // "bad FCP"? {#ifdef IMQ_DEBUG printk("Bad FCP incoming frame discarded\n");#endif } else // don't know this type {#ifdef IMQ_DEBUG printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);#endif } // Check the Frame Manager's error counters. We check them here // because presumably the link is up and healthy enough for the // counters to be meaningful (i.e., don't check them while loop // is initializing). fcChip->Registers.FMLinkStatus1.value = // get TL's counter readl(fcChip->Registers.FMLinkStatus1.address); fcChip->Registers.FMLinkStatus2.value = // get TL's counter readl(fcChip->Registers.FMLinkStatus2.address); break; // We get this CM because we issued a freeze // command to stop outbound frames. We issue the // freeze command at Link Up time; when this message // is received, the ERQ base can be switched and PDISC // frames can be sent. case ERQ_FROZEN_COMPLETION: // note: expect ERQ followed immediately // by FCP when freezing TL fcChip->Registers.TYstatus.value = // read what's frozen readl(fcChip->Registers.TYstatus.address); // (do nothing; wait for FCP frozen message) break; case FCP_FROZEN_COMPLETION: fcChip->Registers.TYstatus.value = // read what's frozen readl(fcChip->Registers.TYstatus.address); // Signal the kernel thread to proceed with SEST modification up( cpqfcHBAdata->TachFrozen); break; case INBOUND_C1_TIMEOUT: case MFS_BUF_WARN: case IMQ_BUF_WARN: break; // In older Tachyons, we 'clear' the internal 'core' interrupt state // by reading the FMstatus register. In newer TachLite (Tachyon), // we must WRITE the register // to clear the condition (TL/TS UG, pg 179) case FRAME_MGR_INTERRUPT: { PFC_LOGGEDIN_PORT pLoggedInPort; fcChip->Registers.FMstatus.value = readl( fcChip->Registers.FMstatus.address ); // PROBLEM: It is possible, especially with "dumb" hubs that // don't automatically LIP on by-pass of ports that are going // away, for the hub by-pass process to destroy critical // ordered sets of a frame. The result of this is a hung LPSM // (Loop Port State Machine), which on Tachyon results in a // (default 2 sec) Loop State Timeout (LST) FM message. We // want to avoid this relatively huge timeout by detecting // likely scenarios which will result in LST. // To do this, we could examine FMstatus for Loss of Synchronization // and/or Elastic Store (ES) errors. Of these, Elastic Store is better // because we get this indication more quickly than the LOS. // Not all ES errors are harmfull, so we don't want to LIP on every // ES. Instead, on every ES, detect whether our LPSM in in one // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE, // or RECEIVED CLOSE. (See TL/TS UG, pg. 181) // If any of these LPSM states are detected // in combination with the LIP while LDn is not set, // send an FM init (LIP F7,F7 for loops)! // It is critical to the physical link stability NOT to reset (LIP) // more than absolutely necessary; this is a basic premise of the // SANMark level 1 spec. { ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4; if( (fcChip->Registers.FMstatus.value & 0x400) // ElasticStore? && !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn && !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF { if( (Lpsm != 0) || // not MONITORING? or !(Lpsm & 0x8) )// not already offline? { // now check the particular LST states... if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) || (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) || (Lpsm == RCVD_CLOSE) ) { // re-init the loop before it hangs itself! printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm); fcChip->fcStats.FMinits++; writel( 6, fcChip->Registers.FMcontrol.address); // LIP } } } else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST? { printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm); fcChip->fcStats.FMinits++; writel( 6, fcChip->Registers.FMcontrol.address); // LIP } } // clear only the 'interrupting' type bits for this REG read writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L), fcChip->Registers.FMstatus.address); // copy frame manager status to unused ULONG slot fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] = fcChip->Registers.FMstatus.value; // (for debugging) // Load the Frame Manager's error counters. We check them here // because presumably the link is up and healthy enough for the // counters to be meaningful (i.e., don't check them while loop // is initializing). fcChip->Registers.FMLinkStatus1.value = // get TL's counter readl(fcChip->Registers.FMLinkStatus1.address); fcChip->Registers.FMLinkStatus2.value = // get TL's counter readl(fcChip->Registers.FMLinkStatus2.address); // Get FM BB_Credit Zero Reg - does not clear on READ fcChip->Registers.FMBB_CreditZero.value = // get TL's counter readl(fcChip->Registers.FMBB_CreditZero.address); fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators // LINK DOWN if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit { #ifdef IMQ_DEBUG printk("LinkDn\n");#endif printk(" #LDn# "); fcChip->fcStats.linkDown++; SetTachTOV( cpqfcHBAdata); // must set according to SANMark // Check the ERQ - force it to be "empty" to prevent Tach // from sending out frames before we do logins. if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex) {// printk("#ERQ PI != CI#"); CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0; writel( fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE)); // re-writing base forces ERQ PI to equal CI } // link down transition occurred -- port_ids can change // on next LinkUp, so we must invalidate current logins // (and any I/O in progress) until PDISC or PLOGI/PRLI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -