📄 cpqfctsworker.c
字号:
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 (prior login OK) { if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) { // Yes. We were expecting PDISC? if( pLoggedInPort->pdisc ) { // Yes; set fields accordingly. (PDISC, not Originator) SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE); // send 'ACC' reply cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC) fchs ); // OK to resume I/O... } else { printk("Not expecting PDISC (pdisc=FALSE)\n"); NeedReject = TRUE; // set reject reason code ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); } } else { if( pLoggedInPort->port_id != 0) { printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id &0xFFFFFF); } NeedReject = TRUE; // set reject reason code ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); } } else { printk("PDISC Request from unknown WWN\n"); NeedReject = TRUE; // set reject reason code ls_reject_code = LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME); } } else // Payload unacceptable { printk("payload unacceptable\n"); NeedReject = TRUE; // reject code already set } if( NeedReject) { ULONG port_id; // The PDISC failed. Set login struct flags accordingly, // terminate any I/O to this port, and Q a PLOGI if( pLoggedInPort ) { pLoggedInPort->pdisc = FALSE; pLoggedInPort->prli = FALSE; pLoggedInPort->plogi = FALSE; cpqfcTSTerminateExchange( cpqfcHBAdata, &pLoggedInPort->ScsiNexus, PORTID_CHANGED); port_id = pLoggedInPort->port_id; } else { port_id = fchs->s_id &0xFFFFFF; } fchs->reserved = ls_reject_code; // borrow this (unused) field cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs ); } break; case 0x0003: // PLOGI? // Payload for PLOGI and PDISC is identical (request & reply) if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload? { LOGIN_PAYLOAD logi; // FC-PH Port Login BOOLEAN NeedReject = FALSE; // PDISC payload OK. If critical login fields // (e.g. WWN) matches last login for this port_id, // we may resume any prior exchanges // with the other port 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 NeedReject = TRUE; // set reject reason code ls_reject_code = LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES); } } if( !NeedReject ) { // OK - we have valid fcPort ptr; set fields accordingly. // (not PDISC, not Originator) SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); // send 'ACC' reply cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC) fchs ); } } else // Payload unacceptable { printk("payload unacceptable\n"); NeedReject = TRUE; // reject code already set } if( NeedReject) { // The PDISC failed. Set login struct flags accordingly, // terminate any I/O to this port, and Q a PLOGI pLoggedInPort->pdisc = FALSE; pLoggedInPort->prli = FALSE; pLoggedInPort->plogi = FALSE; fchs->reserved = ls_reject_code; // borrow this (unused) field // send 'RJT' reply cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs ); } // terminate any exchanges with this device... if( pLoggedInPort ) { cpqfcTSTerminateExchange( cpqfcHBAdata, &pLoggedInPort->ScsiNexus, PORTID_CHANGED); } break; case 0x1020: // PRLI? { BOOLEAN NeedReject = TRUE; 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 Request -not logged in!\n"); // set reject reason code ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); // Q a LOGOut here? } else { // 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; not Originator) SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); // Q an ACCept Reply cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI_ACC, fchs ); NeedReject = FALSE; } else { // huh? printk(" (unexpected) PRLI REQEST with plogi FALSE\n"); // set reject reason code ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); // Q a LOGOut here? } } else { printk(" PRLI REQUEST payload failed verify\n"); // (reject code set by "verify") // Q a LOGOut here? } } if( NeedReject ) { // Q a ReJecT Reply with reason code fchs->reserved = ls_reject_code; cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, // Q Type fchs ); } } break; case 0x0005: // LOGOut? { // was this LOGOUT because we sent a ELS_PDISC to an FC device // with changed (or new) port_id, or does the port refuse // to communicate to us? // We maintain a logout counter - if we get 3 consecutive LOGOuts, // give up! LOGOUT_PAYLOAD logo; BOOLEAN GiveUpOnDevice = FALSE; ULONG ls_reject_code = 0; BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo)); pLoggedInPort = fcFindLoggedInPort( fcChip, NULL, // don't search Scsi Nexus 0, // don't search linked list for port_id &logo.port_name[0], // search linked list for WWN NULL); // don't care about end of list if( pLoggedInPort ) // found the device? { // Q an ACC reply cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_LOGO_ACC, // Q Type fchs ); // device to respond to // set login struct fields (LOGO_counter increment) SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); // are we an Initiator? if( fcChip->Options.initiator) { // we're an Initiator, so check if we should // try (another?) login // Fabrics routinely log out from us after // getting device info - don't try to log them // back in. if( (fchs->s_id & 0xFFF000) == 0xFFF000 ) { ; // do nothing } else if( pLoggedInPort->LOGO_counter <= 3) { // try (another) login (PLOGI request) cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, // Q Type fchs ); // Terminate I/O with "retry" potential cpqfcTSTerminateExchange( cpqfcHBAdata, &pLoggedInPort->ScsiNexus, PORTID_CHANGED); } else { printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", fchs->s_id &&0xFFFFFF); GiveUpOnDevice = TRUE; } } else { GiveUpOnDevice = TRUE; } if( GiveUpOnDevice == TRUE ) { cpqfcTSTerminateExchange( cpqfcHBAdata, &pLoggedInPort->ScsiNexus, DEVICE_REMOVED); } } else // we don't know this WWN! { // Q a ReJecT Reply with reason code fchs->reserved = ls_reject_code; cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, // Q Type fchs ); } } break; // FABRIC only case case 0x0461: // ELS RSCN (Registered State Change Notification)? { int Ports; int i; __u32 Buff; // Typically, one or more devices have been added to or dropped // from the Fabric. // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997) // The first 32-bit word has a 2-byte Payload Length, which // includes the 4 bytes of the first word. Consequently, // this PL len must never be less than 4, must be a multiple of 4, // and has a specified max value 256. // (Endianess!) Ports = ((fchs->pl[0] >>24) - 4) / 4; Ports = Ports > 63 ? 63 : Ports; printk(" RSCN ports: %d\n", Ports); if( Ports <= 0 ) // huh? { // ReJecT the command fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0); cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, // Q Type fchs ); break; } else // Accept the command { cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_ACC, // Q Type fchs ); } // Check the "address format" to determine action. // We have 3 cases: // 0 = Port Address; 24-bit address of affected device // 1 = Area Address; MS 16 bits valid // 2 = Domain Address; MS 8 bits valid for( i=0; i<Ports; i++) { BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4); switch( Buff & 0xFF000000) { case 0: // Port Address? case 0x01000000: // Area Domain? case 0x02000000: // Domain Address // For example, "port_id" 0x201300 // OK, let's try a Name Service Request (Query) fchs->s_id = 0xFFFFFC; // Name Server Address cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs); break; default: // huh? new value on version change? break; } } } break; default: // don't support this request (yet) // set reject reason code fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, REQUEST_NOT_SUPPORTED); cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, // Q Type fchs ); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -