Exemplo n.º 1
0
NTSTATUS
LspConnectBindAddrList(
		IN OUT PLANSCSI_SESSION	LSS,
		OUT PTA_LSTRANS_ADDRESS	BoundAddr,
		IN PTA_LSTRANS_ADDRESS	DestAddr,
		IN PTA_LSTRANS_ADDRESS	BindAddrList
){
	NTSTATUS	status;
	ULONG		idx_addr;
	TA_LSTRANS_ADDRESS	bindAddr;

	//
	//	Parameter check
	//
	if(DestAddr->TAAddressCount != 1) {
		return STATUS_INVALID_PARAMETER;
	}
	if(BindAddrList->TAAddressCount < 1) {
		return STATUS_INVALID_PARAMETER;
	}

	if(DestAddr->Address[0].AddressType != TDI_ADDRESS_TYPE_LPX) {
		return STATUS_NOT_IMPLEMENTED;
	}

	bindAddr.TAAddressCount = 1;
	status = STATUS_UNSUCCESSFUL;

	for(idx_addr = 0; idx_addr < (ULONG)BindAddrList->TAAddressCount; idx_addr++) {
		RtlCopyMemory(	bindAddr.Address,
						&BindAddrList->Address[idx_addr],
						sizeof(struct  _AddrLstrans));

		status = LspConnect(LSS, &bindAddr, DestAddr);
		if(NT_SUCCESS(status)) {
			if(BoundAddr) {
				BoundAddr->TAAddressCount = 1;
				RtlCopyMemory(	BoundAddr->Address,
								&BindAddrList->Address[idx_addr],
								sizeof(struct  _AddrLstrans));
			}
			break;
		}
	}

	return status;
}
Exemplo n.º 2
0
//////////////////////////////////////////////////////////////////////////
//
//	Lanscsi Protocol
//
NTSTATUS
LsuConnectLogin(
	OUT PLANSCSI_SESSION		LanScsiSession,
	IN  PTA_LSTRANS_ADDRESS		TargetAddress,
	IN  PTA_LSTRANS_ADDRESS		BindingAddress,
	IN  PLSSLOGIN_INFO			LoginInfo,
	OUT PLSTRANS_TYPE			LstransType

) {
	NTSTATUS		status;
	LARGE_INTEGER	defaultTimeOut;
	LSPROTO_TYPE	LSProto;

	//
	//	Confirm address type.
	//	Connect to the Lanscsi Node.
	//

	status = LstransAddrTypeToTransType( BindingAddress->Address[0].AddressType, LstransType);
	if(!NT_SUCCESS(status)) {
		KDPrintM(DBG_OTHER_ERROR, ("LstransAddrTypeToTransType(), Can't Connect to the LS node. STATUS:0x%08x\n", status));
		goto error_out;
	}


	//
	//	Set timeouts
	//	Extend generic timeout
	//

	RtlZeroMemory(LanScsiSession, sizeof(LANSCSI_SESSION));
	defaultTimeOut.QuadPart = LURNIDE_GENERIC_TIMEOUT * 15 / 10;
	LspSetDefaultTimeOut(LanScsiSession, &defaultTimeOut);
	status = LspConnect(
					LanScsiSession,
					BindingAddress,
					TargetAddress,
					NULL,
					NULL
				);
	if(!NT_SUCCESS(status)) {
		KDPrintM(DBG_OTHER_ERROR, ("LspConnect(), Can't Connect to the LS node. STATUS:0x%08x\n", status));
		goto error_out;
	}

	//
	//	Login to the Lanscsi Node.
	//
	status = LspLookupProtocol(LoginInfo->HWType, LoginInfo->HWVersion, &LSProto);
	if(!NT_SUCCESS(status)) {
		goto error_out;
	}

	status = LspLogin(
					LanScsiSession,
					LoginInfo,
					LSProto,
					NULL,
					TRUE
				);
	if(!NT_SUCCESS(status)) {
		KDPrintM(DBG_OTHER_ERROR, ("LspLogin(), Can't login to the LS node with UserID:%08lx. STATUS:0x%08x.\n", LoginInfo->UserID, status));
		status = STATUS_ACCESS_DENIED;
		goto error_out;
	}

error_out:
	return status;

}
Exemplo n.º 3
0
NTSTATUS
LspConnectBindAddrList (
	IN  PLANSCSI_SESSION	LSS,
	OUT PTA_ADDRESS			BoundAddr,
	IN  PTA_ADDRESS			DestAddr,
	IN  PTRANSPORT_ADDRESS	BindAddrList,
	IN PVOID				InDisconnectHandler,
	IN PVOID				InDisconnectEventContext,
	IN  PLARGE_INTEGER		TimeOut
	)
{
	NTSTATUS			status;
	ULONG				idx_addr;
	PTA_ADDRESS			bindAddr;


	if (BindAddrList->TAAddressCount < 1) {

		NDAS_ASSERT( FALSE );
		return STATUS_INVALID_PARAMETER;
	}

	if (DestAddr->AddressType != TDI_ADDRESS_TYPE_LPX) {

		NDAS_ASSERT( FALSE );
		return STATUS_NOT_IMPLEMENTED;
	}

	status = STATUS_UNSUCCESSFUL;

	// Allocate overlapped context.

	bindAddr = NULL;

	for (idx_addr = 0; idx_addr < (ULONG)BindAddrList->TAAddressCount; idx_addr++) {
			
		if (bindAddr == NULL) {

			bindAddr = BindAddrList->Address;
		
		} else {

			bindAddr = (PTA_ADDRESS)(((PCHAR)bindAddr) + 
									 (FIELD_OFFSET(TA_ADDRESS, Address)) + 
									 bindAddr->AddressLength);
		}

		DebugTrace( NDASSCSI_DBG_LURN_NDASR_INFO, 
				    ("bindAddr %02x:%02x/%02x:%02x:%02x:%02x:%02x:%02x\n",
					 bindAddr->Address[0], bindAddr->Address[1],
					 bindAddr->Address[2], bindAddr->Address[3],
					 bindAddr->Address[4], bindAddr->Address[5],
					 bindAddr->Address[6], bindAddr->Address[7]) );


		// Connect synchronously

		status = LspConnect( LSS, 
							 bindAddr, 
							 DestAddr, 
							 InDisconnectHandler,
							 InDisconnectEventContext,
							 NULL, 
							 IF_NULL_TIMEOUT_THEN_DEFAULT(LSS, TimeOut) );

		if (NT_SUCCESS(status)) {

			NDAS_ASSERT( bindAddr->AddressLength == TDI_ADDRESS_LENGTH_LPX );

			RtlCopyMemory( BoundAddr,
						   bindAddr,
						   (FIELD_OFFSET(TA_ADDRESS, Address) + TDI_ADDRESS_LENGTH_LPX) );

			DebugTrace( NDASSCSI_DBG_LURN_NDASR_INFO, 
					    ("connected to bindAddr %d %02x:%02x/%02x:%02x:%02x:%02x:%02x:%02x\n",
						 idx_addr,
						 bindAddr->Address[0], bindAddr->Address[1],
						 bindAddr->Address[2], bindAddr->Address[3],
						 bindAddr->Address[4], bindAddr->Address[5],
						 bindAddr->Address[6], bindAddr->Address[7]) );

			break;
		}
	}

	return status;
}
Exemplo n.º 4
0
NTSTATUS
LspWorkaroundCleanupLock(
   PLANSCSI_SESSION	LSS,
   ULONG			LockNo,
   PLARGE_INTEGER	TimeOut
){
	NTSTATUS		status;
	LONG			i;
	LANSCSI_PDUDESC	pduDesc;
	BYTE			pduResponse;
	PLANSCSI_SESSION	tempLSS;
	LONG			maxConn;
	UCHAR			bindingBuffer[(FIELD_OFFSET(TA_ADDRESS, Address) + TDI_ADDRESS_LENGTH_LPX)];
	UCHAR			targetBuffer[(FIELD_OFFSET(TA_ADDRESS, Address) + TDI_ADDRESS_LENGTH_LPX)];
	PTA_ADDRESS		BindingAddress = (PTA_ADDRESS)bindingBuffer;
	PTA_ADDRESS  	TargetAddress = (PTA_ADDRESS)targetBuffer;
	LSSLOGIN_INFO	loginInfo;
	LSPROTO_TYPE	LSProto;
	ULONG			cleaned;

	//
	//	Parameter check
	//
	// Perform clean-up only for NDAS 2.0 rev 0.
	//

	if((LSS->HWVersion == LANSCSIIDE_VERSION_2_0 &&
		 LSS->HWRevision == LANSCSIIDE_VER20_REV_1G_ORIGINAL)) {

		// Get maximum connections excluding the current session/connection.
		maxConn = LANSCSIIDE_MAX_CONNECTION_VER11 - 1;
	} else {
		return STATUS_SUCCESS;
	}

	tempLSS = ExAllocatePoolWithTag(
							NonPagedPool,
							maxConn * sizeof(LANSCSI_SESSION),
							LSS_POOLTAG);
	if(tempLSS == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;
	RtlZeroMemory(tempLSS, maxConn * sizeof(LANSCSI_SESSION));

	//
	//	Init variables
	//

	status = STATUS_SUCCESS;
	RtlZeroMemory(&pduDesc, sizeof(LANSCSI_PDUDESC));
	pduDesc.Param8[3] = (UCHAR)LockNo;
	pduDesc.TimeOut = IF_NULL_TIMEOUT_THEN_DEFAULT(LSS, TimeOut);
	LspGetAddresses(LSS, BindingAddress, TargetAddress);
	cleaned = 0;


	//
	//	Try to make connections to fill up connection pool of the NDAS device.
	//	So, we can clear invalid acquisition of the locks.
	//
	KDPrintM(DBG_LURN_ERROR,("Try to clean up lock\n"));
	for (i=0 ; i < maxConn; i++) {

		tempLSS[i].DefaultTimeOut.QuadPart = IF_NULL_TIMEOUT_THEN_DEFAULT(LSS, TimeOut)->QuadPart;

		//
		//	Connect and log in with read-only access.
		//

		//	connect
		status = LspConnect(
					&tempLSS[i],
					BindingAddress,
					TargetAddress,
					NULL,
					NULL,
					NULL,
					NULL
					);
		if(!NT_SUCCESS(status)) {
			KDPrintM(DBG_LURN_ERROR, ("LspConnect(), Can't Connect to the LS node. STATUS:0x%08x\n", status));
			break;
		}
	}


	for (i=0; i < maxConn; i++) {

		if(!LspIsConnected(&tempLSS[i])) {
			continue;
		}

		KDPrintM(DBG_LURN_TRACE, ("Con#%u\n", i));
		cleaned++;

		//	extract login information from the existing LSS.
		LspBuildLoginInfo(LSS, &loginInfo);
		status = LspLookupProtocol(loginInfo.HWType, loginInfo.HWVersion, &LSProto);
		if(!NT_SUCCESS(status)) {
			LspDisconnect(&tempLSS[i]);
			KDPrintM(DBG_LURN_ERROR, ("Wrong hardware version.\n"));
			continue;
		}

		//	Log in with read-only access.
		loginInfo.UserID &= 0x0000ffff;
		status = LspLogin(
						&tempLSS[i],
						&loginInfo,
						LSProto,
						NULL,
						FALSE
					);
		if(!NT_SUCCESS(status)) {
			KDPrintM(DBG_LURN_ERROR, ("LspLogin() failed. STATUS:0x%08x\n", status));
			LspDisconnect(&tempLSS[i]);
			continue;
		}

		// Do need to acquire the lock to release.
		// NDAS chip 2.0 original allow to release the lock 
		// regardless of the ownership if the connection number
		// in the lock information of NDAS chip 2.0
		// is same.
#if 0
		//
		//	Acquire the lock on the NDAS device.
		//

		pduDesc.Command = VENDOR_OP_SET_MUTEX;
		status = LspVendorRequest(
						&tempLSS[i],
						&pduDesc,
						&pduResponse
						);
		if(pduResponse != LANSCSI_RESPONSE_SUCCESS) {
			KDPrintM(DBG_LURN_ERROR,	("Acquiring lock #%u denied by NDAS device\n", LockNo));
		}
		if(!NT_SUCCESS(status)) {
			LspDisconnect(&tempLSS[i]);
			KDPrintM(DBG_LURN_ERROR, ("LspVendorRequest() failed. STATUS=%08lx\n", status));
			continue;
		}
#endif
		//
		//	Release the lock on the NDAS device.
		//

		pduDesc.Command = VENDOR_OP_FREE_MUTEX;
		status = LspVendorRequest(
						&tempLSS[i],
						&pduDesc,
						&pduResponse
						);
		if(pduResponse != LANSCSI_RESPONSE_SUCCESS) {
			KDPrintM(DBG_LURN_ERROR,	("Releasing lock #%u denied by NDAS device\n", LockNo));
		}
		if(!NT_SUCCESS(status)) {
			LspDisconnect(&tempLSS[i]);
			KDPrintM(DBG_LURN_ERROR, ("LspVendorRequest() failed. STATUS=%08lx\n", status));
			continue;
		}


		//
		//	Log out and disconnect.
		//

		LspLogout(
			&tempLSS[i],
			NULL
			);

		LspDisconnect(
			&tempLSS[i]
			);

		//
		// Init PDU
		//
		pduDesc.Retransmits = 0;
		pduDesc.PacketLoss = 0;
	}

	KDPrintM(DBG_LURN_INFO, ("Cleaned #%u\n", cleaned));

	ExFreePool(tempLSS);

	return status;
}
Exemplo n.º 5
0
static
NTSTATUS
LspConnectBindAddrList(
		IN OUT PLANSCSI_SESSION	LSS,
		OUT PTA_LSTRANS_ADDRESS	BoundAddr,
		IN PTA_LSTRANS_ADDRESS	DestAddr,
		IN PTA_LSTRANS_ADDRESS	BindAddrList,
		IN PLARGE_INTEGER		TimeOut
){
	NTSTATUS	status;
	ULONG		idx_addr, idx_cleanup_addr;
	TA_LSTRANS_ADDRESS	bindAddr;
	PLSTRANS_OVERLAPPED	overlapped;
	PKEVENT				overlappedEvents;
	PKWAIT_BLOCK		overlappedWaitBlocks;
	PLANSCSI_SESSION	overlappedLSS;
	PKEVENT				overlappedWait[MAXIMUM_WAIT_OBJECTS];

	NDASSCSI_ASSERT( TimeOut == NULL || TimeOut->QuadPart < 0 );

	//
	//	Parameter check
	//
	if(DestAddr->TAAddressCount != 1) {
		return STATUS_INVALID_PARAMETER;
	}
	if(BindAddrList->TAAddressCount < 1) {
		return STATUS_INVALID_PARAMETER;
	}
	// Windows does not allow to wait for more than MAXIMUM_WAIT_OBJECTS
	// even using wait block buffer.
	if(BindAddrList->TAAddressCount > MAXIMUM_WAIT_OBJECTS) {
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	if(DestAddr->Address[0].AddressType != TDI_ADDRESS_TYPE_LPX) {
		return STATUS_NOT_IMPLEMENTED;
	}


	bindAddr.TAAddressCount = 1;
	status = STATUS_UNSUCCESSFUL;

	//
	// Allocate overlapped context.
	//
	overlapped = ExAllocatePoolWithTag(
					NonPagedPool,
					sizeof(LSTRANS_OVERLAPPED) * BindAddrList->TAAddressCount,
					LSS_OVERLAPPED_BUFFER_POOLTAG
					);
	if(overlapped == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;
	//
	// Allocate completion events
	//
	overlappedEvents = ExAllocatePoolWithTag(
					NonPagedPool,
					sizeof(KEVENT) * BindAddrList->TAAddressCount,
					LSS_OVERLAPPED_EVENT_POOLTAG
					);;
	if(overlappedEvents == NULL) {
		ExFreePoolWithTag(overlapped, LSS_OVERLAPPED_BUFFER_POOLTAG);
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	//
	// Allocate wait blocks.
	// Need this buffer to wait for more than THREAD_WAIT_OBJECTS.
	//
	overlappedWaitBlocks = ExAllocatePoolWithTag(
					NonPagedPool,
					sizeof(KWAIT_BLOCK) * BindAddrList->TAAddressCount,
					LSS_OVERLAPPED_WAITBLOCK_POOLTAG);
	if(overlappedWaitBlocks == NULL) {
		ExFreePoolWithTag(overlappedEvents, LSS_OVERLAPPED_EVENT_POOLTAG);
		ExFreePoolWithTag(overlapped, LSS_OVERLAPPED_BUFFER_POOLTAG);
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	//
	// Allocate LSSes
	//
	overlappedLSS = ExAllocatePoolWithTag(
					NonPagedPool,
					sizeof(LANSCSI_SESSION) * BindAddrList->TAAddressCount,
					LSS_OVERLAPPED_LSS_POOLTAG);
	if(overlappedLSS == NULL){
		ExFreePoolWithTag(overlappedWaitBlocks, LSS_OVERLAPPED_WAITBLOCK_POOLTAG);
		ExFreePoolWithTag(overlappedEvents, LSS_OVERLAPPED_EVENT_POOLTAG);
		ExFreePoolWithTag(overlapped, LSS_OVERLAPPED_BUFFER_POOLTAG);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	//
	// Connect asynchronously for each binding address
	//

	for(idx_addr = 0; idx_addr < (ULONG)BindAddrList->TAAddressCount; idx_addr++) {

		RtlCopyMemory(	bindAddr.Address,
						&BindAddrList->Address[idx_addr],
						sizeof(struct  _AddrLstrans));

		KDPrintM(DBG_PROTO_ERROR, ("BindingAddr%d=%02x:%02x/%02x:%02x:%02x:%02x:%02x:%02x\n",
			idx_addr,
			bindAddr.Address[0].Address.Address[0],
			bindAddr.Address[0].Address.Address[1],
			bindAddr.Address[0].Address.Address[2],
			bindAddr.Address[0].Address.Address[3],
			bindAddr.Address[0].Address.Address[4],
			bindAddr.Address[0].Address.Address[5],
			bindAddr.Address[0].Address.Address[6],
			bindAddr.Address[0].Address.Address[7]
			));

		// We do not need encryption buffer for connect operation.
		overlappedLSS[idx_addr].EncryptBuffer = NULL;
		overlappedLSS[idx_addr].EncryptBufferLength = 0;

		LspCopy(&overlappedLSS[idx_addr], LSS, FALSE);

		//
		// Initialize overlapped buffer
		//

		KeInitializeEvent(&overlappedEvents[idx_addr], NotificationEvent, FALSE);
		overlappedWait[idx_addr] = &overlappedEvents[idx_addr];
		overlapped[idx_addr].IoCompleteRoutine = LstransConnectComp;
		overlapped[idx_addr].CompletionEvent = &overlappedEvents[idx_addr];
		overlapped[idx_addr].UserContext = NULL;

		//
		// Connect asynchronously
		//

		status = LspConnect(&overlappedLSS[idx_addr], &bindAddr, DestAddr, &overlapped[idx_addr], IF_NULL_TIMEOUT_THEN_DEFAULT(LSS, TimeOut));
		if(!NT_SUCCESS(status)) {
			// Set the completion event to continue with KeWaitForMultipleObjects()
			// even though this address fails.
			overlapped[idx_addr].IoStatusBlock.Status = status;
			KeSetEvent(overlapped[idx_addr].CompletionEvent, IO_NO_INCREMENT, FALSE);
			KDPrintM(DBG_PROTO_ERROR,("LspConnect() failed. idx=%d STATUS=%08lx\n", idx_addr, status));
		}
	}

	do {
		//
		// Wait for all connect completion events
		//

		status = KeWaitForMultipleObjects(
						BindAddrList->TAAddressCount,
						overlappedWait,
						WaitAll,
						Executive,
						KernelMode,
						FALSE,
						NULL,
						overlappedWaitBlocks);
		if(!NT_SUCCESS(status)) {
			ASSERT(FALSE);
			break;
		}

		//
		// Find the first connected address
		//

		for(idx_addr = 0; idx_addr < (ULONG)BindAddrList->TAAddressCount; idx_addr++) {
			status = overlapped[idx_addr].IoStatusBlock.Status;
			if(status == STATUS_SUCCESS) {
				break;
			}
		}

		//
		// Clean up unsuccessful or non-selected connections.
		//
		for(idx_cleanup_addr = 0; idx_cleanup_addr < (ULONG)BindAddrList->TAAddressCount; idx_cleanup_addr++) {
			if(idx_cleanup_addr != idx_addr)
				LspDisconnect(&overlappedLSS[idx_cleanup_addr]);
		}

		//
		// set return value
		//
		if(status == STATUS_SUCCESS) {
			if(BoundAddr) {
				LspCopy(LSS, &overlappedLSS[idx_addr], FALSE);

				BoundAddr->TAAddressCount = 1;
				RtlCopyMemory(	BoundAddr->Address,
					&BindAddrList->Address[idx_addr],
					sizeof(struct  _AddrLstrans));
			}
		} else {
			KDPrintM(DBG_PROTO_ERROR, ("Could not connect to the dest\n"));
		}

	} while(FALSE);


	ExFreePoolWithTag(overlappedLSS, LSS_OVERLAPPED_LSS_POOLTAG);
	ExFreePoolWithTag(overlappedWaitBlocks, LSS_OVERLAPPED_WAITBLOCK_POOLTAG);
	ExFreePoolWithTag(overlappedEvents, LSS_OVERLAPPED_EVENT_POOLTAG);
	ExFreePoolWithTag(overlapped, LSS_OVERLAPPED_BUFFER_POOLTAG);


	return status;
}
Exemplo n.º 6
0
NTSTATUS
LspCleanupLock(
   PLANSCSI_SESSION	LSS,
   UCHAR			LockNo
){
	NTSTATUS		status;
	LONG			i;
	LANSCSI_PDUDESC	pduDesc;
	BYTE			pduResponse;
	PLANSCSI_SESSION	tempLSS;
	LONG			maxConn;
	LARGE_INTEGER	GenericTimeOut;
	TA_LSTRANS_ADDRESS	BindingAddress, TargetAddress;
	LSSLOGIN_INFO	loginInfo;
	LSPROTO_TYPE	LSProto;
	ULONG			cleaned;

	//
	//	Parameter check
	//

	if(LSS->HWProtoVersion <= LSIDEPROTO_VERSION_1_0) {
		return STATUS_NOT_SUPPORTED;
	}

	if(LSS->HWVersion >= 1) {
		maxConn = LANSCSIIDE_MAX_CONNECTION_VER11 - 1;
	} else {
		return STATUS_NOT_SUPPORTED;
	}

	tempLSS = ExAllocatePoolWithTag(
							NonPagedPool,
							maxConn * sizeof(LANSCSI_SESSION),
							LSS_POOLTAG);
	RtlZeroMemory(tempLSS, maxConn * sizeof(LANSCSI_SESSION));

	//
	//	Init variables
	//

	status = STATUS_SUCCESS;
	RtlZeroMemory(&pduDesc, sizeof(LANSCSI_PDUDESC));
	pduDesc.Param64 = ((UINT64)(LockNo & 0x3)) << 32;	// Lock number: 32~33 bit.
	LspGetAddresses(LSS, &BindingAddress, &TargetAddress);
	GenericTimeOut.QuadPart = NANO100_PER_SEC * 5;
	cleaned = 0;


	//
	//	Try to make connections to fill up connection pool of the NDAS device.
	//	So, we can clear invalid acquisition of the locks.
	//
	KDPrintM(DBG_LURN_ERROR,("Try to clean up lock\n"));
	for (i=0 ; i < maxConn; i++) {


		//
		//	Connect and log in with read-only access.
		//

		//	connect
		LspSetTimeOut(&tempLSS[i], &GenericTimeOut);
		status = LspConnect(
					&tempLSS[i],
					&BindingAddress,
					&TargetAddress
					);
		if(!NT_SUCCESS(status)) {
			KDPrintM(DBG_LURN_ERROR, ("LspConnect(), Can't Connect to the LS node. STATUS:0x%08x\n", status));
			break;
		}
	}


	for (i=0; i < maxConn; i++) {

		if(!LspIsConnected(&tempLSS[i])) {
			continue;
		}

		KDPrintM(DBG_LURN_TRACE, ("Con#%u\n", i));
		cleaned++;

		//	extract login information from the existing LSS.
		LspBuildLoginInfo(LSS, &loginInfo);
		status = LspLookupProtocol(loginInfo.HWType, loginInfo.HWVersion, &LSProto);
		if(!NT_SUCCESS(status)) {
			LspDisconnect(&tempLSS[i]);
			KDPrintM(DBG_LURN_ERROR, ("Wrong hardware version.\n"));
			continue;
		}

		//	Log in with read-only access.
		loginInfo.UserID &= 0x0000ffff;
		status = LspLogin(
						&tempLSS[i],
						&loginInfo,
						LSProto,
						FALSE
					);
		if(!NT_SUCCESS(status)) {
			KDPrintM(DBG_LURN_ERROR, ("LspLogin() failed. STATUS:0x%08x\n", status));
			LspDisconnect(&tempLSS[i]);
			ASSERT(FALSE);
			continue;
		}


		//
		//	Acquire the lock on the NDAS device.
		//

		pduDesc.Command = VENDOR_OP_SET_SEMA;
		status = LspVendorRequest(
						&tempLSS[i],
						&pduDesc,
						&pduResponse
						);
		if(pduResponse != LANSCSI_RESPONSE_SUCCESS) {
			KDPrintM(DBG_LURN_ERROR,	("Acquiring lock #%u denied by NDAS device\n", LockNo));
		}
		if(!NT_SUCCESS(status)) {
			LspDisconnect(&tempLSS[i]);
			KDPrintM(DBG_LURN_ERROR, ("LspVendorRequest() failed. STATUS=%08lx\n", status));
			continue;
		}

		//
		//	Release the lock on the NDAS device.
		//

		pduDesc.Command = VENDOR_OP_FREE_SEMA;
		status = LspVendorRequest(
						&tempLSS[i],
						&pduDesc,
						&pduResponse
						);
		if(pduResponse != LANSCSI_RESPONSE_SUCCESS) {
			KDPrintM(DBG_LURN_ERROR,	("Releasing lock #%u denied by NDAS device\n", LockNo));
		}
		if(!NT_SUCCESS(status)) {
			LspDisconnect(&tempLSS[i]);
			KDPrintM(DBG_LURN_ERROR, ("LspVendorRequest() failed. STATUS=%08lx\n", status));
			continue;
		}


		//
		//	Log out and disconnect.
		//

		LspLogout(
			&tempLSS[i]
			);

		LspDisconnect(
			&tempLSS[i]
			);
	}

	KDPrintM(DBG_LURN_INFO, ("Cleaned #%u\n", cleaned));

	ExFreePool(tempLSS);

	return status;
}