VOID CNdasDevice::SetName(LPCTSTR szName) { ximeta::CAutoLock autolock(this); HRESULT hr = ::StringCchCopy( m_szDeviceName, MAX_NDAS_DEVICE_NAME_LEN, szName); _ASSERTE(SUCCEEDED(hr)); BOOL fSuccess = _NdasSystemCfg.SetValueEx( m_szCfgContainer, TEXT("DeviceName"), szName); if (!fSuccess) { DBGPRT_WARN_EX( _FT("Writing device name entry to the registry failed at %s.\n"), m_szCfgContainer); } CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->DevicePropertyChanged(m_dwSlotNo); }
BOOL CNdasDeviceRegistrar::Unregister(const NDAS_DEVICE_ID& DeviceId) { ximeta::CAutoLock autolock(this); CNdasDeviceId cdevid(DeviceId); DPInfo(_FT("Unregister device %s\n"), (LPCTSTR)cdevid); DeviceIdMap::iterator itrId = m_deviceIdMap.find(DeviceId); if (m_deviceIdMap.end() == itrId) { // TODO: ::SetLastError(NDAS_ERROR_DEVICE_NOT_FOUND); // TODO: Make more specific error code ::SetLastError(NDASHLPSVC_ERROR_DEVICE_ENTRY_NOT_FOUND); } PCNdasDevice pDevice = itrId->second; if (pDevice->GetStatus() != NDAS_DEVICE_STATUS_DISABLED) { // TODO: ::SetLastError(NDAS_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE); // TODO: Make more specific error code ::SetLastError(NDASHLPSVC_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE); return FALSE; } DWORD dwSlotNo = pDevice->GetSlotNo(); _ASSERT(0 != dwSlotNo); DeviceSlotMap::iterator itrSlot = m_deviceSlotMap.find(dwSlotNo); m_deviceIdMap.erase(itrId); m_deviceSlotMap.erase(itrSlot); m_pbSlotOccupied[dwSlotNo] = FALSE; pDevice->Release(); TCHAR szContainer[30]; HRESULT hr = ::StringCchPrintf(szContainer, 30, TEXT("Devices\\%04d"), dwSlotNo); _ASSERT(SUCCEEDED(hr)); BOOL fSuccess = _NdasSystemCfg.DeleteContainer(szContainer, TRUE); if (!fSuccess) { DPWarningEx( _FT("Deleting registration entry from the registry failed at %s.\n"), szContainer); } CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); (void) pEventPublisher->DeviceEntryChanged(); return TRUE; }
VOID CNdasDevice::SetName(LPCTSTR szName) { ximeta::CAutoLock autolock(this); HRESULT hr = ::StringCchCopy( m_szDeviceName, MAX_NDAS_DEVICE_NAME_LEN, szName); _ASSERTE(SUCCEEDED(hr)); (VOID) SetConfigValue(_T("DeviceName"), szName); CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->DevicePropertyChanged(m_dwSlotNo); }
BOOL CNdasEventMonitor::OnLogicalDeviceDisconnected(DWORD nWaitIndex) { ximeta::CAutoLock autolock(this); PCNdasLogicalDevice pLogDevice = NULL; if (nWaitIndex < m_vLogDevices.size()) { pLogDevice = m_vLogDevices[nWaitIndex]; } else { _ASSERTE(FALSE); return TRUE; } if (NULL == pLogDevice) { _ASSERTE(FALSE); return TRUE; } CNdasScsiLocation location = pLogDevice->GetNdasScsiLocation(); DPInfo(_FT("Disconnect Event from %s: %s\n"), location.ToString(), pLogDevice->ToString()); // // reset the event to prevent consecutive same event pulse // BOOL fSuccess = ::ResetEvent(pLogDevice->GetDisconnectEvent()); _ASSERTE(fSuccess); CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); NDAS_LOGICALDEVICE_ID logicalDeviceId = pLogDevice->GetLogicalDeviceId(); (VOID) pEventPublisher->LogicalDeviceDisconnected(logicalDeviceId); pLogDevice->OnDisconnected(); return TRUE; }
BOOL CNdasEventMonitor::OnLogicalDeviceAlarmed(DWORD nWaitIndex) { ximeta::CAutoLock autolock(this); PCNdasLogicalDevice pLogDevice = NULL; if (nWaitIndex < m_vLogDevices.size()) { pLogDevice = m_vLogDevices[nWaitIndex]; } else { _ASSERTE(FALSE); return FALSE; } if (NULL == pLogDevice) { _ASSERTE(FALSE); return FALSE; } CNdasScsiLocation ndasScsiLocation = pLogDevice->GetNdasScsiLocation(); DPInfo(_FT("Alarm Event from %s: %s\n"), ndasScsiLocation.ToString(), pLogDevice->ToString()); if (ndasScsiLocation.IsInvalid()) { DBGPRT_ERR(_FT("Invalid SCSI Location\n")); _ASSERTE(FALSE); return FALSE; } // // reset the event to prevent consecutive same event pulse // // should return TRUE BOOL fSuccess = ::ResetEvent(pLogDevice->GetAlarmEvent()); _ASSERTE(fSuccess); ULONG ulAdapterStatus; fSuccess = ::LsBusCtlQueryStatus( ndasScsiLocation.SlotNo, &ulAdapterStatus); if (!fSuccess) { DPErrorEx(_FT("Unable to get alarm status, Ignored: ")); return TRUE; } if(pLogDevice->GetAdapterStatus() != ulAdapterStatus) { pLogDevice->SetAdapterStatus(ulAdapterStatus); CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->LogicalDeviceAlarmed(pLogDevice->GetLogicalDeviceId(), ulAdapterStatus); } if(ADAPTERINFO_ISSTATUSFLAG(ulAdapterStatus, ADAPTERINFO_STATUSFLAG_MEMBER_FAULT)) pLogDevice->SetAllUnitDevicesFault(); return TRUE; }
// // Remove the unit device ID from the list // BOOL CNdasLogicalDevice::RemoveUnitDevice(CNdasUnitDevice& unitDevice) { ximeta::CAutoLock autolock(this); DWORD ldSequence = unitDevice.GetLDSequence(); _ASSERTE(ldSequence < m_logicalDeviceGroup.nUnitDevices); if (ldSequence >= m_logicalDeviceGroup.nUnitDevices) { DBGPRT_ERR(_FT("Invalid sequence (%d) of the unit device.\n"), ldSequence); return FALSE; } _ASSERTE(&unitDevice == m_pUnitDevices[ldSequence]); if (&unitDevice != m_pUnitDevices[ldSequence]) { DBGPRT_ERR(_FT("Unit device in sequence (%d) is not occupied.\n"), ldSequence); return FALSE; } m_pUnitDevices[ldSequence]->Release(); m_pUnitDevices[ldSequence] = NULL; // // Workaround for Fault-tolerant Mode // -> Even if the logical device is incomplete, // Mounted Logical Device Location should be intact // if it is mounted // if (NDAS_LOGICALDEVICE_STATUS_MOUNT_PENDING == GetStatus() || NDAS_LOGICALDEVICE_STATUS_MOUNTED == GetStatus() || NDAS_LOGICALDEVICE_STATUS_UNMOUNT_PENDING == GetStatus()) { --m_nUnitDeviceInstances; return TRUE; } if (IsComplete()) { CNdasLogicalDeviceManager* pLdm = pGetNdasLogicalDeviceManager(); pLdm->UnregisterNdasScsiLocation(m_NdasScsiLocation); } --m_nUnitDeviceInstances; // // Deallocation NDAS SCSI Location when the fist unit device is removed // if (0 == ldSequence) { cpDeallocateNdasScsiLocation(); } // // Publish Event // CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->LogicalDeviceRelationChanged(m_logicalDeviceId); // // Set Device Error // SetLastDeviceError(NDAS_LOGICALDEVICE_ERROR_MISSING_MEMBER); return TRUE; }
// // Set the unit device ID at a sequence // to a unit device member ID list // BOOL CNdasLogicalDevice::AddUnitDevice(CNdasUnitDevice& unitDevice) { ximeta::CAutoLock autolock(this); BOOL fSuccess; DWORD ldSequence = unitDevice.GetLDSequence(); _ASSERTE(ldSequence < m_logicalDeviceGroup.nUnitDevices); if (ldSequence >= m_logicalDeviceGroup.nUnitDevices) { DBGPRT_ERR(_FT("Invalid sequence (%d) of the unit device.\n"), ldSequence); return FALSE; } _ASSERTE(NULL == m_pUnitDevices[ldSequence]); if (NULL != m_pUnitDevices[ldSequence]) { DBGPRT_ERR(_FT("Sequence (%d) is already occupied.\n"), ldSequence); return FALSE; } _ASSERTE(NULL == m_pUnitDevices[ldSequence]); m_pUnitDevices[ldSequence] = &unitDevice; m_pUnitDevices[ldSequence]->AddRef(); ++m_nUnitDeviceInstances; _ASSERTE( m_nUnitDeviceInstances >= 0 && m_nUnitDeviceInstances <= GetUnitDeviceCount() ); if (m_nUnitDeviceInstances < GetUnitDeviceCount()) { SetLastDeviceError(NDAS_LOGICALDEVICE_ERROR_MISSING_MEMBER); } else { SetLastDeviceError(NDAS_LOGICALDEVICE_ERROR_NONE); } // // Allocate NDAS SCSI Location when the first unit device is // available // if (0 == ldSequence) { cpAllocateNdasScsiLocation(); } if (IsComplete()) { CNdasLogicalDeviceManager* pLdm = pGetNdasLogicalDeviceManager(); pLdm->RegisterNdasScsiLocation(m_NdasScsiLocation, *this); } if (IsComplete()) { // // Reconciliation Support // BOOL bAlive, bAdapterError; fSuccess = ::LsBusCtlQueryNodeAlive( m_NdasScsiLocation.SlotNo, &bAlive, &bAdapterError); // // Reconciliation // if (fSuccess && bAlive) { ReconcileFromNdasBus(); } } else if (IsComplete() && m_fMountOnReady) { // // Boot-time Plug In Support // if ((m_mountOnReadyAccess & GetAllowingAccess()) == m_mountOnReadyAccess) { (VOID) PlugIn(m_mountOnReadyAccess); } else if ((GENERIC_READ & GetAllowingAccess()) && m_fReducedMountOnReadyAccess) { (VOID) PlugIn(GENERIC_READ); } } DBGPRT_INFO(_FT("Added %s to Logical Device %s\n"), unitDevice.ToString(), this->ToString()); CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->LogicalDeviceRelationChanged(m_logicalDeviceId); return TRUE; }
BOOL CNdasEventMonitor::OnLogicalDeviceAlarmed(DWORD nWaitIndex) { ximeta::CAutoLock autolock(this); CNdasLogicalDevice* pLogDevice = NULL; if (nWaitIndex < m_vLogDevices.size()) { pLogDevice = m_vLogDevices[nWaitIndex]; } else { _ASSERTE(FALSE); return FALSE; } if (NULL == pLogDevice) { _ASSERTE(FALSE); return FALSE; } CNdasScsiLocation ndasScsiLocation = pLogDevice->GetNdasScsiLocation(); DBGPRT_INFO(_FT("Alarm Event from %s: %s\n"), ndasScsiLocation.ToString(), pLogDevice->ToString()); if (ndasScsiLocation.IsInvalid()) { DBGPRT_ERR(_FT("Invalid SCSI Location\n")); _ASSERTE(FALSE); return FALSE; } // // reset the event to prevent consecutive same event pulse // // should return TRUE BOOL fSuccess = ::ResetEvent(pLogDevice->GetAlarmEvent()); _ASSERTE(fSuccess); ULONG ulAdapterStatus; fSuccess = ::LsBusCtlQueryStatus( ndasScsiLocation.SlotNo, &ulAdapterStatus); if (!fSuccess) { DBGPRT_ERR_EX(_FT("(%s) query status failed on alarm, ignored: "), ndasScsiLocation.ToString()); return TRUE; } DBGPRT_INFO(_FT("(%s) alarmed %08X.\n"), ndasScsiLocation.ToString(), ulAdapterStatus); // Determine whether an alarm will be issued. // Only viable alarm will be published if(pIsViableAlarmStatus(pLogDevice->GetAdapterStatus(), ulAdapterStatus)) { CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->LogicalDeviceAlarmed( pLogDevice->GetLogicalDeviceId(), pGetSignificatAlarm(pLogDevice->GetAdapterStatus(), ulAdapterStatus)); } pLogDevice->SetAdapterStatus(ulAdapterStatus); return TRUE; }
DWORD CNdasEventMonitor:: OnTaskStart() { BOOL bTerminateThread(FALSE); // 15 sec = 10,000,000 nanosec // negative value means relative time LARGE_INTEGER liDueTime; liDueTime.QuadPart = - 10 * 1000 * 1000; BOOL fSuccess = ::SetWaitableTimer( m_hHeartbeatMonitorTimer, &liDueTime, HEARTBEAT_MONITOR_INTERVAL, NULL, NULL, FALSE); if (!fSuccess) { DPErrorEx(_FT("Setting waitable timer failed: ")); } do { // // Lock against m_vLogDevice set change // this->Lock(); DWORD dwLogDevices = m_vLogDevices.size(); DWORD dwHandles = 3 + 2 * dwLogDevices; HANDLE* hWaitingHandles = new HANDLE[dwHandles]; hWaitingHandles[0] = m_hTaskTerminateEvent; hWaitingHandles[1] = m_hLogDeviceSetChangeEvent; hWaitingHandles[2] = m_hHeartbeatMonitorTimer; PCNdasLogicalDeviceVector::const_iterator itr = m_vLogDevices.begin(); for (DWORD i = 3; itr != m_vLogDevices.end(); ++itr, ++i) { PCNdasLogicalDevice pLogDevice = *itr; hWaitingHandles[i] = pLogDevice->GetDisconnectEvent(); hWaitingHandles[dwLogDevices + i] = pLogDevice->GetAlarmEvent(); } this->Unlock(); BOOL fSuccess = ::ResetEvent(m_hLogDeviceSetChangeEvent); _ASSERTE(fSuccess); BOOL bResetLogDeviceSet(FALSE); do { DWORD dwWaitResult = ::WaitForMultipleObjects( dwHandles, hWaitingHandles, FALSE, INFINITE); if (WAIT_OBJECT_0 == dwWaitResult) { // // Terminate Thread Event // bTerminateThread = TRUE; } else if (WAIT_OBJECT_0 + 1 == dwWaitResult) { // // LogicalDeviceSetChange Event // bResetLogDeviceSet = TRUE; } else if (WAIT_OBJECT_0 + 2 == dwWaitResult) { // // Heartbeat Monitor Timer Event // ximeta::CAutoLock autolock(this); PCNdasDeviceSet::const_iterator itr = m_hbMonDevices.begin(); m_bIterating = TRUE; for (; itr != m_hbMonDevices.end();) { PCNdasDevice pDevice = *itr; BOOL bDetach = pDevice->OnStatusCheck(); if (bDetach) { DPInfo(_FT("Detaching device %s from the monitor\n"), CNdasDeviceId(pDevice->GetDeviceId()).ToString()); itr = m_hbMonDevices.erase(itr); } else { ++itr; } } m_bIterating = FALSE; } else if (WAIT_OBJECT_0 + 3 <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + dwLogDevices) { // // Disconnect Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3); PCNdasLogicalDevice pLogDevice = m_vLogDevices[n]; DPInfo(_FT("Disconnect Event from slot %d: %s\n"), pLogDevice->GetSlot(), pLogDevice->ToString()); // // Publish event here // // TODO: Publish event here // CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher->LogicalDeviceDisconnected(logicalDeviceId); BOOL fSuccess = ::ResetEvent(pLogDevice->GetDisconnectEvent()); _ASSERTE(fSuccess); // // Eject device // DPInfo(_FT("Ejecting disconnected logical device\n")); fSuccess = pLogDevice->Eject(); if (!fSuccess) { DPErrorEx(_FT("Eject failed: ")); DPError(_FT("Trying to unplug...\n")); fSuccess = pLogDevice->Unplug(); if (!fSuccess) { DPErrorEx(_FT("Unplugging failed: ")); } } } else if (WAIT_OBJECT_0 + 3 + dwLogDevices <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + 2 * dwLogDevices) { // // Alarm Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3 + dwLogDevices); PCNdasLogicalDevice pLogDevice = m_vLogDevices[n]; ULONG ulStatus; DPInfo(_FT("Alarm Event from slot %d: %s\n"), pLogDevice->GetSlot(), pLogDevice->ToString()); LsBusCtlQueryAlarmStatus(pLogDevice->GetSlot(), &ulStatus); CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); switch (ulStatus) { case ALARM_STATUS_NORMAL: { DPInfo(_FT("Alarm Normal\n")); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher-> LogicalDeviceReconnected(logicalDeviceId); } break; case ALARM_STATUS_START_RECONNECT: { DPInfo(_FT("Alarm Start Reconnect\n")); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher-> LogicalDeviceReconnecting(logicalDeviceId); } break; case ALARM_STATUS_FAIL_RECONNECT: // obsolete DPInfo(_FT("Alarm Failed Reconnecting\n")); break; default: DPWarning(_FT("Unknown alarm status: %d\n"), ulStatus); } // // TODO: Publish event here // BOOL fSuccess = ::ResetEvent(pLogDevice->GetAlarmEvent()); _ASSERTE(fSuccess); } else { _ASSERTE(FALSE); DPErrorEx(_FT("Wait failed: ")); } } while (!bResetLogDeviceSet && !bTerminateThread); delete [] hWaitingHandles; } while (!bTerminateThread); fSuccess = ::CancelWaitableTimer(m_hHeartbeatMonitorTimer); if (!fSuccess) { DPErrorEx(_FT("Canceling waitable timer failed: ")); } return 0; }
PCNdasDevice CNdasDeviceRegistrar::Register(const NDAS_DEVICE_ID& DeviceId, DWORD dwSlotNo) { // // this will lock this class from here // and releases the lock when the function returns; // ximeta::CAutoLock autolock(this); DPInfo(_FT("Registering device %s at slot %d\n"), LPCTSTR(CNdasDeviceId(DeviceId)), dwSlotNo); // check slot number if (dwSlotNo < 1 || dwSlotNo > m_dwMaxSlotNo) { ::SetLastError(NDASHLPSVC_ERROR_INVALID_SLOT_NUMBER); return NULL; } // check and see if the slot is occupied if (m_pbSlotOccupied[dwSlotNo]) { ::SetLastError(NDASHLPSVC_ERROR_SLOT_ALREADY_OCCUPIED); return NULL; } // find an duplicate address if (NULL != Find(DeviceId)) { ::SetLastError(NDASHLPSVC_ERROR_DUPLICATE_DEVICE_ENTRY); return NULL; } // register PCNdasDevice pDevice = new CNdasDevice(dwSlotNo, DeviceId); if (NULL == pDevice) { // memory allocation failed // No need to set error here! return NULL; } pDevice->AddRef(); BOOL fSuccess = pDevice->Initialize(); if (!fSuccess) { // DebugPrintError((ERROR_T("Device initialization failed!"))); pDevice->Release(); return NULL; } m_pbSlotOccupied[dwSlotNo] = TRUE; bool insertResult; insertResult = m_deviceSlotMap.insert(DeviceSlotMap::value_type(dwSlotNo, pDevice)).second; _ASSERTE(insertResult == true); insertResult = m_deviceIdMap.insert(DeviceIdMap::value_type(DeviceId, pDevice)).second; _ASSERTE(insertResult == true); _ASSERTE(m_deviceSlotMap.size() == m_deviceIdMap.size()); TCHAR szContainer[30]; HRESULT hr = ::StringCchPrintf(szContainer, 30, TEXT("Devices\\%04d"), dwSlotNo); _ASSERT(SUCCEEDED(hr)); fSuccess = _NdasSystemCfg.SetSecureValueEx( szContainer, _T("DeviceId"), &DeviceId, sizeof(DeviceId)); if (!fSuccess) { DPWarningEx( _FT("Writing registration entry to the registry failed at %s.\n"), szContainer); } // // During bootstrapping, we do not publish this event // Bootstrapper will do this later. // if (!m_fBootstrapping) { CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->DeviceEntryChanged(); } return pDevice; }