LRESULT CNdasServiceDeviceEventHandler:: OnDeviceHandleQueryRemoveFailed( PDEV_BROADCAST_HANDLE pdbch) { XTLTRACE2(TCPnp, TLInfo, "OnDeviceHandleQueryRemoveFailed: Device Handle %p, Notify Handle %p\n", pdbch->dbch_handle, pdbch->dbch_hdevnotify); DeviceNotifyData notifyData; if (!FindDeviceHandle(pdbch->dbch_hdevnotify, notifyData)) { XTLTRACE2(TCPnp, TLInfo, "Notify Handle is not registered.\n"); return TRUE; } XTLTRACE2(TCPnp, TLInfo, "LogDeviceSlotNo %ls, Type %d\n", CNdasScsiLocation(notifyData.NdasScsiLocation).ToString(), DeviceNotifyDataTypeString(notifyData.Type)); // // DEVNOTIFYINFO_TYPE_STORAGEPORT is the only notification we are // interested in. However, when a CDROM device attached to the storage port, // the storage port device notification for QueryRemoveFailed is not // sent to us. So, we also need to handle CD-ROM. // // Do not worry about redundant calls to pLogDevice->OnUnmountFailed(). // It only cares if NDAS_LOGICALDEVICE_STATUS is UNMOUNT_PENDING, // which means backup calls will be ignored. // switch (notifyData.Type) { case DeviceNotifyData::DNTStoragePort: case DeviceNotifyData::DNTCdRom: case DeviceNotifyData::DNTDisk: { CNdasLogicalDevicePtr pLogDevice = pGetNdasLogicalDevice(notifyData.NdasScsiLocation); if (CNdasLogicalDeviceNullPtr == pLogDevice) { XTLTRACE2(TCPnp, TLWarning, "Logical Device not found at %ls.\n", CNdasScsiLocation(notifyData.NdasScsiLocation).ToString()); return TRUE; } pLogDevice->OnUnmountFailed(); } break; default: break; } return TRUE; }
BOOL CNdasLogicalDevice::Unplug() { BOOL fSuccess(FALSE); ximeta::CAutoLock autolock(this); DBGPRT_INFO(_FT("Unplugging %s\n"), ToString()); if (m_status == NDAS_LOGICALDEVICE_STATUS_NOT_INITIALIZED) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_NOT_INITIALIZED); return FALSE; } if (m_status != NDAS_LOGICALDEVICE_STATUS_MOUNTED && m_status != NDAS_LOGICALDEVICE_STATUS_MOUNT_PENDING && m_status != NDAS_LOGICALDEVICE_STATUS_UNMOUNT_PENDING) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_NOT_MOUNTED); return FALSE; } // // Remove target ejects the disk and the volume. // fSuccess = LsBusCtlRemoveTarget(m_NdasScsiLocation.SlotNo); if (!fSuccess) { DBGPRT_WARN_EX(_FT("LsBusCtlRemoveTarget failed: ")); } // Intentional break ::Sleep(100); // // BUG: // What happened when RemoveTarget succeeded and // Unplugging LANSCSI port is failed? // fSuccess = LsBusCtlUnplug(m_NdasScsiLocation.SlotNo); if (!fSuccess) { DBGPRT_ERR_EX(_FT("LsBusCtlUnplug failed: ")); // last error from lsbusctl unplug return FALSE; } // // Change the status to unmounted // SetStatus(NDAS_LOGICALDEVICE_STATUS_UNMOUNTED); DBGPRT_INFO(_FT("Unplugged successfully at slot %s.\n"), CNdasScsiLocation(m_NdasScsiLocation).ToString()); return TRUE; }
BOOL CNdasLogicalDeviceManager::UnregisterNdasScsiLocation( CONST NDAS_SCSI_LOCATION& location) { ximeta::CAutoLock autolock(this); LocationMap::size_type nErased = m_NdasScsiLocationMap.erase(location); if (1 != nErased) { DBGPRT_WARN( _FT("NdasScsiLocation not registered at %s"), CNdasScsiLocation(location).ToString()); } _ASSERTE(1 == nErased); return (1 == nErased); }
BOOL CNdasLogicalDevice::Recover() { BOOL fSuccess(FALSE); ximeta::CAutoLock autolock(this); DBGPRT_INFO(_FT("Recovering %s\n"), ToString()); switch(GetType()) { case NDAS_LOGICALDEVICE_TYPE_DISK_RAID1: case NDAS_LOGICALDEVICE_TYPE_DISK_RAID4: break; default: return FALSE; } if (m_status == NDAS_LOGICALDEVICE_STATUS_NOT_INITIALIZED) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_NOT_INITIALIZED); return FALSE; } if (m_status != NDAS_LOGICALDEVICE_STATUS_MOUNTED) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_NOT_MOUNTED); return FALSE; } // Do not recover if any NDAS unit device is not alive DWORD ldSequence = 0; for(ldSequence = 0; ldSequence < m_logicalDeviceGroup.nUnitDevices; ldSequence++) { if(NDAS_UNITDEVICE_STATUS_MOUNTED != m_pUnitDevices[ldSequence]->GetStatus()) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_UNITDEVICE_NOT_MOUNTED); return FALSE; } } if(IsAnyUnitDevicesFault()) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_UNITDEVICE_NOT_MOUNTED); return FALSE; } ULONG ulStatus; fSuccess = ::LsBusCtlQueryStatus( m_NdasScsiLocation.SlotNo, &ulStatus); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Unable to get status")); return FALSE; } // Do not recover if NDAS logical device is not under emergency // Do not recover if NDAS logical device is already recovering if(!ADAPTERINFO_ISSTATUSFLAG(ulStatus, ADAPTERINFO_STATUSFLAG_MEMBER_FAULT)) { DBGPRT_ERR_EX(_FT("Not in emergency mode or already recovering")); return FALSE; } // // LsBusCtl is overhauled only to use SlotNo for RemoveTargetData // // // Remove target ejects the disk and the volume. // fSuccess = LsBusCtlRecoverTarget(m_NdasScsiLocation.SlotNo); if (!fSuccess) { DBGPRT_WARN_EX(_FT("LsBusCtlRemoveTarget failed: ")); } DBGPRT_INFO(_FT("Started recovering successfully at slot %s.\n"), CNdasScsiLocation(m_NdasScsiLocation).ToString()); return TRUE; }
LRESULT CNdasServiceDeviceEventHandler:: OnDeviceHandleRemoveComplete( PDEV_BROADCAST_HANDLE pdbch) { // // Device Handle Remove Complete is called on Surprise Removal // XTLTRACE2(TCPnp, TLInfo, "OnDeviceHandleRemoveComplete: Device Handle %p, Notify Handle %p\n", pdbch->dbch_handle, pdbch->dbch_hdevnotify); DeviceNotifyData notifyData; if (!FindDeviceHandle(pdbch->dbch_hdevnotify, notifyData)) { XTLTRACE2(TCPnp, TLInfo, "Notify Handle is not registered.\n"); return TRUE; } // Erase from the map XTLVERIFY(1 == m_DevNotifyMap.erase(pdbch->dbch_hdevnotify)); BOOL fSuccess = ::UnregisterDeviceNotification(pdbch->dbch_hdevnotify); if (!fSuccess) { XTLTRACE2(TCPnp, TLWarning, "Unregistering a device notification to %p failed.\n", pdbch->dbch_hdevnotify); } switch (notifyData.Type) { case DeviceNotifyData::DNTStoragePort: { // // Remove removal is completed for NDAS SCSI Controller // CNdasLogicalDevicePtr pLogDevice = pGetNdasLogicalDevice(notifyData.NdasScsiLocation); if (CNdasLogicalDeviceNullPtr == pLogDevice) { XTLTRACE2(TCPnp, TLWarning, "Logical Device not found at %ls.\n", CNdasScsiLocation(notifyData.NdasScsiLocation).ToString()); } else { pLogDevice->OnUnmounted(); } } break; case DeviceNotifyData::DNTDisk: { XTLTRACE2(TCPnp, TLInfo, "Disk Remove Complete(%ls)\n", CNdasScsiLocation(notifyData.NdasScsiLocation).ToString()); } break; case DeviceNotifyData::DNTCdRom: { XTLTRACE2(TCPnp, TLInfo, "CDROM Remove Complete(%ls)\n", CNdasScsiLocation(notifyData.NdasScsiLocation).ToString()); } break; case DeviceNotifyData::DNTVolume: { XTLTRACE2(TCPnp, TLInfo, "Volume Remove Complete(%ls)\n", CNdasScsiLocation(notifyData.NdasScsiLocation).ToString()); } break; default: // We do not care about other types at this time. break; } return TRUE; }