Пример #1
0
static
NTSTATUS
NdscCopyQueryOutputToSrb(
	PMINIPORT_DEVICE_EXTENSION	HwDeviceExtension,
	ULONG						CcbBufferLength,
	PUCHAR						CcbBuffer,
	ULONG						SrbIoctlBufferLength,
	PUCHAR						SrbIoctlBuffer
){
	NTSTATUS		status;
	PLUR_QUERY		lurQuery;

	lurQuery = (PLUR_QUERY)CcbBuffer;
	if(CcbBufferLength < FIELD_OFFSET(LUR_QUERY, QueryDataLength)) {
		return STATUS_INVALID_PARAMETER;
	}

	status = STATUS_SUCCESS;
	switch(lurQuery->InfoClass) {
		case LurPrimaryLurnInformation: { // NdscPrimaryUnitDiskInformation
			PLURN_PRIMARYINFORMATION	lurPrimaryInfo = (PLURN_PRIMARYINFORMATION)LUR_QUERY_INFORMATION(lurQuery);
			PNDSCIOCTL_PRIMUNITDISKINFO	primUnitDisk = (PNDSCIOCTL_PRIMUNITDISKINFO)SrbIoctlBuffer;

			if(CcbBufferLength < sizeof(LURN_PRIMARYINFORMATION)) {
				return STATUS_INVALID_PARAMETER;
			}
			if(SrbIoctlBufferLength < sizeof(NDSCIOCTL_PRIMUNITDISKINFO)) {
				return STATUS_INVALID_PARAMETER;
			}

			//
			//	Set length.
			//
			primUnitDisk->Length					= sizeof(NDSCIOCTL_PRIMUNITDISKINFO);
			primUnitDisk->UnitDisk.Length			= sizeof(NDSC_UNITDISK);
			//
			//	Adapter information
			//
			primUnitDisk->EnabledTime.QuadPart		=	HwDeviceExtension->EnabledTime.QuadPart;

			//
			// LUR information ( Scsi LU information )
			//
			primUnitDisk->Lur.Length		= sizeof(NDSC_LUR);
			primUnitDisk->Lur.DevType		= HwDeviceExtension->LURs[0]->DevType;
			primUnitDisk->Lur.TargetId		= HwDeviceExtension->LURs[0]->LurId[1];
			primUnitDisk->Lur.Lun			= HwDeviceExtension->LURs[0]->LurId[2];
			primUnitDisk->Lur.LurnCnt		= HwDeviceExtension->LURs[0]->NodeCount;
			primUnitDisk->Lur.DeviceMode	= HwDeviceExtension->LURs[0]->DeviceMode;
			primUnitDisk->Lur.SupportedFeatures	= HwDeviceExtension->LURs[0]->SupportedNdasFeatures;
			primUnitDisk->Lur.EnabledFeatures	= HwDeviceExtension->LURs[0]->EnabledNdasFeatures;

			//
			//	Unit device
			//

			primUnitDisk->UnitDisk.UnitDiskId		= lurPrimaryInfo->PrimaryLurn.UnitDiskId;
			primUnitDisk->UnitDisk.Connections		= lurPrimaryInfo->PrimaryLurn.Connections;
			primUnitDisk->UnitDisk.GrantedAccess	= lurPrimaryInfo->PrimaryLurn.AccessRight;
			RtlCopyMemory(
				primUnitDisk->UnitDisk.UserID,
				&lurPrimaryInfo->PrimaryLurn.UserID,
				sizeof(primUnitDisk->UnitDisk.UserID)
				);
			RtlCopyMemory(
				primUnitDisk->UnitDisk.Password,
				&lurPrimaryInfo->PrimaryLurn.Password,
				sizeof(primUnitDisk->UnitDisk.Password)
				);

#if 0
			RtlCopyMemory(	&primUnitDisk->UnitDisk.NetDiskAddress,
				&lurPrimaryInfo->PrimaryLurn.NetDiskAddress,
				sizeof(TA_LSTRANS_ADDRESS)
				);

			RtlCopyMemory(	&primUnitDisk->UnitDisk.BindingAddress,
				&lurPrimaryInfo->PrimaryLurn.BindingAddress,
				sizeof(TA_LSTRANS_ADDRESS)
				);

#else

			primUnitDisk->UnitDisk.NetDiskAddress.TAAddressCount = 1;
			primUnitDisk->UnitDisk.NetDiskAddress.Address[0].AddressLength 
				= lurPrimaryInfo->PrimaryLurn.NdasNetDiskAddress.AddressLength;
			primUnitDisk->UnitDisk.NetDiskAddress.Address[0].AddressType = 
				lurPrimaryInfo->PrimaryLurn.NdasNetDiskAddress.AddressType;
			
			RtlCopyMemory( &primUnitDisk->UnitDisk.NetDiskAddress.Address[0].Address,
						   &lurPrimaryInfo->PrimaryLurn.NdasNetDiskAddress.Address[0], 
					   	   lurPrimaryInfo->PrimaryLurn.NdasNetDiskAddress.AddressLength );

			primUnitDisk->UnitDisk.BindingAddress.TAAddressCount = 1;
			primUnitDisk->UnitDisk.BindingAddress.Address[0].AddressLength 
				= lurPrimaryInfo->PrimaryLurn.NdasBindingAddress.AddressLength;
			primUnitDisk->UnitDisk.BindingAddress.Address[0].AddressType = 
				lurPrimaryInfo->PrimaryLurn.NdasBindingAddress.AddressType;
			
			RtlCopyMemory( &primUnitDisk->UnitDisk.BindingAddress.Address[0].Address,
						   &lurPrimaryInfo->PrimaryLurn.NdasBindingAddress.Address[0], 
					   	   lurPrimaryInfo->PrimaryLurn.NdasBindingAddress.AddressLength );

#endif

			primUnitDisk->UnitDisk.UnitBlocks		= (UINT32)lurPrimaryInfo->PrimaryLurn.UnitBlocks;
			primUnitDisk->UnitDisk.SlotNo			= HwDeviceExtension->SlotNumber;
			RtlCopyMemory(primUnitDisk->NDSC_ID, lurPrimaryInfo->PrimaryLurn.PrimaryId, LURN_PRIMARY_ID_LENGTH);

			KDPrint(2,("NDSC_ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
				primUnitDisk->NDSC_ID[0], primUnitDisk->NDSC_ID[1], primUnitDisk->NDSC_ID[2], primUnitDisk->NDSC_ID[3], 
				primUnitDisk->NDSC_ID[4], primUnitDisk->NDSC_ID[5], primUnitDisk->NDSC_ID[6], primUnitDisk->NDSC_ID[7], 
				primUnitDisk->NDSC_ID[8], primUnitDisk->NDSC_ID[9], primUnitDisk->NDSC_ID[10], primUnitDisk->NDSC_ID[11], 
				primUnitDisk->NDSC_ID[12], primUnitDisk->NDSC_ID[13], primUnitDisk->NDSC_ID[14], primUnitDisk->NDSC_ID[15])
				);
		break;
		}
		case LurEnumerateLurn: { // NdscLurInformation
			PLURN_ENUM_INFORMATION	lurnEnumInfo = (PLURN_ENUM_INFORMATION)LUR_QUERY_INFORMATION(lurQuery);
			PNDSCIOCTL_LURINFO		info = (PNDSCIOCTL_LURINFO)SrbIoctlBuffer;
			NDAS_DEV_ACCESSMODE		deviceMode;
			NDAS_FEATURES			supportedNdasFeatures, enabledNdasFeatures;
			PNDSC_LURN_FULL			unitDisk;
			ULONG					idx_lurn;
			PLURN_INFORMATION		lurnInformation;
			ULONG					returnLength;
			UINT32				nodeCount;

			if(CcbBufferLength < sizeof(LURN_PRIMARYINFORMATION)) {
				return STATUS_INVALID_PARAMETER;
			}
			if(SrbIoctlBufferLength < FIELD_OFFSET(NDSCIOCTL_LURINFO, Reserved1)) {
				return STATUS_INVALID_PARAMETER;
			}

			if (HwDeviceExtension->LURs[0]) {
				ASSERT(HwDeviceExtension->LURs[0]->NodeCount >= 1);
				deviceMode = HwDeviceExtension->LURs[0]->DeviceMode;
				supportedNdasFeatures = HwDeviceExtension->LURs[0]->SupportedNdasFeatures;
				enabledNdasFeatures = HwDeviceExtension->LURs[0]->EnabledNdasFeatures;
				nodeCount = HwDeviceExtension->LURs[0]->NodeCount;
			} else {
				deviceMode = 0;
				supportedNdasFeatures = 0;
				enabledNdasFeatures = 0;
				nodeCount = 0;
			}

			//
			//	Adapter information
			//

			info->Length			=	FIELD_OFFSET(NDSCIOCTL_LURINFO, Lurns) +
										sizeof(NDSC_LURN_FULL) *
										nodeCount;

			// return length check
			returnLength = FIELD_OFFSET(NDSCIOCTL_LURINFO, Lurns);
			if(SrbIoctlBufferLength < returnLength) {
				return STATUS_BUFFER_TOO_SMALL;
			}

			info->EnabledTime.QuadPart					=	HwDeviceExtension->EnabledTime.QuadPart;
			info->Lur.Length		= sizeof(NDSC_LUR);
			info->Lur.DevType		= HwDeviceExtension->LURs[0]->DevType;
			info->Lur.TargetId		= HwDeviceExtension->LURs[0]->LurId[1];
			info->Lur.Lun			= HwDeviceExtension->LURs[0]->LurId[2];
			info->Lur.LurnCnt		= HwDeviceExtension->LURs[0]->NodeCount;
			info->LurnCnt		= info->Lur.LurnCnt;
			info->Lur.DeviceMode = deviceMode;
			info->Lur.SupportedFeatures = supportedNdasFeatures;
			info->Lur.EnabledFeatures = enabledNdasFeatures;

			//
			//	Set return values for each LURN.
			//
			for(idx_lurn = 0; idx_lurn < info->LurnCnt; idx_lurn++) {

				//
				//	Add one LURN to return bytes and check the user buffer size.
				//
				returnLength += sizeof(NDSC_LURN_FULL);
				if(SrbIoctlBufferLength < returnLength) {
					status = STATUS_BUFFER_TOO_SMALL;
					// Do not exit. Must return full length.
					continue;
				}

				unitDisk = info->Lurns + idx_lurn;
				lurnInformation = lurnEnumInfo->Lurns + idx_lurn;

				unitDisk->Length = sizeof(NDSC_LURN_FULL);
				unitDisk->UnitDiskId = lurnInformation->UnitDiskId;
				unitDisk->Connections = lurnInformation->Connections;
				unitDisk->AccessRight = lurnInformation->AccessRight;
				unitDisk->UnitBlocks = lurnInformation->UnitBlocks;
				unitDisk->StatusFlags = lurnInformation->StatusFlags;
				unitDisk->LurnId = lurnInformation->LurnId;
				unitDisk->LurnType = lurnInformation->LurnType;
				unitDisk->StatusFlags = lurnInformation->StatusFlags;

				RtlCopyMemory(
					unitDisk->UserID,
					&lurnInformation->UserID,
					sizeof(unitDisk->UserID)
					);

				RtlCopyMemory(
					unitDisk->Password,
					&lurnInformation->Password,
					sizeof(unitDisk->Password)
					);

#if 0
				RtlCopyMemory(	&unitDisk->NetDiskAddress,
					&lurnInformation->NetDiskAddress,
					sizeof(TA_LSTRANS_ADDRESS)
					);
				RtlCopyMemory(	&unitDisk->BindingAddress,
					&lurnInformation->BindingAddress,
					sizeof(TA_LSTRANS_ADDRESS)
					);
#else

			unitDisk->NetDiskAddress.TAAddressCount = 1;
			unitDisk->NetDiskAddress.Address[0].AddressLength 
				= lurnInformation->NdasNetDiskAddress.AddressLength;
			unitDisk->NetDiskAddress.Address[0].AddressType = 
				lurnInformation->NdasNetDiskAddress.AddressType;
			
			RtlCopyMemory( &unitDisk->NetDiskAddress.Address[0].Address,
						   &lurnInformation->NdasNetDiskAddress.Address[0], 
					   	   lurnInformation->NdasNetDiskAddress.AddressLength );

			unitDisk->BindingAddress.TAAddressCount = 1;
			unitDisk->BindingAddress.Address[0].AddressLength 
				= lurnInformation->NdasBindingAddress.AddressLength;
			unitDisk->BindingAddress.Address[0].AddressType = 
				lurnInformation->NdasBindingAddress.AddressType;
			
			RtlCopyMemory( &unitDisk->BindingAddress.Address[0].Address,
						   &lurnInformation->NdasBindingAddress.Address[0], 
					   	   lurnInformation->NdasBindingAddress.AddressLength );

#endif

			}
			break;
		 }

		default:
			status = STATUS_INVALID_PARAMETER;
		break;
	}

	return status;
}
Пример #2
0
NTSTATUS
NdasDluSrbIoctlQueryInfo(
		PNDAS_LOGICALUNIT_EXTENSION	LogicalUnitExtension,
		PNDAS_DLU_EXTENSION			DluLuExtension,
		PSCSI_REQUEST_BLOCK			Srb,
		PNDASSCSI_QUERY_INFO_DATA	QueryInfo,
		ULONG						OutputBufferLength,
		PUCHAR						OutputBuffer,
		PULONG						SrbIoctlReturnCode,
		PUCHAR						SrbStatus
) {
	NTSTATUS	status;
	PCCB		Ccb;
//	KIRQL		oldIrql;


	UNREFERENCED_PARAMETER(LogicalUnitExtension);
	UNREFERENCED_PARAMETER(DluLuExtension);

	*SrbIoctlReturnCode = SRB_STATUS_SUCCESS;
	*SrbStatus = SRB_STATUS_SUCCESS;
	status = STATUS_SUCCESS;
	switch(QueryInfo->InfoClass) {

	case NdscPrimaryUnitDiskInformation: {
		PNDSCIOCTL_PRIMUNITDISKINFO	primUnitDisk = (PNDSCIOCTL_PRIMUNITDISKINFO)OutputBuffer;
		PLUR_QUERY					lurQuery;
		PLURN_PRIMARYINFORMATION	lurPrimaryInfo;
		PBYTE						lurBuffer;

		KDPrint(1,("NdscPrimaryUnitDiskInformation\n"));

		if(OutputBufferLength < sizeof(NDSCIOCTL_PRIMUNITDISKINFO)) {
			KDPrint(1,("Too small output buffer\n"));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_BUFFER_TOO_SMALL;
			if (OutputBufferLength > sizeof(UINT32)) 
				primUnitDisk->Length					= sizeof(NDSCIOCTL_PRIMUNITDISKINFO);
			break;
		}

		//
		//	Query to the LUR
		//
		status = LsCcbAllocate(&Ccb);
		if(!NT_SUCCESS(status)) {
			KDPrint(1,("LsCcbAllocate() failed.\n"));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INSUFFICIENT_RESOURCES;
			break;
		}

		lurBuffer = ExAllocatePoolWithTag(
							NonPagedPool,
							SIZE_OF_LURQUERY(0, sizeof(LURN_PRIMARYINFORMATION)),
							LURN_IOCTL_POOL_TAG);
		if(lurBuffer == NULL) {
			KDPrint(1,("LsCcbAllocate() failed.\n"));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INSUFFICIENT_RESOURCES;
			break;
		}

		//
		// Set up asynchronous CCB
		//

		LSCCB_INITIALIZE(Ccb);
		Ccb->Srb = Srb;
		Ccb->OperationCode = CCB_OPCODE_QUERY;
		LsCcbSetFlag(Ccb, CCB_FLAG_ALLOCATED|CCB_FLAG_DATABUF_ALLOCATED);
		Ccb->DataBuffer = lurBuffer;
		Ccb->DataBufferLength = sizeof(LURN_PRIMARYINFORMATION);
		LsCcbSetCompletionRoutine(Ccb, NdasDluCcbCompletion, DluLuExtension);
		InterlockedIncrement(&DluLuExtension->RequestExecuting);
		LsuIncrementTdiClientInProgress();

		lurQuery = (PLUR_QUERY)lurBuffer;
		lurQuery->InfoClass			= LurPrimaryLurnInformation;
		lurQuery->Length			= SIZE_OF_LURQUERY(0, sizeof(LURN_PRIMARYINFORMATION));
		lurQuery->QueryDataLength	= 0;

		lurPrimaryInfo = (PLURN_PRIMARYINFORMATION)LUR_QUERY_INFORMATION(lurQuery);

		if(DluLuExtension->LUR == NULL) {
			LsuDecrementTdiClientInProgress();
			InterlockedDecrement(&DluLuExtension->RequestExecuting);
			ExFreePoolWithTag(lurBuffer, LURN_IOCTL_POOL_TAG);
			LsCcbFree(Ccb);

			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INVALID_PARAMETER;
			break;
		}

		status = LurRequest(
							DluLuExtension->LUR,
							Ccb
						);
		if(!NT_SUCCESS(status)) {
			LsuDecrementTdiClientInProgress();
			InterlockedDecrement(&DluLuExtension->RequestExecuting);
			ExFreePoolWithTag(lurBuffer, LURN_IOCTL_POOL_TAG);
			LsCcbFree(Ccb);

			KDPrint(1,("LurRequest() failed.\n"));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INVALID_PARAMETER;
			break;
		}
		status = STATUS_PENDING;
		break;
		}

	case NdscLurInformation: {
		PNDSCIOCTL_LURINFO	info = (PNDSCIOCTL_LURINFO)OutputBuffer;
		PLUR_QUERY			lurQuery;
		UINT32				lurnEnumInfoLen;
		UINT32				nodeCount;

		KDPrint(1,("NdscLurInformation\n"));

		if(OutputBufferLength < FIELD_OFFSET(NDSCIOCTL_LURINFO, Lurns)) {
			KDPrint(2,("LurInfo: Buffer size %d is less than required %d bytes\n", OutputBufferLength, FIELD_OFFSET(NDSCIOCTL_LURINFO, Lurns)));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INVALID_PARAMETER;
			break;
		}

		//
		//	allocate a CCB
		//
		status = LsCcbAllocate(&Ccb);
		if(!NT_SUCCESS(status)) {
			KDPrint(1,("LsCcbAllocate() failed.\n"));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		//
		//	initialize query CCB
		//
		LSCCB_INITIALIZE(Ccb);
		Ccb->Srb = Srb;
		Ccb->OperationCode = CCB_OPCODE_QUERY;
		LsCcbSetFlag(Ccb, CCB_FLAG_ALLOCATED|CCB_FLAG_DATABUF_ALLOCATED);

		if (DluLuExtension->LUR) {
			nodeCount = DluLuExtension->LUR->NodeCount;
		} else {
			nodeCount = 0;
			ASSERT(FALSE);
		}

		lurnEnumInfoLen = FIELD_OFFSET(LURN_ENUM_INFORMATION, Lurns) + sizeof(LURN_INFORMATION) * nodeCount;
		// Allocate memory and initialize it.
		LUR_QUERY_INITIALIZE(lurQuery, LurEnumerateLurn, 0, lurnEnumInfoLen);
		if(!lurQuery) {
			LsCcbFree(Ccb);

			KDPrint(1,("allocating DataBuffer failed.\n"));
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INSUFFICIENT_RESOURCES;
			break;
		}

		Ccb->DataBuffer = lurQuery;
		Ccb->DataBufferLength = lurQuery->Length;

		//
		// Set completion routine
		//

		LsCcbSetCompletionRoutine(Ccb, NdasDluCcbCompletion, DluLuExtension);
		InterlockedIncrement(&DluLuExtension->RequestExecuting);
		LsuIncrementTdiClientInProgress();

		//
		//	send the CCB down
		//
		status = LurRequest(
							DluLuExtension->LUR,
							Ccb
						);
		if(!NT_SUCCESS(status)) {
			InterlockedDecrement(&DluLuExtension->RequestExecuting);
			LsuDecrementTdiClientInProgress();
			LsCcbFree(Ccb);

			KDPrint(1,("LurRequest() failed.\n"));
			ExFreePoolWithTag(lurQuery, NDSC_PTAG_IOCTL);
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INVALID_PARAMETER;
			break;
		}
		status = STATUS_PENDING;
		break;
		}
	case NdscSystemBacl:
	case NdscUserBacl: {
		ULONG			requiredBufLen;
		PNDAS_BLOCK_ACL	ndasBacl = (PNDAS_BLOCK_ACL)OutputBuffer;
		PLSU_BLOCK_ACL	targetBacl;


		KDPrint(1,("NdscSystemBacl/UserBacl: going to default LuExtention 0.\n"));
		if(DluLuExtension->LUR == NULL) {
			*SrbStatus = SRB_STATUS_INVALID_REQUEST;
			status = STATUS_INVALID_PARAMETER;
			break;
		}

		if(QueryInfo->InfoClass == NdscSystemBacl)
			targetBacl = &DluLuExtension->LUR->SystemBacl;
		else
			targetBacl = &DluLuExtension->LUR->UserBacl;

		status = LsuConvertLsuBaclToNdasBacl(
								ndasBacl, 
								OutputBufferLength,
								&requiredBufLen,
								targetBacl);

		if(status == STATUS_BUFFER_TOO_SMALL) {
			//
			//	Set required field.
			//
			if(OutputBufferLength >= FIELD_OFFSET(NDAS_BLOCK_ACL, BlockACECnt)) {
				ndasBacl->Length = requiredBufLen;
			}
			//
			//	Set error code to the srb ioctl, but return success
			//
			*SrbIoctlReturnCode = SRB_STATUS_DATA_OVERRUN;

		} else if(!NT_SUCCESS(status)) {
			*SrbStatus = SRB_STATUS_ERROR;
			break;
		}

		*SrbStatus = SRB_STATUS_SUCCESS;
		status = STATUS_SUCCESS;
		break;
	}
	default:
		KDPrint(1,("Invalid Information Class!!\n"));
		*SrbStatus = SRB_STATUS_INVALID_REQUEST;
		status = STATUS_INVALID_PARAMETER;
	}

	return status;
}
Пример #3
0
UCHAR
SrbIoctlQueryInfo(
		PMINIPORT_DEVICE_EXTENSION	HwDeviceExtension,
		PMINIPORT_LU_EXTENSION		LuExtension,
		PLSMPIOCTL_QUERYINFO		QueryInfo,
		ULONG						OutputBufferLength,
		PUCHAR						OutputBuffer,
		PNTSTATUS					NtStatus,
		ULONG						CurSrbSequence
) {
	UCHAR				status;
	PCCB				Ccb;
	NTSTATUS			ntStatus;
	KIRQL				oldIrql;

	UNREFERENCED_PARAMETER(LuExtension);

	status = SRB_STATUS_SUCCESS;
	switch(QueryInfo->InfoClass) {
	case LsmpAdapterInformation: {
		PLSMPIOCTL_ADAPTERINFO	adapter = (PLSMPIOCTL_ADAPTERINFO)OutputBuffer;

		KDPrint(1,("LsmpAdapterInformation\n"));

		if(OutputBufferLength < sizeof(LSMPIOCTL_ADAPTERINFO)) {
			KDPrint(1,("Too small output buffer. OutputBufferLength:%d\n", OutputBufferLength));
			*NtStatus = STATUS_BUFFER_TOO_SMALL;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		adapter->Length								= sizeof(LSMPIOCTL_ADAPTERINFO);
		adapter->Adapter.SlotNo						= HwDeviceExtension->SlotNumber;
		adapter->Adapter.Length						= sizeof(LSMP_ADAPTER);
		adapter->Adapter.InitiatorId				= HwDeviceExtension->InitiatorId;
		adapter->Adapter.NumberOfBuses				= HwDeviceExtension->NumberOfBuses;
		adapter->Adapter.MaximumNumberOfTargets		= HwDeviceExtension->MaximumNumberOfTargets;
		adapter->Adapter.MaximumNumberOfLogicalUnits= HwDeviceExtension->MaximumNumberOfLogicalUnits;
		adapter->Adapter.MaxBlocksPerRequest		= HwDeviceExtension->AdapterMaxBlocksPerRequest;

		ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql);
		adapter->Adapter.Status						= HwDeviceExtension->AdapterStatus;
		RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql);

		*NtStatus = STATUS_SUCCESS;
		status = SRB_STATUS_SUCCESS;
		break;
		}
	case LsmpPrimaryUnitDiskInformation: {
		PLSMPIOCTL_PRIMUNITDISKINFO	primUnitDisk = (PLSMPIOCTL_PRIMUNITDISKINFO)OutputBuffer;
		PLUR_QUERY					LurQuery;
		PLURN_PRIMARYINFORMATION	LurPrimaryInfo;
		BYTE						LurBuffer[SIZE_OF_LURQUERY(0, sizeof(LURN_PRIMARYINFORMATION))];
		ACCESS_MASK					DesiredAccess;

		KDPrint(1,("LsmpPrimaryUnitDiskInformation\n"));

		if(OutputBufferLength < sizeof(LSMPIOCTL_PRIMUNITDISKINFO)) {
			KDPrint(1,("Too small output buffer\n"));
			*NtStatus = STATUS_BUFFER_TOO_SMALL;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		//
		//	Query to the LUR
		//
		ntStatus = LSCcbAllocate(&Ccb);
		if(!NT_SUCCESS(ntStatus)) {
			KDPrint(1,("LSCcbAllocate() failed.\n"));
			*NtStatus = STATUS_INSUFFICIENT_RESOURCES;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		LSCCB_INITIALIZE(Ccb, CurSrbSequence);
		Ccb->OperationCode = CCB_OPCODE_QUERY;
		LSCcbSetFlag(Ccb, CCB_FLAG_SYNCHRONOUS|CCB_FLAG_ALLOCATED);
		Ccb->DataBuffer = LurBuffer;
		Ccb->DataBufferLength = sizeof(LURN_PRIMARYINFORMATION);

		LurQuery = (PLUR_QUERY)LurBuffer;
		LurQuery->InfoClass			= LurPrimaryLurnInformation;
		LurQuery->Length			= SIZE_OF_LURQUERY(0, sizeof(LURN_PRIMARYINFORMATION));
		LurQuery->QueryDataLength	= 0;

		LurPrimaryInfo = (PLURN_PRIMARYINFORMATION)LUR_QUERY_INFORMATION(LurQuery);

		KDPrint(3,("going to default LuExtention 0.\n"));
		if(HwDeviceExtension->LURs[0] == NULL || HwDeviceExtension->LURCount == 0) {
			LSCcbFree(Ccb);

			*NtStatus = STATUS_INVALID_PARAMETER;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		ntStatus = LurRequest(
							HwDeviceExtension->LURs[0],	// default: 0.
							Ccb
						);
		DesiredAccess = HwDeviceExtension->LURs[0]->DesiredAccess;
		if(!NT_SUCCESS(ntStatus)) {
			LSCcbFree(Ccb);

			KDPrint(1,("LurRequest() failed.\n"));
			*NtStatus = STATUS_INSUFFICIENT_RESOURCES;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		//
		//	Set return values.
		//
		primUnitDisk->Length					= sizeof(LSMPIOCTL_PRIMUNITDISKINFO);
		primUnitDisk->UnitDisk.Length			= sizeof(LSMP_UNITDISK);
		//
		//	Adapter information
		//
		primUnitDisk->EnabledTime.QuadPart					=	HwDeviceExtension->EnabledTime.QuadPart;

		primUnitDisk->Adapter.SlotNo						= HwDeviceExtension->SlotNumber;
		primUnitDisk->Adapter.Length						= sizeof(LSMP_ADAPTER);
		primUnitDisk->Adapter.InitiatorId					= HwDeviceExtension->InitiatorId;
		primUnitDisk->Adapter.NumberOfBuses					= HwDeviceExtension->NumberOfBuses;
		primUnitDisk->Adapter.MaximumNumberOfTargets		= HwDeviceExtension->MaximumNumberOfTargets;
		primUnitDisk->Adapter.MaximumNumberOfLogicalUnits	= HwDeviceExtension->MaximumNumberOfLogicalUnits;
		primUnitDisk->Adapter.MaxBlocksPerRequest			= HwDeviceExtension->AdapterMaxBlocksPerRequest;

		ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql);
		primUnitDisk->Adapter.Status						= HwDeviceExtension->AdapterStatus;
		RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql);
		//
		// LUR information ( Scsi LU information )
		//
		primUnitDisk->Lur.Length		= sizeof(LSMP_LUR);
		primUnitDisk->Lur.DevType		= HwDeviceExtension->LURs[0]->DevType;
		primUnitDisk->Lur.TargetId		= HwDeviceExtension->LURs[0]->LurId[1];
		primUnitDisk->Lur.Lun			= HwDeviceExtension->LURs[0]->LurId[2];
		primUnitDisk->Lur.LurnCnt		= HwDeviceExtension->LURs[0]->NodeCount;
		primUnitDisk->Lur.DesiredAccess = HwDeviceExtension->LURs[0]->DesiredAccess;
		primUnitDisk->Lur.GrantedAccess = HwDeviceExtension->LURs[0]->GrantedAccess;
		primUnitDisk->Lur.LowestHwVer	= HwDeviceExtension->LURs[0]->LowestHwVer;

		//
		//	Unit device
		//

		primUnitDisk->UnitDisk.UnitDiskId		= LurPrimaryInfo->PrimaryLurn.UnitDiskId;
		primUnitDisk->UnitDisk.DesiredAccess	= DesiredAccess;
		primUnitDisk->UnitDisk.GrantedAccess	= LurPrimaryInfo->PrimaryLurn.AccessRight;
		RtlCopyMemory(
			primUnitDisk->UnitDisk.UserID,
			&LurPrimaryInfo->PrimaryLurn.UserID,
			sizeof(primUnitDisk->UnitDisk.UserID)
			);
		RtlCopyMemory(
			primUnitDisk->UnitDisk.Password,
			&LurPrimaryInfo->PrimaryLurn.Password,
			sizeof(primUnitDisk->UnitDisk.Password)
			);

		RtlCopyMemory(	&primUnitDisk->UnitDisk.NetDiskAddress,
						&LurPrimaryInfo->PrimaryLurn.NetDiskAddress,
						sizeof(TA_LSTRANS_ADDRESS)
			);
		RtlCopyMemory(	&primUnitDisk->UnitDisk.BindingAddress,
						&LurPrimaryInfo->PrimaryLurn.BindingAddress,
						sizeof(TA_LSTRANS_ADDRESS)
			);
		primUnitDisk->UnitDisk.UnitBlocks		= (UINT32)LurPrimaryInfo->PrimaryLurn.UnitBlocks;
		primUnitDisk->UnitDisk.SlotNo			= HwDeviceExtension->SlotNumber;
		break;
		}

	case LsmpAdapterLurInformation: {
		PLSMPIOCTL_ADAPTERLURINFO	info = (PLSMPIOCTL_ADAPTERLURINFO)OutputBuffer;
		PLSMP_LURN_FULL				unitDisk;
		PLUR_QUERY					LurQuery;
		PLURN_ENUM_INFORMATION		LurnEnumInfo;
		UINT32						LurnEnumInfoLen;
		PLURN_INFORMATION			lurnInformation;
		ACCESS_MASK					DesiredAccess;
		ACCESS_MASK					GrantedAccess;
		ULONG						idx_lurn;
		UINT32						returnLength;

		KDPrint(1,("LsmpAdapterLurInformation\n"));

		if(OutputBufferLength < FIELD_OFFSET(LSMPIOCTL_ADAPTERLURINFO, UnitDisks)) {
			KDPrint(1,("PDOSLOTLIST: Buffer size is less than required %d bytes\n", FIELD_OFFSET(LSMPIOCTL_ADAPTERLURINFO, UnitDisks)));
			*NtStatus = STATUS_INVALID_PARAMETER;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		returnLength = FIELD_OFFSET(LSMPIOCTL_ADAPTERLURINFO, UnitDisks);

		//
		//	Adapter information
		//
		info->EnabledTime.QuadPart					=	HwDeviceExtension->EnabledTime.QuadPart;

		info->Adapter.SlotNo						= HwDeviceExtension->SlotNumber;
		info->Adapter.Length						= sizeof(LSMP_ADAPTER);
		info->Adapter.InitiatorId					= HwDeviceExtension->InitiatorId;
		info->Adapter.NumberOfBuses					= HwDeviceExtension->NumberOfBuses;
		info->Adapter.MaximumNumberOfTargets		= HwDeviceExtension->MaximumNumberOfTargets;
		info->Adapter.MaximumNumberOfLogicalUnits	= HwDeviceExtension->MaximumNumberOfLogicalUnits;
		info->Adapter.MaxBlocksPerRequest			= HwDeviceExtension->AdapterMaxBlocksPerRequest;

		ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql);
		info->Adapter.Status						= HwDeviceExtension->AdapterStatus;
		RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql);
		//
		// LUR information ( Scsi LU information )
		//
		if(!HwDeviceExtension->LURs[0]) {
			KDPrint(1,("No LUR exists.\n"));
			*NtStatus = STATUS_INVALID_PARAMETER;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}
		info->Lur.Length		= sizeof(LSMP_LUR);
		info->Lur.DevType		= HwDeviceExtension->LURs[0]->DevType;
		info->Lur.TargetId		= HwDeviceExtension->LURs[0]->LurId[1];
		info->Lur.Lun			= HwDeviceExtension->LURs[0]->LurId[2];
		info->Lur.LurnCnt		= HwDeviceExtension->LURs[0]->NodeCount;
		info->Lur.LowestHwVer	= HwDeviceExtension->LURs[0]->LowestHwVer;
		info->UnitDiskCnt		= info->Lur.LurnCnt;

		ASSERT(HwDeviceExtension->LURs[0]->NodeCount >= 1);
		info->Length			=	sizeof(LSMPIOCTL_ADAPTERLURINFO) +
									sizeof(LSMP_LURN_FULL) *
									(HwDeviceExtension->LURs[0]->NodeCount - 1);

		//
		//	Lurn information.
		//	Query to the LUR
		//
		unitDisk = info->UnitDisks;

		//
		//	allocate a CCB
		//
		ntStatus = LSCcbAllocate(&Ccb);
		if(!NT_SUCCESS(ntStatus)) {
			KDPrint(1,("LSCcbAllocate() failed.\n"));
			*NtStatus = STATUS_INSUFFICIENT_RESOURCES;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		//
		//	initialize query CCB
		//
		LSCCB_INITIALIZE(Ccb, CurSrbSequence);
		Ccb->OperationCode = CCB_OPCODE_QUERY;
		LSCcbSetFlag(Ccb, CCB_FLAG_SYNCHRONOUS|CCB_FLAG_ALLOCATED);

		ASSERT(info->Lur.LurnCnt >= 1);

		LurnEnumInfoLen = sizeof(LURN_ENUM_INFORMATION) + sizeof(LURN_INFORMATION) * (info->Lur.LurnCnt-1);
		LUR_QUERY_INITIALIZE(LurQuery, LurEnumerateLurn, 0, LurnEnumInfoLen);
		if(!LurQuery) {
			LSCcbFree(Ccb);

			KDPrint(1,("allocating DataBuffer failed.\n"));
			*NtStatus = STATUS_INSUFFICIENT_RESOURCES;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		Ccb->DataBuffer = LurQuery;
		Ccb->DataBufferLength = LurQuery->Length;

		LurnEnumInfo = (PLURN_ENUM_INFORMATION)LUR_QUERY_INFORMATION(LurQuery);

		//
		//	send the CCB down
		//
		KDPrint(3,("going to default LuExtention 0.\n"));
		ntStatus = LurRequest(
							HwDeviceExtension->LURs[0],	// default: 0.
							Ccb
						);
		DesiredAccess = HwDeviceExtension->LURs[0]->DesiredAccess;
		GrantedAccess = HwDeviceExtension->LURs[0]->GrantedAccess;
		if(!NT_SUCCESS(ntStatus)) {
			LSCcbFree(Ccb);

			KDPrint(1,("LurRequest() failed.\n"));
			ExFreePoolWithTag(LurQuery, LSMP_PTAG_IOCTL);
			*NtStatus = STATUS_INSUFFICIENT_RESOURCES;
			status = SRB_STATUS_INVALID_REQUEST;
			break;
		}

		info->Lur.DesiredAccess = DesiredAccess;
		info->Lur.GrantedAccess = GrantedAccess;

		//
		//	Set return values for each LURN.
		//
		for(idx_lurn = 0; idx_lurn < info->UnitDiskCnt; idx_lurn++) {

			//
			//	Add one Unitdisk to return bytes and check the user buffer size.
			//
			returnLength += sizeof(LSMP_LURN_FULL);
			if(returnLength > OutputBufferLength) {
				continue;
			}

			unitDisk = info->UnitDisks + idx_lurn;
			lurnInformation = LurnEnumInfo->Lurns + idx_lurn;

			unitDisk->Length = sizeof(LSMP_LURN_FULL);
			unitDisk->UnitDiskId = lurnInformation->UnitDiskId;
			unitDisk->AccessRight = lurnInformation->AccessRight;
			unitDisk->UnitBlocks = lurnInformation->UnitBlocks;
			unitDisk->StatusFlags = lurnInformation->StatusFlags;
			unitDisk->LurnId = lurnInformation->LurnId;
			unitDisk->LurnType = lurnInformation->LurnType;
			unitDisk->StatusFlags = lurnInformation->StatusFlags;

			RtlCopyMemory(
					unitDisk->UserID,
					&lurnInformation->UserID,
					sizeof(unitDisk->UserID)
				);

			RtlCopyMemory(
					unitDisk->Password,
					&lurnInformation->Password,
					sizeof(unitDisk->Password)
				);

			RtlCopyMemory(	&unitDisk->NetDiskAddress,
						&lurnInformation->NetDiskAddress,
						sizeof(TA_LSTRANS_ADDRESS)
					);
			RtlCopyMemory(	&unitDisk->BindingAddress,
						&lurnInformation->BindingAddress,
						sizeof(TA_LSTRANS_ADDRESS)
					);
		}

		if(returnLength > OutputBufferLength) {
			KDPrint(1,("Output buffer too small. outbuffer:%u required:%u\n", OutputBufferLength, returnLength));
			ExFreePoolWithTag(LurQuery, LSMP_PTAG_IOCTL);
			*NtStatus = STATUS_BUFFER_TOO_SMALL;
			status = SRB_STATUS_SUCCESS;
			break;
		}

		ExFreePoolWithTag(LurQuery, LSMP_PTAG_IOCTL);
		*NtStatus = STATUS_SUCCESS;
		status = SRB_STATUS_SUCCESS;
		break;
		}
	//
	//	User application can use this information instead of LANSCSIMINIPORT_IOCTL_GET_VERSION.
	// 
	case 	LsmpDriverVersion:				// 5
		{
			PLSMPIOCTL_DRVVER	version = (PLSMPIOCTL_DRVVER)OutputBuffer;

			version->VersionMajor = VER_FILEMAJORVERSION;
			version->VersionMinor = VER_FILEMINORVERSION;
			version->VersionBuild = VER_FILEBUILD;
			version->VersionPrivate = VER_FILEBUILD_QFE;

			*NtStatus = STATUS_SUCCESS;
			status = SRB_STATUS_SUCCESS;
		break;
		}

	default:
		KDPrint(1,("Invalid Information Class!!\n"));
		*NtStatus = STATUS_INVALID_PARAMETER;
		status = SRB_STATUS_INVALID_REQUEST;
	}

	return status;
}