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; }
////////////////////////////////////////////////////////////////////////// // // 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; }
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; }
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; }
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; }
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; }