BOOL WINAPI NdasDmGetNdasLogDevSlotNoOfDisk(HANDLE hDisk, LPDWORD lpdwSlotNo) { _ASSERTE(INVALID_HANDLE_VALUE != hDisk); _ASSERTE(NULL != hDisk); _ASSERTE(!IsBadWritePtr(lpdwSlotNo, sizeof(DWORD))); BOOL fSuccess(FALSE); DWORD dwScsiPortNumber; fSuccess = NdasDmGetScsiPortNumberOfDisk(hDisk, &dwScsiPortNumber); if (!fSuccess) { DPError(_FT("NdasDmGetScsiPortNumberOfDisk(%p) failed.\n"), hDisk); return FALSE; } fSuccess = NdasDmGetNdasLogDevSlotNoOfScsiPort(dwScsiPortNumber, lpdwSlotNo); if (!fSuccess) { DPError(_FT("NdasDmGetNdasLogDevSlotNoOfScsiPort(%d) failed.\n"), dwScsiPortNumber); return FALSE; } return TRUE; }
BOOL CNdasDeviceComm::GetDiskInfoBlock(PNDAS_DIB pDiskInfoBlock) { _ASSERTE(m_bInitialized && "CNdasDeviceComm is not initialized"); _ASSERTE(pDiskInfoBlock != NULL); // // Read Last Sector for NDAS_UNITDISK_INFORMATION_BLOCK // unsigned _int8 ui8IdeResponse; PTARGET_DATA pTargetData = &m_lspath.PerTarget[m_dwUnitNo]; UINT64 ui64DiskBlock = pTargetData->SectorCount - 1; INT iResult = IdeCommand( &m_lspath, m_dwUnitNo, 0, WIN_READ, ui64DiskBlock, 1, 0, (PCHAR) pDiskInfoBlock, &ui8IdeResponse); if (0 != iResult) { DPError(_FT("IdeCommand failed with error %d, ide response %d.\n"), iResult, ui8IdeResponse); return FALSE; } return TRUE; }
BOOL WINAPI NdasDmGetScsiPortNumberOfDisk( IN DWORD dwPhysicalDiskNumber, OUT LPDWORD lpdwScsiPortNumber) { _ASSERTE(!IsBadWritePtr(lpdwScsiPortNumber, sizeof(DWORD))); // // make up Physical Drive Name // TCHAR szDiskDevicePath[_MAX_PATH + 1]; HRESULT hr = ::StringCchPrintf( szDiskDevicePath, _MAX_PATH + 1, _T("\\\\.\\PHYSICALDRIVE%d"), dwPhysicalDiskNumber); _ASSERT(SUCCEEDED(hr)); DPInfo(_FT("Disk Device Path:%s\n"), szDiskDevicePath); // // open the disk device // DPTrace(_FT("CreateFile(%s)\n"), szDiskDevicePath); HANDLE hDisk = ::CreateFile( szDiskDevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDisk) { DPErrorEx(_FT("CreateFile(%s) failed: "), szDiskDevicePath); return FALSE; } // // Get SCSI Port Number of the Disk // BOOL fSuccess = NdasDmGetScsiPortNumberOfDisk(hDisk, lpdwScsiPortNumber); if (!fSuccess) { DPError(_FT("NdasDmGetScsiPortNumberOfDisk(%s) failed.\n"), szDiskDevicePath); (VOID) ::CloseHandle(hDisk); return FALSE; } (VOID) ::CloseHandle(hDisk); return TRUE; }
BOOL CNdasDeviceComm::ReadDiskBlock(PBYTE pBlockBuffer, INT64 i64DiskBlock, INT32 i32BlockSize) { _ASSERTE(m_bInitialized && "CNdasDeviceComm is not initialized"); _ASSERTE(pBlockBuffer != NULL); _ASSERTE(i32BlockSize >= 1 && i32BlockSize <= 128); _ASSERTE(!::IsBadWritePtr(pBlockBuffer, i32BlockSize * 512)); // // Read Last Sector for NDAS_UNITDISK_INFORMATION_BLOCK // UINT8 ui8IdeResponse; PTARGET_DATA pTargetData = &m_lspath.PerTarget[m_dwUnitNo]; INT64 i64AbsoluteBlock = (i64DiskBlock >= 0) ? i64DiskBlock : (INT64)pTargetData->SectorCount + i64DiskBlock; INT iResult = IdeCommand( &m_lspath, m_dwUnitNo, 0, WIN_READ, i64AbsoluteBlock, (INT16)i32BlockSize, 0, (PCHAR) pBlockBuffer, &ui8IdeResponse); if (0 != iResult) { DPError(_FT("IdeCommand failed with error %d, ide response %d.\n"), iResult, ui8IdeResponse); return FALSE; } return TRUE; }
BOOL WINAPI NdasDmGetNdasLogDevSlotNoOfScsiPort( HANDLE hScsiPort, LPDWORD lpdwSlotNo) { // // Make up IOCTL In-parameter // LANSCSIMINIPORT_IOCTL_GET_SLOT_NO to get Logical Device Slot No // BOOL fSuccess(FALSE); const DWORD cbHeader = sizeof(SRB_IO_CONTROL); const DWORD cbData = sizeof(ULONG); const DWORD cbInBuffer = cbHeader + cbData; DWORD cbReturned(0); BYTE lpInBuffer[cbInBuffer]; ::ZeroMemory(lpInBuffer, cbInBuffer); PSRB_IO_CONTROL pSrbIoControl = (PSRB_IO_CONTROL) lpInBuffer; pSrbIoControl->HeaderLength = cbHeader; ::CopyMemory(pSrbIoControl->Signature, LANSCSIMINIPORT_IOCTL_SIGNATURE, 8); pSrbIoControl->Timeout = 10; pSrbIoControl->ControlCode = LANSCSIMINIPORT_IOCTL_GET_SLOT_NO; pSrbIoControl->Length = cbData; // // Get Logical Device Slot No // fSuccess = ::DeviceIoControl( hScsiPort, IOCTL_SCSI_MINIPORT, lpInBuffer, cbInBuffer, lpInBuffer, // we use the same buffer for output cbInBuffer, &cbReturned, NULL); if (!fSuccess) { DPErrorEx(_FT("DeviceIoControl(IOCTL_SCSI_MINIPORT,") _T("LANSCSIMINIPORT_IOCTL_GET_SLOT_NO) failed: ")); return FALSE; } if (0 != pSrbIoControl->ReturnCode) { DPError(_FT("DeviceIoControl(IOCTL_SCSI_MINIPORT,") _T("LANSCSIMINIPORT_IOCTL_GET_SLOT_NO) returned SrbIoControl error %d.\n"), pSrbIoControl->ReturnCode); ::SetLastError(NDASDM_ERROR_SRB_IO_CONTROL_ERROR); return FALSE; } // // Calculate the slot number offset and retrieve the value // ULONG* lpdwSlotNoOut = (ULONG*)(lpInBuffer + cbHeader); *lpdwSlotNo = *lpdwSlotNoOut; DPInfo(_FT("NDAS Logical Device Slot: %d\n"), *lpdwSlotNo); return TRUE; }
BOOL WINAPI NdasDmGetNdasLogDevSlotNoOfScsiPort( LPCWSTR wszDbccName, LPDWORD lpdwSlotNo) { _ASSERTE(!IsBadWritePtr(lpdwSlotNo, sizeof(DWORD))); _ASSERTE(!IsBadStringPtr(wszDbccName, _MAX_PATH)); DPInfo(_FT("NdasDmGetNdasLogDevSlotNoOfScsiPort got %s.\n"), wszDbccName); // // extract the last string between '&' and '#', which has slot number and unitdisk numer // // example of dbcc_name at logical device slot no 10 // // \\?\lanscsibus#netdisk_v0#1&1a590e2c&5&10#{2accfe60-c130-11d2-b082-00a0c91efb8b} // ^^^^ if (!NdasDmIsLANSCSIPortInterface(wszDbccName)) { DPInfo(_FT("Non-LANSCSI Port Interface Name.\n")); return FALSE; } // skip LANSCSIIDDEV_IFDW LPCWSTR pwszLeftBound = &wszDbccName[LANSCSI_DEV_IFIDW_LEN]; // pwszLeftBound now points to // \\?\lanscsibus#netdisk_v0#1&1a590e2c&5&10#{2accfe60-c130-11d2-b082-00a0c91efb8b} // ^ // left bound while (*pwszLeftBound != L'#') { if (*pwszLeftBound == L'\0') { DPError(_FT("Slot Number Parse Error at left bound!\n")); return FALSE; // invalid! } ++pwszLeftBound; } // pwszpwszLeftBound now points to // \\?\lanscsibus#netdisk_v0#1&1a590e2c&5&10#{2accfe60-c130-11d2-b082-00a0c91efb8b} // ^ // left bound LPCWSTR pwszRightBound = pwszLeftBound + 1; while (*pwszRightBound != L'#') { if (*pwszRightBound == L'\0') { DPError(_FT("Slot Number Parse Error at right bound!\n")); return FALSE; // invalid! } ++pwszRightBound; } // pwszRightBound now points to // \\?\lanscsibus#netdisk_v0#1&1a590e2c&5&10#{2accfe60-c130-11d2-b082-00a0c91efb8b} // ^ ^ // left bound right bound LPCWSTR pwszSlotStart = pwszRightBound - 1; while (*pwszSlotStart != L'&') { if (pwszSlotStart <= pwszLeftBound) { DPError(_FT("Slot Number Parse Error at slot start bound!\n")); return FALSE; } --pwszSlotStart; } // pwszRightBound now points to // \\?\lanscsibus#netdisk_v0#1&1a590e2c&5&10#{2accfe60-c130-11d2-b082-00a0c91efb8b} // ^ ^ ^ // left bound | right bound // slot start if (pwszSlotStart + 1 == pwszRightBound) { // &# -> no slot number DPError(_FT("Slot Number Parse Error at slot start bound!\n")); return FALSE; } WCHAR szSlotNo[10]; LPCWSTR pch = pwszSlotStart + 1; DWORD i(0); for (; pch < pwszRightBound && i < 9; ++i, ++pch) { szSlotNo[i] = *pch; } szSlotNo[i] = L'\0'; DWORD dwSlotNo = _wtoi(szSlotNo); if (dwSlotNo == 0) { DPError(_FT("Invalid slot number (%s) -> (%d)\n"), szSlotNo, dwSlotNo); return FALSE; } *lpdwSlotNo = dwSlotNo; DPInfo(_FT("Slot no is %d.\n"), dwSlotNo); return TRUE; }
BOOL WINAPI NdasDmGetNdasLogDevSlotNoOfVolume( HANDLE hVolume, LPDWORD lpdwSlotNo, DWORD nBuffer, LPDWORD lpdwBufferUsed) { _ASSERTE(INVALID_HANDLE_VALUE != hVolume); _ASSERTE(NULL != hVolume); _ASSERTE(!IsBadWritePtr(lpdwSlotNo, sizeof(DWORD) * nBuffer)); _ASSERTE(!IsBadWritePtr(lpdwBufferUsed, sizeof(DWORD))); BOOL fSuccess(FALSE); // // Get the physical disk numbers of the volume // DWORD pDiskNumbers[256]; DWORD nDiskNumbers; fSuccess = NdasDmGetDiskNumbersOfVolume(hVolume, pDiskNumbers, 256, &nDiskNumbers); if (!fSuccess) { DPError(_FT("NdasDmGetDiskNumbersOfVolume failed.\n")); return FALSE; } // // Get SCSI port number for each disks // // TODO: Resolve this problem! // What if the volume is spanned through NDAS Logical Disks and // OS's regular Disks? // *lpdwBufferUsed = 0; for (DWORD i = 0; i < nDiskNumbers; ++i) { if (*lpdwBufferUsed >= nBuffer) { DPError(_FT("Insufficient Slot Buffer.\n")); ::SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } DWORD dwDiskNumber = pDiskNumbers[i]; DWORD dwScsiPortNumber; fSuccess = NdasDmGetScsiPortNumberOfDisk(dwDiskNumber, &dwScsiPortNumber); if (!fSuccess) { DPErrorEx(_FT("NdasDmGetScsiPortNumberOfDisk(%d) failed: "), dwDiskNumber); return FALSE; } DWORD dwSlotNo; fSuccess = NdasDmGetNdasLogDevSlotNoOfScsiPort(dwScsiPortNumber, &dwSlotNo); if (!fSuccess) { DPErrorEx(_FT("NdasDmGetNdasLogDevSlotNoOfScsiPort(%d) failed: "), dwScsiPortNumber); return FALSE; } BOOL bDuplicate(FALSE); for (DWORD j = 0; j < *lpdwBufferUsed; ++j) { if (lpdwSlotNo[j] == dwSlotNo) { bDuplicate = TRUE; break; } } if (!bDuplicate) { lpdwSlotNo[*lpdwBufferUsed] = dwSlotNo; (*lpdwBufferUsed)++; } } return TRUE; }
BOOL WINAPI NdasDmGetNdasLogDevSlotNoOfScsiPort( DWORD dwScsiPortNumber, LPDWORD lpdwSlotNo) { BOOL fSuccess(FALSE); // // Make up SCSI Port Name // TCHAR szScsiPortName[_MAX_PATH + 1]; HRESULT hr = ::StringCchPrintf( szScsiPortName, _MAX_PATH + 1, TEXT("\\\\.\\Scsi%d:"), dwScsiPortNumber); DPInfo(_FT("SCSI Port Name: %s\n"), szScsiPortName); // // Open SCSI Port Device // HANDLE hScsiPort = ::CreateFile( szScsiPortName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hScsiPort) { DPErrorEx(_FT("CreateFile(%s) failed: "), szScsiPortName); return FALSE; } // // Make up IOCTL In-parameter // LANSCSIMINIPORT_IOCTL_GET_SLOT_NO to get Logical Device Slot No // const DWORD cbHeader = sizeof(SRB_IO_CONTROL); const DWORD cbData = sizeof(ULONG); const DWORD cbInBuffer = cbHeader + cbData; DWORD cbReturned(0); BYTE lpInBuffer[cbInBuffer]; ::ZeroMemory(lpInBuffer, cbInBuffer); PSRB_IO_CONTROL pSrbIoControl = (PSRB_IO_CONTROL) lpInBuffer; pSrbIoControl->HeaderLength = cbHeader; ::CopyMemory(pSrbIoControl->Signature, LANSCSIMINIPORT_IOCTL_SIGNATURE, 8); pSrbIoControl->Timeout = 10; pSrbIoControl->ControlCode = LANSCSIMINIPORT_IOCTL_GET_SLOT_NO; pSrbIoControl->Length = cbData; // // Get Logical Device Slot No // fSuccess = ::DeviceIoControl( hScsiPort, IOCTL_SCSI_MINIPORT, lpInBuffer, cbInBuffer, lpInBuffer, // we use the same buffer for output cbInBuffer, &cbReturned, NULL); if (!fSuccess) { DPErrorEx(_FT("DeviceIoControl(IOCTL_SCSI_MINIPORT,") _T("LANSCSIMINIPORT_IOCTL_GET_SLOT_NO) failed: ")); ::CloseHandle(hScsiPort); return FALSE; } if (0 != pSrbIoControl->ReturnCode) { DPError(_FT("DeviceIoControl(IOCTL_SCSI_MINIPORT,") _T("LANSCSIMINIPORT_IOCTL_GET_SLOT_NO) returned error %d.\n"), pSrbIoControl->ReturnCode); ::CloseHandle(hScsiPort); return FALSE; } // // Calculate the slot number offset and retrieve the value // ULONG* lpdwSlotNoOut = (ULONG*)(lpInBuffer + cbHeader); *lpdwSlotNo = *lpdwSlotNoOut; DPInfo(_FT("NDAS Logical Device Slot: %d\n"), *lpdwSlotNo); ::CloseHandle(hScsiPort); return TRUE; }
BOOL CNdasDeviceComm::GetUnitDeviceInformation(PNDAS_UNITDEVICE_INFORMATION pUnitDevInfo) { _ASSERTE(m_bInitialized && "CNdasDeviceComm is not initialized"); _ASSERTE(pUnitDevInfo != NULL); INT iResult = GetDiskInfo(&m_lspath, m_dwUnitNo); if (0 != iResult) { // TODO: LANDISK_ERROR_BADKEY? DPError(_FT("GetDiskInfo failed with error %d\n"), iResult); return FALSE; } PTARGET_DATA pTargetData = &m_lspath.PerTarget[m_dwUnitNo]; pUnitDevInfo->bLBA = pTargetData->bLBA; pUnitDevInfo->bLBA48 = pTargetData->bLBA48; pUnitDevInfo->bPIO = pTargetData->bPIO; pUnitDevInfo->bDMA = pTargetData->bDma; pUnitDevInfo->bUDMA = pTargetData->bUDma; pUnitDevInfo->MediaType = pTargetData->MediaType; pUnitDevInfo->dwROHosts = pTargetData->NRROHost; pUnitDevInfo->dwRWHosts = pTargetData->NRRWHost; pUnitDevInfo->SectorCount = pTargetData->SectorCount; #ifdef UNICODE // // What if FwRev, Model, SerialNo is not null terminated? // -> solved by terminating null between fields _ASSERTE(sizeof(pUnitDevInfo->szModel) / sizeof(pUnitDevInfo->szModel[0]) == sizeof(pTargetData->Model)); _ASSERTE(sizeof(pUnitDevInfo->szSerialNo) / sizeof(pUnitDevInfo->szSerialNo[0]) == sizeof(pTargetData->SerialNo)); _ASSERTE(sizeof(pUnitDevInfo->szFwRev) / sizeof(pUnitDevInfo->szFwRev[0]) == sizeof(pTargetData->FwRev)); ::MultiByteToWideChar( CP_ACP, 0, pTargetData->Model, sizeof(pTargetData->Model), pUnitDevInfo->szModel, sizeof(pUnitDevInfo->szModel) / sizeof(pUnitDevInfo->szModel[0])); ::MultiByteToWideChar( CP_ACP, 0, pTargetData->SerialNo, sizeof(pTargetData->SerialNo), pUnitDevInfo->szSerialNo, sizeof(pUnitDevInfo->szSerialNo) / sizeof(pUnitDevInfo->szSerialNo[0])); ::MultiByteToWideChar( CP_ACP, 0, pTargetData->FwRev, sizeof(pTargetData->FwRev), pUnitDevInfo->szFwRev, sizeof(pUnitDevInfo->szFwRev) / sizeof(pUnitDevInfo->szFwRev[0])); #else _ASSERTE(sizeof(pUnitDevInfo->szModel) == sizeof(pTargetData->Model)); _ASSERTE(sizeof(pUnitDevInfo->szFwRev) == sizeof(pTargetData->FwRev)); _ASSERTE(sizeof(pUnitDevInfo->szSerialNo) == sizeof(pTargetData->SerialNo)); ::CopyMemory(pUnitDevInfo->szModel, pTargetData->Model, sizeof(pTargetData->Model)); ::CopyMemory(pUnitDevInfo->szFwRev, pTargetData->FwRev, sizeof(pTargetData->FwRev)); ::CopyMemory(pUnitDevInfo->szSerialNo, pTargetData->SerialNo, sizeof(pTargetData->SerialNo)); #endif DPInfo(_FT("Model : %s\n"), pUnitDevInfo->szModel); DPInfo(_FT("Serial No : %s\n"), pUnitDevInfo->szSerialNo); DPInfo(_FT("Firmware Rev : %s\n"), pUnitDevInfo->szFwRev); return TRUE; }
static HANDLE CreatePipeConnection(LPOVERLAPPED lpOverlapped) { HANDLE hPipe = ::CreateFile( NDAS_EVENT_PIPE_NAME, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == hPipe) { DPErrorEx(_FT("Connecting to %s failed: "), NDAS_EVENT_PIPE_NAME); return INVALID_HANDLE_VALUE; } // // We should read the event version info immediately // NDAS_EVENT_MESSAGE message = {0}; DWORD cbMessage = sizeof(NDAS_EVENT_MESSAGE); DWORD cbRead(0); BOOL fSuccess = ::ReadFile( hPipe, &message, cbMessage, &cbRead, lpOverlapped); if (!fSuccess && ERROR_IO_PENDING != ::GetLastError()) { DPErrorEx(_FT("Retrieving version information failed on ReadFile: ")); ::CloseHandle(hPipe); return INVALID_HANDLE_VALUE; } if (fSuccess) { fSuccess = ::SetEvent(lpOverlapped->hEvent); _ASSERTE(fSuccess); } // // If we cannot retrieve the version information // in a timeout interval or the version information // is mismatch, an error is returned // const DWORD dwTimeout = 3000; // 3 sec timeout DWORD dwWaitResult = ::WaitForSingleObject( lpOverlapped->hEvent, dwTimeout); if (dwWaitResult == WAIT_TIMEOUT) { DPError(_FT("Retrieving version information timed out.")); ::CloseHandle(hPipe); return INVALID_HANDLE_VALUE; } if (dwWaitResult != WAIT_OBJECT_0) { DPErrorEx(_FT("Retrieving version information failed: ")); ::CloseHandle(hPipe); return INVALID_HANDLE_VALUE; } fSuccess = ::GetOverlappedResult( hPipe, lpOverlapped, &cbRead, TRUE); if (!fSuccess) { DPErrorEx(_FT("Getting overlapped result failed: ")); ::CloseHandle(hPipe); return INVALID_HANDLE_VALUE; } if (NDAS_EVENT_TYPE_VERSION_INFO != message.EventType) { DPError(_FT("Getting Event Version Info failed: ") _T("Type expected %d, received %d.\n"), NDAS_EVENT_TYPE_VERSION_INFO, message.EventType); ::CloseHandle(hPipe); ::SetLastError(NDASUSER_ERROR_EVENT_VERSION_MISMATCH); return INVALID_HANDLE_VALUE; } if (NDAS_EVENT_VERSION_MAJOR != message.VersionInfo.MajorVersion || NDAS_EVENT_VERSION_MINOR != message.VersionInfo.MinorVersion) { DPErrorEx(_FT("Event version mismatch: ") _T("Version expected %d.%d, received %d.%d"), NDAS_EVENT_VERSION_MAJOR, NDAS_EVENT_VERSION_MINOR, message.VersionInfo.MajorVersion, message.VersionInfo.MinorVersion); ::CloseHandle(hPipe); ::SetLastError(NDASUSER_ERROR_EVENT_VERSION_MISMATCH); return INVALID_HANDLE_VALUE; } return hPipe; }
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; }