📄 cpqfctsworker.c
字号:
}}static void ProcessELS_Reply( CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs){ PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; ULONG ox_id = (fchs->ox_rx_id >>16); ULONG ls_reject_code; PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort; // If this is a valid reply, then we MUST have sent a request. // Verify that we can find a valid request OX_ID corresponding to // this reply if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0) { printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff); goto Quit; // exit this routine } // Is the reply a RJT (reject)? if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply? {// ****** REJECT REPLY ******** switch( Exchanges->fcExchange[ox_id].type ) { case ELS_FDISC: // we sent out Fabric Discovery case ELS_FLOGI: // we sent out FLOGI printk("RJT received on Fabric Login from %Xh, reason %Xh\n", fchs->s_id, fchs->pl[1]); break; default: break; } goto Done; } // OK, we have an ACCept... // What's the ACC type? (according to what we sent) switch( Exchanges->fcExchange[ox_id].type ) { case ELS_PLOGI: // we sent out PLOGI if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) { LOGIN_PAYLOAD logi; // FC-PH Port Login // login ACC payload acceptable; search for WWN in our list // of fcPorts BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); pLoggedInPort = fcFindLoggedInPort( fcChip, NULL, // don't search Scsi Nexus 0, // don't search linked list for port_id &logi.port_name[0], // search linked list for WWN &pLastLoggedInPort); // must return non-NULL; when a port_id // is not found, this pointer marks the // end of the singly linked list if( pLoggedInPort == NULL) // WWN not found - new port { pLoggedInPort = CreateFcPort( cpqfcHBAdata, pLastLoggedInPort, fchs, &logi); if( pLoggedInPort == NULL ) { printk(" cpqfcTS: New port allocation failed - lost FC device!\n"); // Now Q a LOGOut Request, since we won't be talking to that device goto Done; // exit with error! dropped login frame } } else // WWN was already known. Ensure that any open // exchanges for this WWN are terminated. // NOTE: It's possible that a device can change its // 24-bit port_id after a Link init or Fabric change // (e.g. LIP or Fabric RSCN). In that case, the old // 24-bit port_id may be duplicated, or no longer exist. { cpqfcTSTerminateExchange( cpqfcHBAdata, &pLoggedInPort->ScsiNexus, PORTID_CHANGED); } // We have an fcPort struct - set fields accordingly // not PDISC, originator SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE); // We just set a "port_id"; is it duplicated? TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort); // For Fabric operation, we issued PLOGI to 0xFFFFFC // so we can send SCR (State Change Registration) // Check for this special case... if( fchs->s_id == 0xFFFFFC ) { // PLOGI ACC was a Fabric response... issue SCR fchs->s_id = 0xFFFFFD; // address for SCR cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs); } else { // Now we need a PRLI to enable FCP-SCSI operation // set flags and Q up a ELS_PRLI cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs); } } else { // login payload unacceptable - reason in ls_reject_code // Q up a Logout Request printk("Login Payload unacceptable\n"); } break; // PDISC logic very similar to PLOGI, except we never want // to allocate mem for "new" port, and we set flags differently // (might combine later with PLOGI logic for efficiency) case ELS_PDISC: // we sent out PDISC if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) { LOGIN_PAYLOAD logi; // FC-PH Port Login BOOLEAN NeedLogin = FALSE; // login payload acceptable; search for WWN in our list // of (previously seen) fcPorts BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); pLoggedInPort = fcFindLoggedInPort( fcChip, NULL, // don't search Scsi Nexus 0, // don't search linked list for port_id &logi.port_name[0], // search linked list for WWN &pLastLoggedInPort); // must return non-NULL; when a port_id // is not found, this pointer marks the // end of the singly linked list if( pLoggedInPort != NULL) // WWN found? { // WWN has same port_id as last login? (Of course, a properly // working FC device should NEVER ACCept a PDISC if it's // port_id changed, but check just in case...) if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) { // Yes. We were expecting PDISC? if( pLoggedInPort->pdisc ) { int i; // PDISC expected -- set fields. (PDISC, Originator) SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE); // We are ready to resume FCP-SCSI to this device... // Do we need to start anything that was Queued? for( i=0; i< TACH_SEST_LEN; i++) { // see if any exchange for this PDISC'd port was queued if( ((fchs->s_id &0xFFFFFF) == (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF)) && (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) { fchs->reserved = i; // copy ExchangeID// printk(" *Q x_ID %Xh after PDISC* ",i); cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs ); } } // Complete commands Q'd while we were waiting for Login UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort); } else { printk("Not expecting PDISC (pdisc=FALSE)\n"); NeedLogin = TRUE; } } else { printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id &0xFFFFFF); NeedLogin = TRUE; } } else { printk("PDISC ACC from unknown WWN\n"); NeedLogin = TRUE; } if( NeedLogin) { // The PDISC failed. Set login struct flags accordingly, // terminate any I/O to this port, and Q a PLOGI if( pLoggedInPort ) // FC device previously known? { cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_LOGO, // Q Type fchs ); // has port_id to send to // There are a variety of error scenarios which can result // in PDISC failure, so as a catchall, add the check for // duplicate port_id. TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);// TriggerHBA( fcChip->Registers.ReMapMemBase, 0); pLoggedInPort->pdisc = FALSE; pLoggedInPort->prli = FALSE; pLoggedInPort->plogi = FALSE; cpqfcTSTerminateExchange( cpqfcHBAdata, &pLoggedInPort->ScsiNexus, PORTID_CHANGED); } cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs ); } } else { // login payload unacceptable - reason in ls_reject_code // Q up a Logout Request printk("ERROR: Login Payload unacceptable!\n"); } break; case ELS_PRLI: // we sent out PRLI pLoggedInPort = fcFindLoggedInPort( fcChip, NULL, // don't search Scsi Nexus (fchs->s_id & 0xFFFFFF), // search linked list for port_id NULL, // DON'T search linked list for WWN NULL); // don't care if( pLoggedInPort == NULL ) { // huh? printk(" Unexpected PRLI ACCept frame!\n"); // Q a LOGOut here? goto Done; } // verify the PRLI ACC payload if( !verify_PRLI( fchs, &ls_reject_code) ) { // PRLI Reply is acceptable; were we expecting it? if( pLoggedInPort->plogi ) { // yes, we expected the PRLI ACC (not PDISC; Originator) SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE); // OK, let's send a REPORT_LUNS command to determine // whether VSA or PDA FCP-LUN addressing is used. cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs ); // It's possible that a device we were talking to changed // port_id, and has logged back in. This function ensures // that I/O will resume. UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort); } else { // huh? printk(" (unexpected) PRLI ACCept with plogi FALSE\n"); // Q a LOGOut here? goto Done; } } else { printk(" PRLI ACCept payload failed verify\n"); // Q a LOGOut here? } break; case ELS_FLOGI: // we sent out FLOGI (Fabric Login) // update the upper 16 bits of our port_id in Tachyon // the switch adds those upper 16 bits when responding // to us (i.e. we are the destination_id) fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF); writel( fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID); // now send out a PLOGI to the well known port_id 0xFFFFFC fchs->s_id = 0xFFFFFC; cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs); break; case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login)) printk( " ELS_FDISC success "); break; case ELS_SCR: // we sent out State Change Registration // now we can issue Name Service Request to find any // Fabric-connected devices we might want to login to. fchs->s_id = 0xFFFFFC; // Name Server Address cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs); break; default: printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff); break; } Done: // Regardless of whether the Reply is valid or not, the // the exchange is done - complete cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete Quit: return;}// **************** Fibre Channel Services **************// This is where we process the Directory (Name) Service Reply// to know which devices are on the Fabricstatic void ProcessFCS_Reply( CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs){ PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; ULONG ox_id = (fchs->ox_rx_id >>16);// ULONG ls_reject_code;// PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort; // If this is a valid reply, then we MUST have sent a request. // Verify that we can find a valid request OX_ID corresponding to // this reply if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0) { printk(" *Discarding Reply frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff); goto Quit; // exit this routine } // OK, we were expecting it. Now check to see if it's a // "Name Service" Reply, and if so force a re-validation of // Fabric device logins (i.e. Start the login timeout and // send PDISC or PLOGI) // (Endianess Byte Swap?) if( fchs->pl[1] == 0x02FC ) // Name Service { // got a new (or NULL) list of Fabric attach devices... // Invalidate current logins PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; while( pLoggedInPort ) // for all ports which are expecting // PDISC after the next LIP, set the // logoutTimer { if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device? && (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port { pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout?? // suspend any I/O in progress until // PDISC received... pLoggedInPort->prli = FALSE; // block FCP-SCSI commands } pLoggedInPort = pLoggedInPort->pNextPort; } if( fchs->pl[2] == 0x
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -