/* BEGIN_ICS_COPYRIGHT4 **************************************** Copyright (c) 2015-2017, Intel Corporation Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** END_ICS_COPYRIGHT4 ****************************************/ #include "bmamain.h" #include "bmadebug.h" #include "bma_provider.h" #include "bspcommon/h/usrBootManager.h" #include "bspcommon/ibml/h/icsApi.h" // // Debug params // #if ICS_LOGGING _IB_DBG_PARAM_BLOCK(_DBG_LVL_ALL, _DBG_BREAK_ENABLE, BMA_TAG, "Bma", MOD_BMA, Bma); #else _IB_DBG_PARAM_BLOCK((_DBG_LVL_FATAL | _DBG_LVL_ERROR), _DBG_BREAK_ENABLE, BMA_TAG, "Bma"); #endif // // Global Info // BMA_GLOBAL_INFO *g_BmaGlobalInfo; // // Stored settings // BMA_GLOBAL_CONFIG_PARAMETERS g_BmaSettings = BMA_DEFAULT_SETTINGS; // // BmaLoad // // This routine is called by the VCA Init when the driver is first loaded. // This routine is to create and initialize the BMA agent global data structures. // // INPUTS: // // ComponentInfo - Address of IBT_COMPONENT_INFO that needs to be updated // with this driver's specific handlers for add/remove of a channel adapter // device as well as the overall driver unload handler. // // OUTPUTS: // // None. // // RETURNS: // // FSUCCESS - Indicates a successful load. // FSTATUS BmaLoad( IN IBT_COMPONENT_INFO *ComponentInfo ) { FSTATUS status = FSUCCESS; extern uint32 BmaDbg; #ifdef IB_TRACE extern uint32 BmaTrace; #endif _DBG_ENTER_LVL(_DBG_LVL_MAIN, BMALoad); _DBG_INIT; __DBG_LEVEL__ = BmaDbg; #ifdef IB_TRACE __DBG_TRACE_LEVEL__ = BmaTrace; #endif #if defined(IB_DEBUG) || defined(DBG) MsgOut ("Bma:DebugFlags = 0x%8x\n", __DBG_LEVEL__); #endif #if defined(VXWORKS) _DBG_PRINT(_DBG_LVL_MAIN, (" InfiniBand Baseboard Management Class agent. Built %s %s\n",\ __DATE__, __TIME__ )); #else _DBG_PRINT(_DBG_LVL_MAIN, (" InfiniBand Baseboard Management Class agent. Built %s %s\n",\ _DBG_PTR(__DATE__), _DBG_PTR(__TIME__) )); #endif _TRC_REGISTER(); // // Establish dispatch entry points for the functions supported. // MemoryClear( ComponentInfo, sizeof(IBT_COMPONENT_INFO) ); ComponentInfo->AddDevice = BmaAddDevice; ComponentInfo->RemoveDevice = BmaRemoveDevice; ComponentInfo->Unload = BmaUnload; // // Read any registry parameters for the driver which may be present. // //BmaReadRegistryParameters(); // // This function is called to initialize the GSA subsystem. This must be // called only once and if the function does not return success, the // caller must unload the component containing GSA or else not use the // GSA functionality since GSA will not be available. // // We are being asked to do a one-time initialization. Here we initialize // the list of channel adapters as well as initialize the list of service // classes as well as initialize the spin locks guarding these lists. // // // Allocate space for Global data // g_BmaGlobalInfo = (BMA_GLOBAL_INFO*)MemoryAllocateAndClear( sizeof(BMA_GLOBAL_INFO), FALSE, BMA_TAG ); if ( NULL != g_BmaGlobalInfo ) { // // initialize global data // g_BmaGlobalInfo->binitsuccess = FALSE; SpinLockInitState( &g_BmaGlobalInfo->DevListLock ); if( !SpinLockInit( &g_BmaGlobalInfo->DevListLock ) ) { _DBG_ERROR(( "Unable to initialize spin locks!\n" )); status = FINSUFFICIENT_RESOURCES; goto fail_lock; } // // Recv Queue and Thread // CmdThreadInitState(&g_BmaGlobalInfo->RecvThread); if ( ! CmdThreadCreate(&g_BmaGlobalInfo->RecvThread, THREAD_PRI_HIGH, "Bma", (CMD_THREAD_CALLBACK)BmaThreadCallback, (CMD_THREAD_CALLBACK)BmaFreeCallback, (void*)g_BmaGlobalInfo)) { _DBG_ERROR(("BmaMain: Unable to Create RecvThread\n")); status = FINSUFFICIENT_RESOURCES; goto fail_thread; } // initialize this general service class manager with GSI status = iba_gsi_register_class(MCLASS_BM, IB_BM_CLASS_VERSION, GSI_REGISTER_RESPONDER, // Register as a Responder FALSE, // No SAR cap needed g_BmaGlobalInfo, // Context BmaSendCallback, BmaRecvCallback, &g_BmaGlobalInfo->GsaHandle); if (status != FSUCCESS) { CmdThreadDestroy(&g_BmaGlobalInfo->RecvThread); fail_thread: SpinLockDestroy( &g_BmaGlobalInfo->DevListLock ); fail_lock: MemoryDeallocate(g_BmaGlobalInfo); g_BmaGlobalInfo = NULL; _DBG_ERROR(("BmaMain: Unable to register with GSA!!! \n", status)); _DBG_LEAVE_EXT(_DBG_LVL_FUNC_TRACE); return status; } } else { status = FINSUFFICIENT_RESOURCES; _DBG_PRINT(_DBG_LVL_MAIN,("Not enough memory!\n")); } _DBG_LEAVE_LVL(_DBG_LVL_MAIN); return status; } // // BmaUnload // // This routine should release resources allocated in the BmaLoad function. // Also, since their is a single instance of the service for all channel // adapters in the system, it will also release resources allocated in the // BmaAddDevice function. // // INPUTS: // // None. // // OUTPUTS: // // None. // // RETURNS: // // None // // void BmaUnload(void) { _DBG_ENTER_LVL(_DBG_LVL_MAIN, BmaUnload); _TRC_UNREGISTER(); if ( g_BmaGlobalInfo ) { // Destroy the datagram pool if ( g_BmaGlobalInfo->DgrmPoolHandle ) iba_gsi_destroy_dgrm_pool( g_BmaGlobalInfo->DgrmPoolHandle ); // Deregister this class agent with the GSA if ( g_BmaGlobalInfo->GsaHandle ) iba_gsi_deregister_class(g_BmaGlobalInfo->GsaHandle); // // Recv Thread // CmdThreadDestroy(&g_BmaGlobalInfo->RecvThread); // // Ca List Members // while ( g_BmaGlobalInfo->DevList ) { BmaRemoveDevice( g_BmaGlobalInfo->DevList->CaGuid, NULL ); } // // Ca List Lock // SpinLockDestroy( &g_BmaGlobalInfo->DevListLock ); // // Free up global memory // MemoryDeallocate( g_BmaGlobalInfo ); g_BmaGlobalInfo = NULL; } // if g_BmaGlobalInfo _DBG_LEAVE_LVL(_DBG_LVL_MAIN); } ////////////////////////////////////////////////////////////////////////// // BmaAddDevice() // // This routine is called once for every new device added. // // INPUTS: // CaGuid - the channel adapters GUID // // OUTPUTS: // // None. Although function is defined to return context value, this // value is not set since their is nothing specifically allocated for // each new channel adapter, so nothing is done in the BmaRemoveDevice // function that needs the context. // // RETURNS: // // FSUCCESS - Indicates a successful initialization. // // FSTATUS BmaAddDevice( IN EUI64 CaGuid, OUT void **Context ) { FSTATUS status = FSUCCESS; uint32 BufferSize; BMA_DEV_INFO *pDevInfo=NULL; _DBG_ENTER_LVL(_DBG_LVL_MAIN, BmaAddDevice); ASSERT(g_BmaGlobalInfo); if (!g_BmaGlobalInfo->binitsuccess) { // Create the datagram pool BufferSize = sizeof(MAD); status = iba_gsi_create_dgrm_pool(g_BmaGlobalInfo->GsaHandle, g_BmaSettings.MaxNDgrm, 1, &BufferSize, 0, //1, &g_BmaGlobalInfo->DgrmPoolHandle ); if (status != FSUCCESS) { // Cleanup iba_gsi_deregister_class(g_BmaGlobalInfo->GsaHandle); MemoryDeallocate(g_BmaGlobalInfo); g_BmaGlobalInfo = NULL; _DBG_ERROR(("Unable to create BMA datagram pool!!! \n", status)); } else { g_BmaGlobalInfo->binitsuccess = TRUE; } } if (g_BmaGlobalInfo->binitsuccess) { pDevInfo = (BMA_DEV_INFO*)MemoryAllocateAndClear(sizeof(BMA_DEV_INFO), FALSE, BMA_TAG ); if (pDevInfo) { IB_CA_ATTRIBUTES CaAttributes; pDevInfo->CaGuid = CaGuid; status = iba_query_ca_by_guid_alloc(CaGuid, &CaAttributes); if ( status == FSUCCESS ) { pDevInfo->NumPorts = CaAttributes.Ports; pDevInfo->Port = (BMA_PORT_INFO*) MemoryAllocateAndClear(sizeof(BMA_PORT_INFO)*pDevInfo->NumPorts, FALSE, BMA_TAG); if (pDevInfo->Port) { IB_PORT_ATTRIBUTES *pPortAttr; unsigned i; for ( i = 0, pPortAttr = CaAttributes.PortAttributesList; i < pDevInfo->NumPorts; i++, pPortAttr = pPortAttr->Next ) { // Traps disabled by default, Trap settings are all zero // BKey, BKeyProtect, BKeyViolations, and BKeyLease all init to zero pDevInfo->Port[i].Guid = pPortAttr->GUID; } MemoryDeallocate(CaAttributes.PortAttributesList); // Success, add this CA to the list SpinLockAcquire( &g_BmaGlobalInfo->DevListLock ); pDevInfo->Next = g_BmaGlobalInfo->DevList; g_BmaGlobalInfo->DevList = pDevInfo; SpinLockRelease( &g_BmaGlobalInfo->DevListLock ); } else { _DBG_ERROR(("MemAlloc failed for Port List!\n")); status = FINSUFFICIENT_MEMORY; } } else { _DBG_ERROR(("CA Query Failed!\n")); MemoryDeallocate(pDevInfo); } } else { _DBG_ERROR(("MemAlloc failed for pDevInfo!\n")); status = FINSUFFICIENT_MEMORY; } } _DBG_LEAVE_LVL(_DBG_LVL_MAIN); return status; } // BmaAddDevice() ////////////////////////////////////////////////////////////////////////// // BmaRemoveDevice() // // This routine is called once for every CA device being removed. Nothing // is performed in this function. All cleanup is performed in the BmaUnload // function. // // INPUTS: // CaGuid - the channel adapters GUID // Context - driver defined unique context for this CA // // OUTPUTS: // // None. // // RETURNS: // // FSUCCESS - Indicates a successful initialization. // // FSTATUS BmaRemoveDevice( IN EUI64 CaGuid, IN void *Context ) { FSTATUS status = FSUCCESS; BMA_DEV_INFO *pDevInfo=NULL; _DBG_ENTER_LVL(_DBG_LVL_MAIN, BmaRemoveDevice); ASSERT(g_BmaGlobalInfo); SpinLockAcquire( &g_BmaGlobalInfo->DevListLock ); pDevInfo = g_BmaGlobalInfo->DevList; if ( g_BmaGlobalInfo->DevList->CaGuid == CaGuid ) { g_BmaGlobalInfo->DevList = pDevInfo->Next; } else { while ( pDevInfo->Next ) { if ( pDevInfo->Next->CaGuid == CaGuid ) { BMA_DEV_INFO *Found = pDevInfo->Next; pDevInfo->Next = Found->Next; pDevInfo = Found; break; } pDevInfo = pDevInfo->Next; } } SpinLockRelease( &g_BmaGlobalInfo->DevListLock ); if (pDevInfo && pDevInfo->CaGuid == CaGuid) { MemoryDeallocate( pDevInfo->Port ); MemoryDeallocate( pDevInfo ); } else { _DBG_ERROR(("Unable to find Ca with GUID 0x%"PRIx64"\n", CaGuid)); status = FERROR; } _DBG_LEAVE_LVL(_DBG_LVL_MAIN); return status; } // BmaRemoveDevice()