📄 cpqfctsworker.c
字号:
if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn { printk("Discard Q'd ELS login frame\n"); break; } ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI (TachFCHDR_GCMND*) fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs NULL, // no data (no scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed if( !ulStatus ) // Exchange setup? { ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); if( !ulStatus ) { // submitted to Tach's Outbound Que (ERQ PI incremented) // waited for completion for ELS type (Login frames issued // synchronously) } else // check reason for Exchange not being started - we might // want to Queue and start later, or fail with error { } } else // Xchange setup failed... printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus ); break; case SCSI_REPORT_LUNS: // pass the incoming frame (actually, it's a PRLI frame) // so we can send REPORT_LUNS, in order to determine VSA/PDU // FCP-SCSI Lun address mode IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*) fcLQ->Qitem[QconsumerNdx].ulBuff); break; case BLS_ABTS: // need to ABORT one or more exchanges { LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0]; BOOLEAN FrozeTach = FALSE; if( x_ID > TACH_SEST_LEN ) // (in)sanity check {// printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID); break; } if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE {// printk(" ABTS %Xh Scsi Cmnd null! ", x_ID); break; // nothing to abort! }//#define ABTS_DBG#ifdef ABTS_DBG printk("INV SEST[%X] ", x_ID); if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) { printk("FC2TO"); } if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) { printk("IA"); } if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) { printk("PORTID"); } if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) { printk("DEVRM"); } if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) { printk("LKF"); } if( Exchanges->fcExchange[x_ID].status & FRAME_TO) { printk("FRMTO"); } if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) { printk("ABSQ"); } if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME) { printk("SFQFR"); } if( Exchanges->fcExchange[ x_ID].type == 0x2000) printk(" WR"); else if( Exchanges->fcExchange[ x_ID].type == 0x3000) printk(" RD"); else if( Exchanges->fcExchange[ x_ID].type == 0x10) printk(" ABTS"); else printk(" %Xh", Exchanges->fcExchange[ x_ID].type); if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) { printk(" Cmd %p, ", Exchanges->fcExchange[ x_ID].Cmnd); printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", cpqfcHBAdata->HBAnum, Exchanges->fcExchange[ x_ID].Cmnd->channel, Exchanges->fcExchange[ x_ID].Cmnd->target, Exchanges->fcExchange[ x_ID].Cmnd->lun, Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF); } else // assume that Cmnd ptr is invalid on _abort() { printk(" Cmd ptr invalid\n"); } #endif // Steps to ABORT a SEST exchange: // 1. Freeze TL SCSI assists & ERQ (everything) // 2. Receive FROZEN inbound CM (must succeed!) // 3. Invalidate x_ID SEST entry // 4. Resume TL SCSI assists & ERQ (everything) // 5. Build/start on exchange - change "type" to BLS_ABTS, // timeout to X sec (RA_TOV from PLDA is actually 0) // 6. Set Exchange Q'd status if ABTS cannot be started, // or simply complete Exchange in "Terminate" condition PCI_TRACEO( x_ID, 0xB4) // 1 & 2 . Freeze Tach & get confirmation of freeze FrozeTach = FreezeTach( cpqfcHBAdata); // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange. // FC2_TIMEOUT means we are originating the abort, while // TARGET_ABORT means we are ACCepting an abort. // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are // all from Tachyon: // Exchange was corrupted by LDn or other FC physical failure // INITIATOR_ABORT means the upper layer driver/application // requested the abort. // clear bit 31 (VALid), to invalidate & take control from TL fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; // examine and Tach's "Linked List" for IWEs that // received (nearly) simultaneous transfer ready (XRDY) // repair linked list if necessary (TBD!) // (If we ignore the "Linked List", we will time out // WRITE commands where we received the FCP-SCSI XFRDY // frame (because Tachyon didn't processes it). Linked List // management should be done as an optimization.// readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST )); // 4. Resume all Tachlite functions (for other open Exchanges) // as quickly as possible to allow other exchanges to other ports // to resume. Freezing Tachyon may cause cascading errors, because // any received SEST frame cannot be processed by the SEST. // Don't "unfreeze" unless Link is operational if( FrozeTach ) // did we just freeze it (above)? fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists PCI_TRACEO( x_ID, 0xB4) // Note there is no confirmation that the chip is "unfrozen". Also, // if the Link is down when unfreeze is called, it has no effect. // Chip will unfreeze when the Link is back up. // 5. Now send out Abort commands if possible // Some Aborts can't be "sent" (Port_id changed or gone); // if the device is gone, there is no port_id to send the ABTS to. if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED) && !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) ) { Exchanges->fcExchange[ x_ID].type = BLS_ABTS; fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id; ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, BLS_ABTS, &fchs, // (uses only s_id) NULL, // (no scatter/gather list for ABTS) &x_ID );// ABTS on this Exchange ID if( !ulStatus ) // Exchange setup build OK? { // ABTS may be needed because an Exchange was corrupted // by a Link disruption. If the Link is UP, we can // presume that this ABTS can start immediately; otherwise, // set Que'd status so the Login functions // can restart it when the FC physical Link is restored if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init? { // printk(" *set Q status x_ID %Xh on LDn* ", x_ID); Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED; } else // what FC device (port_id) does the Cmd belong to? { PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[ x_ID].pLoggedInPort; // if Port is logged in, we might start the abort. if( (pLoggedInPort != NULL) && (pLoggedInPort->prli == TRUE) ) { // it's possible that an Exchange has already been Queued // to start after Login completes. Check and don't // start it (again) here if Q'd status set// printk(" ABTS xchg %Xh ", x_ID); if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) {// printk("already Q'd "); } else {// printk("starting "); fcChip->fcStats.FC2aborted++; ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID ); if( !ulStatus ) { // OK // submitted to Tach's Outbound Que (ERQ PI incremented) } else {/* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", ulStatus, x_ID);*/ } } } else {/* printk(" ABTS NOT starting xchg %Xh, %p ", x_ID, pLoggedInPort); if( pLoggedInPort ) printk("prli %d ", pLoggedInPort->prli);*/ } } } else // what the #@! { // how do we fail to build an Exchange for ABTS?? printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", ulStatus, x_ID); } } else // abort without ABTS -- just complete exchange/Cmnd to Linux {// printk(" *Terminating x_ID %Xh on %Xh* ", // x_ID, Exchanges->fcExchange[x_ID].status); cpqfcTSCompleteExchange( fcChip, x_ID); } } // end of ABTS case break; case BLS_ABTS_ACC: // need to ACCept one ABTS // (NOTE! this code not updated for Linux yet..) printk(" *ABTS_ACC* "); // 1. Freeze TL fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists memcpy( // copy the incoming ABTS frame &fchs, fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs sizeof( fchs)); // 3. OK, Tachyon is frozen so we can invalidate SEST entry // (if necessary) // Status FC2_TIMEOUT means we are originating the abort, while // TARGET_ABORT means we are ACCepting an abort ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange// printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID); // sanity check on received ExchangeID if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT ) { // clear bit 31 (VALid), to invalidate & take control from TL// printk("Invalidating SEST exchange %Xh\n", ExchangeID); fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF; } // 4. Resume all Tachlite functions (for other open Exchanges) // as quickly as possible to allow other exchanges to other ports // to resume. Freezing Tachyon for too long may royally screw // up everything! fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists // Note there is no confirmation that the chip is "unfrozen". Also, // if the Link is down when unfreeze is called, it has no effect. // Chip will unfreeze when the Link is back up. // 5. Now send out Abort ACC reply for this exchange Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC; fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id; ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, BLS_ABTS_ACC, &fchs, NULL, // no data (no scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed if( !ulStatus ) // Exchange setup? { ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); if( !ulStatus ) { // submitted to Tach's Outbound Que (ERQ PI incremented) // waited for completion for ELS type (Login frames issued // synchronously) } else // check reason for Exchange not being started - we might // want to Queue and start later, or fail with error { } } break; case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the // exchange doesn't exist in the TARGET context. // ExchangeID has to come from LinkService space. printk(" *ABTS_RJT* "); ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, BLS_ABTS_RJT, (TachFCHDR_GCMND*) fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs NULL, // no data (no scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed if( !ulStatus ) // Exchange setup OK? { ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); // If it fails, we aren't required to retry. } if( ulStatus ) { printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID); } else { printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID); } break; default: break; } // end switch//doNothing: // done with this item - now set the NEXT index if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test { fcLQ->consumer = 0; } else { fcLQ->consumer++; } PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94) LEAVE("WorkTask"); return;}// When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)// commands come in, post to the LinkQ so that action can be taken outside the// interrupt handler. // This circular Q works like Tachyon's que - the producer points to the next// (unused) entry. Called by Interrupt handler, WorkerThread, Timer// sputlinkqvoid cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata, int Type, void *QueContent){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -