示例#1
0
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;
}