/** * Module entry point * * Initialize moduel-wide resources and register driver */ int init_module(void) { VMK_ReturnStatus vmkStatus; Nvme_LogNoHandle("Loading driver %s.", NVME_DRIVER_IDENT); Nvme_ValidateModuleParams(); #if VMKAPIDDK_VERSION >= 650 VMK_ASSERT(sizeof(NvmeIoRequest) <= vmk_ScsiCmdGetDriverFrameSize()); #endif /* Always initialize heap in the first place. */ vmkStatus = HeapCreate(); if (vmkStatus != VMK_OK) { Nvme_LogNoHandle("failed to create driver heap, 0x%x.", vmkStatus); return vmkStatus; } /* Initialize log components, and set default log level based on * module parameter. */ vmkStatus = LogHandleCreate(nvme_log_level); if (vmkStatus != VMK_OK) { Nvme_LogNoHandle("failed to create log handle, 0x%x.", vmkStatus); goto destroy_heap; } /* Initialize mem pool. mem pool is used for allocating large * physically contiguous memory. */ vmkStatus = MemPoolCreate(); if (vmkStatus != VMK_OK) { EPRINT("failed to create mem pool, 0x%x.", vmkStatus); goto destroy_log; } /** Initialize global management handle */ vmkStatus = NvmeMgmt_GlobalInitialize(); if (vmkStatus != VMK_OK) { EPRINT("failed to initialize global management interface, 0x%x.", vmkStatus); goto destroy_mpool; } /** Initialize global lock */ vmkStatus = OsLib_LockCreateNoRank(NVME_GLOBAL_LOCK_NAME, &NVME_DRIVER_RES_LOCK); if (vmkStatus != VMK_OK) { EPRINT("failed to initialize global lock, 0x%x.", vmkStatus); goto destroy_mgmt; } /** Initialize adapter list */ vmk_ListInit(&NVME_DRIVER_RES_ADAPTERLIST); /* TODO: Do we have other global resources to initialize here? */ /* Finally, register driver */ vmkStatus = NvmeDriver_Register(); if (vmkStatus != VMK_OK) { EPRINT("failed to register driver, 0x%x.", vmkStatus); goto destroy_lock; } IPRINT("module initialized successfully."); return 0; destroy_lock: OsLib_LockDestroy(&NVME_DRIVER_RES_LOCK); destroy_mgmt: NvmeMgmt_GlobalDestroy(); destroy_mpool: MemPoolDestroy(); destroy_log: LogHandleDestroy(); destroy_heap: HeapDestroy(); return vmkStatus; }
/** * Attach and bring up controller * * Allocate controller related resources * * @param [in] ctrlr controller instance */ VMK_ReturnStatus NvmeCtrlr_Attach(struct NvmeCtrlr *ctrlr) { VMK_ReturnStatus vmkStatus; char lockName[VMK_MISC_NAME_MAX]; /** * Set initial state. * * Note: lock is not initialized by here, so do not use locking. */ NvmeState_SetCtrlrState(ctrlr, NVME_CTRLR_STATE_INIT, VMK_FALSE); /** * Initialize PCI resources first to access controller bars. * * Note: has to initialize PCI resource first, all the following operations * require BARs to be mapped already. */ vmkStatus = PciInit(ctrlr); if (vmkStatus != VMK_OK) { return vmkStatus; } vmkStatus = NvmeCtrlr_ValidateParams(ctrlr); if (vmkStatus != VMK_OK) { goto cleanup_pci; } /* Initialize DMA facilities (dma engine, sg handle, etc.) */ vmkStatus = OsLib_DmaInit(&ctrlr->ctrlOsResources); if (vmkStatus != VMK_OK) { goto cleanup_pci; } /* Initialize interrupt */ vmkStatus = IntrInit(ctrlr); if (vmkStatus != VMK_OK) { goto cleanup_dma; } /* Initialize lock domain for locks within this controller */ vmkStatus = OsLib_LockDomainCreate(&ctrlr->ctrlOsResources, Nvme_GetCtrlrName(ctrlr)); if (vmkStatus != VMK_OK) { goto cleanup_intr; } /* Initialize lock */ vmk_StringFormat(lockName, sizeof(lockName), NULL, "%s-lock", Nvme_GetCtrlrName(ctrlr)); vmkStatus = OsLib_LockCreate(&ctrlr->ctrlOsResources, NVME_LOCK_RANK_LOW, lockName, &ctrlr->lock); if (vmkStatus != VMK_OK) { goto cleanup_lockdomain; } /* Initialize task management mutex */ vmk_StringFormat(lockName, sizeof(lockName), NULL, "%s-mutex", Nvme_GetCtrlrName(ctrlr)); vmkStatus = OsLib_SemaphoreCreate(lockName, 1, &ctrlr->taskMgmtMutex); if (vmkStatus != VMK_OK) { goto cleanup_lock; } vmkStatus = OsLib_TimerQueueCreate(ctrlr); if (vmkStatus != VMK_OK) { goto cleanup_sema; } #if EXC_HANDLER vmkStatus = OsLib_SetupExceptionHandler(ctrlr); if (vmkStatus != VMK_OK) { EPRINT("The device can not handle exceptions."); goto cleanup_timer_queue; } #endif /* * TODO: Initialize and kick off timers and kernel thread */ #if 0 vmkStatus = NvmeCtrlr_CreateLogWorld(ctrlr); if (vmkStatus != VMK_OK) { goto cleanup_intr; } #endif vmkStatus = CreateScsiUnmapSlab(ctrlr); if (vmkStatus != VMK_OK) { #if EXC_HANDLER goto cleanup_exc_handler; #else goto cleanup_timer_queue; #endif } #if NVME_MUL_COMPL_WORLD vmkStatus = OsLib_StartCompletionWorlds(ctrlr); if (vmkStatus != VMK_OK) { EPRINT("Failed to create completion worlds. vmkStatus: 0x%x.", \ vmkStatus); goto cleanup_unmap_slab; } #endif vmkStatus = NvmeCtrlr_AdminQueueSetup(ctrlr); if (vmkStatus != VMK_OK) { #if NVME_MUL_COMPL_WORLD goto cleanup_compl_worlds; #else goto cleanup_unmap_slab; #endif } #if NVME_DEBUG_INJECT_ERRORS NvmeDebug_ErrorInjectInit(ctrlr->errCounters); #endif /** * Initialize all other essential members */ vmk_ListInit(&ctrlr->nsList); return VMK_OK; #if NVME_MUL_COMPL_WORLD cleanup_compl_worlds: OsLib_EndCompletionWorlds(ctrlr); #endif cleanup_unmap_slab: vmk_SlabDestroy(ctrlr->scsiUnmapSlabId); #if EXC_HANDLER cleanup_exc_handler: OsLib_ShutdownExceptionHandler(ctrlr); #endif cleanup_timer_queue: OsLib_TimerQueueDestroy(ctrlr); cleanup_sema: OsLib_SemaphoreDestroy(&ctrlr->taskMgmtMutex); cleanup_lock: OsLib_LockDestroy(&ctrlr->lock); cleanup_lockdomain: OsLib_LockDomainDestroy(&ctrlr->ctrlOsResources); cleanup_intr: IntrCleanup(ctrlr); cleanup_dma: OsLib_DmaCleanup(&ctrlr->ctrlOsResources); cleanup_pci: PciCleanup(ctrlr); NvmeState_SetCtrlrState(ctrlr, NVME_CTRLR_STATE_FAILED, VMK_FALSE); DPRINT_CTRLR("failed to attach controller, 0x%x.", vmkStatus); return vmkStatus; }