BOOL CNdasAutoRegister::ProcessRegister( CONST NDAS_DEVICE_ID& deviceId, ACCESS_MASK autoRegAccess) { CNdasDeviceRegistrar* pRegistrar = pGetNdasDeviceRegistrar(); CRefObjPtr<CNdasDevice> pExistingDevice = pRegistrar->Find(deviceId); if (NULL != pExistingDevice.p) { return TRUE; } CRefObjPtr<CNdasDevice> pDevice = pRegistrar->Register(deviceId, TRUE, TRUE); if (NULL == pDevice.p) { return FALSE; } pDevice->SetGrantedAccess(autoRegAccess); BOOL fSuccess = pDevice->Enable(TRUE); if (!fSuccess) { DBGPRT_ERR(_FT("Enable failed: ")); } TCHAR szName[MAX_NDAS_DEVICE_NAME_LEN + 1]; HRESULT hr = ::StringCchPrintf(szName, MAX_NDAS_DEVICE_NAME_LEN + 1, _T("NDAS Device A%04d"), pDevice->GetSlotNo()); _ASSERTE(SUCCEEDED(hr)); pDevice->SetName(szName); return TRUE; }
ACCESS_MASK CNdasLogicalDevice::GetAllowingAccess() { ximeta::CAutoLock autolock(this); if (0 == GetUnitDeviceCount()) { return 0x00000000L; } ACCESS_MASK access(0xFFFFFFFFL); // // Any single missing entry will revoke all accesses // for (DWORD i = 0; i < GetUnitDeviceCount(); ++i) { CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(i); if (NULL == pUnitDevice.p) { return 0x00000000L; } access &= pUnitDevice->GetAllowingAccess(); } return access; }
BOOL CNdasLogicalDevice::IsVolatile() { ximeta::CAutoLock autolock(this); DWORD nUnitDevices = GetUnitDeviceCount(); for (DWORD i = 0; i < nUnitDevices; ++i) { CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(i); // Unit Device can be null if (NULL == pUnitDevice.p) continue; CRefObjPtr<CNdasDevice> pDevice = pUnitDevice->GetParentDevice(); // If unit device is not null, parent device cannot be null _ASSERTE(NULL != pDevice.p); if (pDevice->IsVolatile()) { // If any single device is volatile, then it's volatile. return TRUE; } } // Otherwise, we don't consider it volatile. return FALSE; }
CNdasLogicalDevice* CNdasLogicalDeviceManager::Register(CNdasUnitDevice& unitDevice) { ximeta::CAutoLock autolock(this); CONST NDAS_LOGICALDEVICE_GROUP& ldGroup = unitDevice.GetLDGroup(); DWORD ldSequence = unitDevice.GetLDSequence(); CNdasLogicalDevice* pLogDevice = NULL; LDGroupMap::iterator itr = m_LDGroupMap.find(ldGroup); if (itr == m_LDGroupMap.end()) { // // New Logical Device Instance // NDAS_LOGICALDEVICE_ID id = cpAllocateID(); if (0 == id) { // SLOT FULL ::SetLastError(NDASSVC_ERROR_LOGICALDEVICE_SLOT_FULL); return NULL; } pLogDevice = new CNdasLogicalDevice(id, ldGroup); if (NULL == pLogDevice) { ::SetLastError(ERROR_OUTOFMEMORY); return NULL; } BOOL fSuccess = pLogDevice->Initialize(); if (!fSuccess) { delete pLogDevice; return NULL; } pLogDevice->AddRef(); // internal pointer reference m_LDGroupMap.insert(LDGroupMap::value_type(ldGroup, pLogDevice)); m_LDIDMap.insert(LDIDMap::value_type(id, pLogDevice)); CRefObjPtr<CNdasDevice> pDevice = unitDevice.GetParentDevice(); _ASSERTE(NULL != pDevice.p); if (pDevice->IsAutoRegistered()) { pLogDevice->SetMountOnReady(pDevice->GetGrantedAccess()); // auto registered devices always ignore RiskyMountFlag pLogDevice->SetRiskyMountFlag(FALSE); } } else { pLogDevice = itr->second; } BOOL fSuccess = pLogDevice->AddUnitDevice(unitDevice); _ASSERTE(fSuccess); if (!fSuccess) { return NULL; } if (NULL != pLogDevice) pLogDevice->AddRef(); // external pointer reference return pLogDevice; }
static void CheckUnitDeviceOnUnmount(CNdasUnitDevice* pUnitDevice) { if (pUnitDevice) { CRefObjPtr<CNdasDevice> pDevice = pUnitDevice->GetParentDevice(); if (NULL != pDevice.p) { (VOID) pDevice->UpdateDeviceInfo(); } } }
VOID CNdasLogicalDevice::SetStatus(NDAS_LOGICALDEVICE_STATUS newStatus) { ximeta::CAutoLock autolock(this); // // Ignore duplicate status change // if (m_status == newStatus) { return; } NDAS_LOGICALDEVICE_STATUS oldStatus = m_status; BOOL fValid = pCheckStatusValidity(m_status, newStatus); _ASSERTE(fValid); m_status = newStatus; // Update Unit Device Status for (DWORD i = 0; i < GetUnitDeviceCount(); ++i) { CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(i); if (NULL == pUnitDevice.p) { DBGPRT_ERR(_FT("Unit Device %s is not found.\n"), CNdasUnitDeviceId(GetUnitDeviceID(i)).ToString()); continue; } // // TODO: Create a status updater with observer // switch (m_status) { case NDAS_LOGICALDEVICE_STATUS_MOUNTED: case NDAS_LOGICALDEVICE_STATUS_MOUNT_PENDING: case NDAS_LOGICALDEVICE_STATUS_UNMOUNT_PENDING: pUnitDevice->SetStatus(NDAS_UNITDEVICE_STATUS_MOUNTED); break; default: // otherwise pUnitDevice->SetStatus(NDAS_UNITDEVICE_STATUS_NOT_MOUNTED); } } // publish a status change event (VOID) pGetNdasEventPublisher()-> LogicalDeviceStatusChanged(m_logicalDeviceId, oldStatus, newStatus); }
const NDAS_CONTENT_ENCRYPT* CNdasLogicalDevice::GetContentEncrypt() { CRefObjPtr<CNdasUnitDevice> pPrimaryUnitDevice = GetUnitDevice(0); if (NULL == pPrimaryUnitDevice.p) { return NULL; } if (NDAS_UNITDEVICE_TYPE_DISK != pPrimaryUnitDevice->GetType()) { return NULL; } CNdasUnitDiskDevice* pUnitDiskDevice = reinterpret_cast<CNdasUnitDiskDevice*>(pPrimaryUnitDevice.p); m_contentEncrypt = pUnitDiskDevice->GetEncryption(); return &m_contentEncrypt; }
BOOL CNdasLogicalDeviceManager::Unregister(CNdasUnitDevice& unitDevice) { ximeta::CAutoLock autolock(this); CRefObjPtr<CNdasLogicalDevice> pLogDevice = unitDevice.GetLogicalDevice(); if (NULL == pLogDevice.p) { return FALSE; } DWORD ldSequence = unitDevice.GetLDSequence(); pLogDevice->RemoveUnitDevice(unitDevice); if (pLogDevice->GetUnitDeviceInstanceCount() == 0) { NDAS_LOGICALDEVICE_ID id = pLogDevice->GetLogicalDeviceId(); LDGroupMap::size_type ldg_erased = m_LDGroupMap.erase(pLogDevice->GetLDGroup()); _ASSERTE(1 == ldg_erased); LDIDMap::size_type id_erased = m_LDIDMap.erase(id); _ASSERTE(1 == id_erased); pLogDevice->Release(); BOOL fSuccess = cpDeallocateID(id); _ASSERTE(fSuccess); } return TRUE; }
DWORD CNdasLogicalDevice::cpGetMaxRequestBlocks() { ximeta::CAutoLock autolock(this); // // MaxRequestBlock is a NDAS Device's dependent property // So we only have to look at NDAS devices // DWORD dwMaxRequestBlocks(0); for (DWORD i = 0; i < GetUnitDeviceCount(); i++) { CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(i); if (NULL == pUnitDevice.p) { return 0; } if (0 == i) { dwMaxRequestBlocks = pUnitDevice->GetOptimalMaxRequestBlock(); } else { dwMaxRequestBlocks = min(dwMaxRequestBlocks, pUnitDevice->GetOptimalMaxRequestBlock()); } } m_dwCurrentMRB = dwMaxRequestBlocks; return dwMaxRequestBlocks; }
BOOL CNdasLogicalDevice::PlugIn(ACCESS_MASK requestingAccess) { ximeta::CAutoLock autolock(this); BOOL fPSWriteShare = IsPSWriteShareCapable(); BOOL fSuccess = cpCheckPlugInCondition(requestingAccess); if (!fSuccess) { return FALSE; } // // Plug In // - NDAS Controller // CRefObjPtr<CNdasUnitDevice> pPrimaryUnitDevice = GetUnitDevice(0); if (NULL == pPrimaryUnitDevice.p) { SetLastDeviceError(NDAS_LOGICALDEVICE_ERROR_MISSING_MEMBER); ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_MEMBER_MISSING); return FALSE; } CRefObjPtr<CNdasDevice> pDevice = pPrimaryUnitDevice->GetParentDevice(); if (NULL == pDevice.p) { SetLastDeviceError(NDAS_LOGICALDEVICE_ERROR_MISSING_MEMBER); ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_MEMBER_MISSING); } // // Max DVD Instance (Global Instance) Constraint // // Do not allow local host to have multiple DVD devices // with Write Access. // I-O Data's request? // #if NDAS_FEATURE_DONOT_ALLOW_MULTIPLE_DVD_RW_INSTANCES if (NDAS_LOGICALDEVICE_TYPE_DVD == GetType()) { fSuccess = cpCheckPlugInCondForDVD(requestingAccess); if (!fSuccess) { // SetLastError is set by the pCheckPlugInCondForDVD return FALSE; } } #endif // // Resetting an event always succeeds if the handle is valid // fSuccess = ::ResetEvent(m_hDisconnectedEvent); _ASSERTE(fSuccess); fSuccess = ::ResetEvent(m_hAlarmEvent); _ASSERTE(fSuccess); // // Add Target // - Add a disk device to the NDAS controller // SIZE_T cbAddTargetDataSize = sizeof(LANSCSI_ADD_TARGET_DATA) - sizeof(LSBUS_UNITDISK) + GetUnitDeviceCount() * sizeof(LSBUS_UNITDISK); PLANSCSI_ADD_TARGET_DATA pAddTargetData = (PLANSCSI_ADD_TARGET_DATA) ::HeapAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, cbAddTargetDataSize); if (NULL == pAddTargetData) { // TODO: Out of memory return FALSE; } // automatically free the heap when it goes out of the scope AutoProcessHeap autoHeap = pAddTargetData; UCHAR ucTargetType = pConvertToLSBusTargetType(m_logicalDeviceGroup.Type); pAddTargetData->ulSize = cbAddTargetDataSize; pAddTargetData->ulSlotNo = m_NdasScsiLocation.SlotNo; pAddTargetData->ulTargetBlocks = 0; // initialization and will be added pAddTargetData->DesiredAccess = requestingAccess; pAddTargetData->ulNumberOfUnitDiskList = GetUnitDeviceCount(); pAddTargetData->ucTargetType = ucTargetType; // if PSWriteShare is not capable, we should specify the LUROption // to turn off the PSWriteShare explicitly. DWORD dwLUROptions = 0; { BOOL fConfigured = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("LUROptions"), &dwLUROptions); if (!fConfigured) { // revert to default for safety dwLUROptions = 0; } } if (!fPSWriteShare) { dwLUROptions |= LUROPTION_OFF_WRITESHARE_PS; dwLUROptions &= ~(LUROPTION_ON_WRITESHARE_PS); } pAddTargetData->LurOptions = dwLUROptions; // Set Content Encryption from the primary unit device // (Only for Disk Devices) if (NDAS_UNITDEVICE_TYPE_DISK == pPrimaryUnitDevice->GetType()) { CNdasUnitDiskDevice* pUnitDiskDevice = reinterpret_cast<CNdasUnitDiskDevice*>(pPrimaryUnitDevice.p); CONST NDAS_CONTENT_ENCRYPT& encrypt = pUnitDiskDevice->GetEncryption(); pAddTargetData->CntEcrKeyLength = encrypt.KeyLength; pAddTargetData->CntEcrMethod = encrypt.Method; ::CopyMemory( pAddTargetData->CntEcrKey, encrypt.Key, encrypt.KeyLength); } if (NDASSCSI_TYPE_DISK_RAID1 == ucTargetType || NDASSCSI_TYPE_DISK_RAID4 == ucTargetType) { CNdasUnitDiskDevice* pUnitDiskDevice = reinterpret_cast<CNdasUnitDiskDevice*>(pPrimaryUnitDevice.p); _ASSERTE(NULL != pUnitDiskDevice->GetAddTargetInfo()); ::CopyMemory( &pAddTargetData->RAID_Info, pUnitDiskDevice->GetAddTargetInfo(), sizeof(INFO_RAID)); if (0 == pAddTargetData->RAID_Info.SectorsPerBit) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_INVALID_BIND_INFORMATION); return FALSE; } } for (DWORD i = 0; i < GetUnitDeviceCount(); ++i) { CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(i); if (NULL == pUnitDevice.p) { SetLastDeviceError(NDAS_LOGICALDEVICE_ERROR_MISSING_MEMBER); ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_MEMBER_MISSING); return FALSE; } CRefObjPtr<CNdasDevice> pDevice = pUnitDevice->GetParentDevice(); _ASSERTE(NULL != pDevice.p); PLSBUS_UNITDISK pud = &pAddTargetData->UnitDiskList[i]; ::CopyMemory( pud->Address.Node, pDevice->GetRemoteLpxAddress().Node, sizeof(pud->Address.Node)); pud->Address.Port = htons(NDAS_DEVICE_LPX_PORT); C_ASSERT( sizeof(pud->NICAddr.Node) == sizeof(pDevice->GetLocalLpxAddress().Node)); ::CopyMemory( pud->NICAddr.Node, pDevice->GetLocalLpxAddress().Node, sizeof(pud->NICAddr.Node)); pud->NICAddr.Port = htons(0); // should be zero pud->iUserID = pUnitDevice->GetDeviceUserID(requestingAccess); pud->iPassword = pUnitDevice->GetDevicePassword(); pud->ulUnitBlocks = pUnitDevice->GetUserBlockCount(); pud->ulPhysicalBlocks = pUnitDevice->GetPhysicalBlockCount(); pud->ucUnitNumber = pUnitDevice->GetUnitNo(); pud->ucHWType = pDevice->GetHWType(); pud->ucHWVersion = pDevice->GetHWVersion(); pud->IsWANConnection = FALSE; // // Set Reconnect Retry Count, Retry Interval // if overridden by the user // // default: // ReconnTrial = 19, ReconnInterval = 3000 // // reddotnet: (will be set by the installer) // ReconnTrial = 2, ReconnInterval = 3000 // { BOOL fOverride = FALSE; BOOL fConfigured = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("OverrideLogDevReconnect"), &fOverride); if (!fConfigured) { fOverride = FALSE; } if (fOverride) { static const DWORD LOGDEV_RECONNECT_DEFAULT = 19; static const DWORD LOGDEV_RECONNECT_MAX = 19; DWORD dwReconnect = LOGDEV_RECONNECT_DEFAULT; fConfigured = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("LogDevReconnect"), &dwReconnect); if (!fConfigured || dwReconnect > LOGDEV_RECONNECT_MAX) { dwReconnect = LOGDEV_RECONNECT_DEFAULT; } static const DWORD LOGDEV_RECONNECT_INTERVAL_DEFAULT = 3000; static const DWORD LOGDEV_RECONNECT_INTERVAL_MAX = 60000; DWORD dwReconnectInterval = LOGDEV_RECONNECT_INTERVAL_DEFAULT; fConfigured = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("LogDevReconnectInterval"), &dwReconnectInterval); if (!fConfigured || dwReconnectInterval > LOGDEV_RECONNECT_INTERVAL_MAX) { dwReconnectInterval = LOGDEV_RECONNECT_INTERVAL_DEFAULT; } pud->LurnOptions |= LURNOPTION_SET_RECONNECTION; pud->ReconnTrial = dwReconnect; pud->ReconnInterval = dwReconnectInterval; } } // // Add Target Info // /* if (NDASSCSI_TYPE_DISK_RAID1 == ucTargetType) { CNdasUnitDiskDevice* pUnitDiskDevice = reinterpret_cast<CNdasUnitDiskDevice*>(pUnitDevice.p); _ASSERTE(NULL != pUnitDiskDevice->GetAddTargetInfo()); ::CopyMemory( &pud->RAID_Info, pUnitDiskDevice->GetAddTargetInfo(), sizeof(INFO_RAID)); if (0 == pud->RAID_Info.SectorsPerBit) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_INVALID_BIND_INFORMATION); return FALSE; } } else if(NDASSCSI_TYPE_DISK_RAID4 == ucTargetType) { CNdasUnitDiskDevice* pUnitDiskDevice = reinterpret_cast<CNdasUnitDiskDevice*>(pUnitDevice.p); _ASSERTE(NULL != pUnitDiskDevice->GetAddTargetInfo()); ::CopyMemory( &pud->RAID_Info, pUnitDiskDevice->GetAddTargetInfo(), sizeof(INFO_RAID)); if (0 == pud->RAID_Info.SectorsPerBit) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_INVALID_BIND_INFORMATION); return FALSE; } } */ if (NDAS_UNITDEVICE_TYPE_DISK == pUnitDevice->GetType()) { CNdasUnitDiskDevice* pUnitDiskDevice = reinterpret_cast<CNdasUnitDiskDevice*>(pUnitDevice.p); // // check if last DIB information is same with current one // if(!pUnitDiskDevice->HasSameDIBInfo()) { pDevice->InvalidateUnitDevice(pUnitDevice->GetUnitNo()); ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_MODIFIED_BIND_INFORMATION); return FALSE; } // // check if bitmap status in RAID 1, 4. Do not plug in // #ifdef __DO_NOT_MOUNT_CORRUPTED_RAID__ // now driver supports recover on mount if (NDAS_UNITDEVICE_DISK_TYPE_RAID1 == pUnitDiskDevice->GetSubType().DiskDeviceType || NDAS_UNITDEVICE_DISK_TYPE_RAID4 == pUnitDiskDevice->GetSubType().DiskDeviceType) { if (!pUnitDiskDevice->IsBitmapClean()) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_CORRUPTED_BIND_INFORMATION); return FALSE; } } #endif // // Done checking plug in condition // } } // // Check Multiple Write Access Compatibility // if (GENERIC_WRITE & requestingAccess) { DWORD dwMaxNDFSCompatCheck = 1; if (m_fDisconnected) { // On disconnection (other than power failure), // they may exist an inactive R/W connection at the NDAS device. // In such case, no host will reply to NDFS Compatibility Check. // As an workaround for that we try NDFS Compatibility Check // more than once if failed. static const DWORD MAX_NDFS_COMPAT_CHECK_DEFAULT = 10; static const DWORD MAX_NDFS_COMPAT_CHECK_MAX = 60; fSuccess = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("MaxWriteAccessCheck"), &dwMaxNDFSCompatCheck); if (!fSuccess || dwMaxNDFSCompatCheck > MAX_NDFS_COMPAT_CHECK_MAX) { dwMaxNDFSCompatCheck = MAX_NDFS_COMPAT_CHECK_DEFAULT; } } for (DWORD i = 0; i < dwMaxNDFSCompatCheck; ++i) { fSuccess = IsWriteAccessAllowed(fPSWriteShare, pPrimaryUnitDevice); if (fSuccess) { break; } } if (!fSuccess) { return FALSE; } } // After this, we used up a Disconnected flag, so we can clear it. m_fDisconnected = FALSE; pAddTargetData->ulTargetBlocks = GetUserBlockCount(); DWORD dwMaxRequestBlocksPerUnit = cpGetMaxRequestBlocks(); DWORD dwMaxRequestBlocks; // use max of MBR switch(GetType()) { case NDAS_LOGICALDEVICE_TYPE_DISK_RAID0: dwMaxRequestBlocks = dwMaxRequestBlocksPerUnit * GetUnitDeviceCountInRaid(); break; case NDAS_LOGICALDEVICE_TYPE_DISK_RAID4: dwMaxRequestBlocks = dwMaxRequestBlocksPerUnit * (GetUnitDeviceCountInRaid() -1); break; default: dwMaxRequestBlocks = dwMaxRequestBlocksPerUnit; break; } DBGPRT_INFO( _FT("LsBusCtlPlugInEx2(SlotNo %d, MaxReqBlock %d, DisEvt %p, RecEvt %p).)\n"), m_NdasScsiLocation.SlotNo, dwMaxRequestBlocks, m_hDisconnectedEvent, m_hAlarmEvent); SetReconnectFlag(FALSE); BOOL fVolatileRegister = IsVolatile(); fSuccess = LsBusCtlPlugInEx2( m_NdasScsiLocation.SlotNo, dwMaxRequestBlocks, m_hDisconnectedEvent, m_hAlarmEvent, fVolatileRegister); if (!fSuccess) { DBGPRT_ERR_EX(_FT("LsBusCtlPlugInEx2 failed: \n")); _ASSERTE(fSuccess && "PlugIn failure"); return FALSE; } DBGPRT_INFO(_FT("LsBusCtlPluginEx succeeded.\n")); BEGIN_DBGPRT_BLOCK_INFO() DBGPRT_INFO(_FT("LsBusCtlAddTarget(pAddTargetData)\n")); DPType(XDebug::OL_INFO, pAddTargetData, cbAddTargetDataSize); END_DBGPRT_BLOCK() fSuccess = LsBusCtlAddTarget(pAddTargetData); if (!fSuccess) { DBGPRT_ERR_EX(_FT("AddTarget failed.\n")); ::Sleep(1000); LsBusCtlEject(m_NdasScsiLocation.SlotNo); _ASSERTE(fSuccess); return FALSE; } DBGPRT_INFO(_FT("LsBusCtlAddTarget succeeded.\n")); // // Set the status // SetMountedAccess(requestingAccess); // // Set the status as pending, actual mount completion is // reported from PNP event handler to call OnMounted() // to complete this process // SetStatus(NDAS_LOGICALDEVICE_STATUS_MOUNT_PENDING); // // Attach or detach from the event monitor // CNdasEventMonitor* pEventMon = pGetNdasEventMonitor(); pEventMon->Attach(this); DBGPRT_INFO(_FT("Plugged in successfully at %s.\n"), m_NdasScsiLocation.ToString()); return TRUE; }
DWORD CNdasLogicalDevice::GetUserBlockCount() { ximeta::CAutoLock autolock(this); if (!IsComplete()) { return 0; } if (!IS_NDAS_LOGICALDEVICE_TYPE_DISK_GROUP(m_logicalDeviceGroup.Type)) { _ASSERTE(1 == GetUnitDeviceCount()); CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(0); _ASSERTE(NULL != pUnitDevice.p); if (NULL == pUnitDevice.p) { return 0; } return pUnitDevice->GetUserBlockCount(); } DWORD dwBlocks = 0; for (DWORD i = 0; i < GetUnitDeviceCount(); i++) { CRefObjPtr<CNdasUnitDevice> pUnitDevice = GetUnitDevice(i); _ASSERTE(NULL != pUnitDevice.p); if (NULL == pUnitDevice.p) { return 0; } _ASSERTE(pUnitDevice->GetType() == NDAS_UNITDEVICE_TYPE_DISK); CNdasUnitDiskDevice* pUnitDisk = reinterpret_cast<CNdasUnitDiskDevice*>(pUnitDevice.p); // dwBlocks += pUnitDisk->GetBlocks(); _ASSERTE(IS_NDAS_LOGICALDEVICE_TYPE_DISK_GROUP(m_logicalDeviceGroup.Type)); switch (m_logicalDeviceGroup.Type) { case NDAS_LOGICALDEVICE_TYPE_DISK_MIRRORED: if (0 == i) { dwBlocks = pUnitDisk->GetUserBlockCount(); } break; case NDAS_LOGICALDEVICE_TYPE_DISK_AGGREGATED: case NDAS_LOGICALDEVICE_TYPE_DISK_RAID0: dwBlocks += pUnitDisk->GetUserBlockCount(); break; case NDAS_LOGICALDEVICE_TYPE_DISK_RAID1: if (i % 2) { dwBlocks += pUnitDisk->GetUserBlockCount(); } break; case NDAS_LOGICALDEVICE_TYPE_DISK_RAID4: if (i != GetUnitDeviceCount() - 1) { // // do not count parity disk // dwBlocks += pUnitDisk->GetUserBlockCount(); } break; case NDAS_LOGICALDEVICE_TYPE_DISK_SINGLE: dwBlocks = pUnitDisk->GetUserBlockCount(); break; default: // not implemented yet : DVD, VDVD, MO, FLASH ... _ASSERTE(FALSE); break; } } return dwBlocks; }