2 Miscellaneous routines for iSCSI driver.
4 Copyright (c) 2004 - 2008, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "IScsiImpl.h"
17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString
[] = "0123456789ABCDEFabcdef";
20 Removes (trims) specified leading and trailing characters from a string.
22 @param[in, out] Str Pointer to the null-terminated string to be trimmed. On return,
23 Str will hold the trimmed string.
25 @param[in] CharC Character will be trimmed from str.
41 // Trim off the leading and trailing characters c
43 for (Pointer1
= Str
; (*Pointer1
!= 0) && (*Pointer1
== CharC
); Pointer1
++) {
48 if (Pointer2
== Pointer1
) {
49 while (*Pointer1
!= 0) {
54 while (*Pointer1
!= 0) {
55 *Pointer2
= *Pointer1
;
63 for (Pointer1
= Str
+ StrLen(Str
) - 1; Pointer1
>= Str
&& *Pointer1
== CharC
; Pointer1
--) {
66 if (Pointer1
!= Str
+ StrLen(Str
) - 1) {
72 Calculate the prefix length of the IPv4 subnet mask.
74 @param[in] SubnetMask The IPv4 subnet mask.
76 @return The prefix length of the subnet mask.
77 @retval 0 Other errors as indicated.
80 IScsiGetSubnetMaskPrefixLength (
81 IN EFI_IPv4_ADDRESS
*SubnetMask
88 // The SubnetMask is in network byte order.
90 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
95 ReverseMask
= ~ReverseMask
;
97 if ((ReverseMask
& (ReverseMask
+ 1)) != 0) {
103 while (ReverseMask
!= 0) {
104 ReverseMask
= ReverseMask
>> 1;
108 return (UINT8
) (32 - Len
);
112 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
114 @param[in] Str The hexadecimal encoded LUN string.
115 @param[out] Lun Storage to return the 64-bit LUN.
117 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
118 @retval EFI_INVALID_PARAMETER The string is malformatted.
127 CHAR8
*LunUnitStr
[4];
132 ZeroMem (LunUnitStr
, sizeof (LunUnitStr
));
137 if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
138 return EFI_INVALID_PARAMETER
;
141 while (*Str
!= '\0') {
143 // Legal representations of LUN:
144 // 4752-3A4F-6b7e-2F99,
152 if (*(Str
+ 1) != '\0') {
153 if (!IsHexDigit ((UINT8
*) &Digit
, *(Str
+ 1))) {
154 return EFI_INVALID_PARAMETER
;
157 LunUnitStr
[Index
] = Str
+ 1;
159 } else if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
160 return EFI_INVALID_PARAMETER
;
166 for (Index
= 0; (Index
< 4) && (LunUnitStr
[Index
] != NULL
); Index
++) {
167 if (AsciiStrLen (LunUnitStr
[Index
]) > 4) {
168 return EFI_INVALID_PARAMETER
;
171 Temp
= AsciiStrHexToUintn (LunUnitStr
[Index
]);
172 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Temp
);
179 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
181 @param[in] Lun The 64-bit LUN.
182 @param[out] Str The storage to return the hexadecimal encoded LUN string.
185 IScsiLunToUnicodeStr (
195 for (Index
= 0; Index
< 4; Index
++) {
197 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
198 StrCpy (TempStr
, L
"0-");
200 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
201 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0x0F];
202 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
203 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0x0F];
207 StrTrim (TempStr
, L
'0');
210 TempStr
+= StrLen (TempStr
);
213 Str
[StrLen (Str
) - 1] = 0;
215 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
216 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
225 Convert the ASCII string into a UNICODE string.
227 @param[in] Source The ASCII string.
228 @param[out] Destination The storage to return the UNICODE string.
230 @return CHAR16 * Pointer to the UNICODE string.
233 IScsiAsciiStrToUnicodeStr (
235 OUT CHAR16
*Destination
238 ASSERT (Destination
!= NULL
);
239 ASSERT (Source
!= NULL
);
241 while (*Source
!= '\0') {
242 *(Destination
++) = (CHAR16
) *(Source
++);
251 Convert the UNICODE string into an ASCII string.
253 @param[in] Source The UNICODE string.
254 @param[out] Destination The storage to return the ASCII string.
256 @return CHAR8 * Pointer to the ASCII string.
259 IScsiUnicodeStrToAsciiStr (
261 OUT CHAR8
*Destination
264 ASSERT (Destination
!= NULL
);
265 ASSERT (Source
!= NULL
);
267 while (*Source
!= '\0') {
269 // If any Unicode characters in Source contain
270 // non-zero value in the upper 8 bits, then ASSERT().
272 ASSERT (*Source
< 0x100);
273 *(Destination
++) = (CHAR8
) *(Source
++);
282 Convert the decimal dotted IPv4 address into the binary IPv4 address.
284 @param[in] Str The UNICODE string.
285 @param[out] Ip The storage to return the ASCII string.
287 @retval EFI_SUCCESS The binary IP address is returned in Ip.
288 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
293 OUT EFI_IPv4_ADDRESS
*Ip
304 return EFI_INVALID_PARAMETER
;
308 while (NET_IS_DIGIT (*Str
)) {
309 Number
= Number
* 10 + (*Str
- '0');
314 return EFI_INVALID_PARAMETER
;
317 Ip
->Addr
[Index
] = (UINT8
) Number
;
319 if ((*Str
!= '\0') && (*Str
!= '.')) {
321 // The current character should be either the NULL terminator or
322 // the dot delimiter.
324 return EFI_INVALID_PARAMETER
;
329 // Skip the delimiter.
338 return EFI_INVALID_PARAMETER
;
345 Convert the mac address into a hexadecimal encoded "-" seperated string.
347 @param[in] Mac The mac address.
348 @param[in] Len Length in bytes of the mac address.
349 @param[out] Str The storage to return the mac string.
353 IN EFI_MAC_ADDRESS
*Mac
,
360 for (Index
= 0; Index
< Len
; Index
++) {
361 Str
[3 * Index
] = (CHAR16
) IScsiHexString
[(Mac
->Addr
[Index
] >> 4) & 0x0F];
362 Str
[3 * Index
+ 1] = (CHAR16
) IScsiHexString
[Mac
->Addr
[Index
] & 0x0F];
363 Str
[3 * Index
+ 2] = L
'-';
366 Str
[3 * Index
- 1] = L
'\0';
370 Convert the binary encoded buffer into a hexadecimal encoded string.
372 @param[in] BinBuffer The buffer containing the binary data.
373 @param[in] BinLength Length of the binary buffer.
374 @param[in, out] HexStr Pointer to the string.
375 @param[in, out] HexLength The length of the string.
377 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
378 and the length of the string is updated.
379 @retval EFI_BUFFER_TOO_SMALL The string is too small.
380 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
386 IN OUT CHAR8
*HexStr
,
387 IN OUT UINT32
*HexLength
392 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
393 return EFI_INVALID_PARAMETER
;
396 if (((*HexLength
) - 3) < BinLength
* 2) {
397 *HexLength
= BinLength
* 2 + 3;
398 return EFI_BUFFER_TOO_SMALL
;
401 *HexLength
= BinLength
* 2 + 3;
403 // Prefix for Hex String
408 for (Index
= 0; Index
< BinLength
; Index
++) {
409 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
410 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0x0F];
413 HexStr
[Index
* 2 + 2] = '\0';
419 Convert the hexadecimal string into a binary encoded buffer.
421 @param[in, out] BinBuffer The binary buffer.
422 @param[in, out] BinLength Length of the binary buffer.
423 @param[in] HexStr The hexadecimal string.
425 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
427 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
431 IN OUT UINT8
*BinBuffer
,
432 IN OUT UINT32
*BinLength
,
445 // Find out how many hex characters the string has.
448 if ((HexBuf
[0] == '0') && ((HexBuf
[1] == 'x') || (HexBuf
[1] == 'X'))) {
452 for (Index
= 0, HexCount
= 0; IsHexDigit (&Digit
, HexBuf
[Index
]); Index
++, HexCount
++)
460 // Test if buffer is passed enough.
462 if (((HexCount
+ 1) / 2) > *BinLength
) {
463 *BinLength
= (HexCount
+ 1) / 2;
464 return EFI_BUFFER_TOO_SMALL
;
467 *BinLength
= (HexCount
+ 1) / 2;
469 for (Index
= 0; Index
< HexCount
; Index
++) {
471 IsHexDigit (&Digit
, HexBuf
[HexCount
- 1 - Index
]);
473 if ((Index
& 1) == 0) {
476 Byte
= BinBuffer
[*BinLength
- 1 - Index
/ 2];
478 Byte
= (UINT8
) (Byte
| (Digit
<< 4));
481 BinBuffer
[*BinLength
- 1 - Index
/ 2] = Byte
;
488 Generate random numbers.
490 @param[in, out] Rand The buffer to contain random numbers.
491 @param[in] RandLength The length of the Rand buffer.
501 while (RandLength
> 0) {
502 Random
= NET_RANDOM (NetRandomInitSeed ());
503 *Rand
++ = (UINT8
) (Random
);
509 Create the iSCSI driver data..
511 @param[in] Image The handle of the driver image.
512 @param[in] Controller The handle of the controller.
514 @return The iSCSI driver data created.
515 @retval NULL Other errors as indicated.
518 IScsiCreateDriverData (
520 IN EFI_HANDLE Controller
523 ISCSI_DRIVER_DATA
*Private
;
526 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
527 if (Private
== NULL
) {
531 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
532 Private
->Image
= Image
;
533 Private
->Controller
= Controller
;
536 // Create an event to be signal when the BS to RT transition is triggerd so
537 // as to abort the iSCSI session.
539 Status
= gBS
->CreateEventEx (
542 IScsiOnExitBootService
,
544 &gEfiEventExitBootServicesGuid
,
545 &Private
->ExitBootServiceEvent
547 if (EFI_ERROR (Status
)) {
548 gBS
->FreePool (Private
);
552 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
555 // 0 is designated to the TargetId, so use another value for the AdapterId.
557 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
558 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
559 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
560 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
563 // Install the Ext SCSI PASS THRU protocol.
565 Status
= gBS
->InstallProtocolInterface (
566 &Private
->ExtScsiPassThruHandle
,
567 &gEfiExtScsiPassThruProtocolGuid
,
568 EFI_NATIVE_INTERFACE
,
569 &Private
->IScsiExtScsiPassThru
571 if (EFI_ERROR (Status
)) {
572 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
573 gBS
->FreePool (Private
);
578 IScsiSessionInit (&Private
->Session
, FALSE
);
584 Clean the iSCSI driver data.
586 @param[in] Private The iSCSI driver data.
589 IScsiCleanDriverData (
590 IN ISCSI_DRIVER_DATA
*Private
593 if (Private
->DevicePath
!= NULL
) {
594 gBS
->UninstallProtocolInterface (
595 Private
->ExtScsiPassThruHandle
,
596 &gEfiDevicePathProtocolGuid
,
600 gBS
->FreePool (Private
->DevicePath
);
603 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
604 gBS
->UninstallProtocolInterface (
605 Private
->ExtScsiPassThruHandle
,
606 &gEfiExtScsiPassThruProtocolGuid
,
607 &Private
->IScsiExtScsiPassThru
611 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
613 gBS
->FreePool (Private
);
617 Get the various configuration data of this iSCSI instance.
619 @param[in] Private The iSCSI driver data.
621 @retval EFI_SUCCESS The configuration of this instance is got.
622 @retval EFI_ABORTED The operation was aborted.
623 @retval Others Other errors as indicated.
627 IN ISCSI_DRIVER_DATA
*Private
631 ISCSI_SESSION
*Session
;
633 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
634 EFI_SIMPLE_NETWORK_MODE
*Mode
;
635 CHAR16 MacString
[65];
638 // get the iSCSI Initiator Name
640 Session
= &Private
->Session
;
641 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
642 Status
= gIScsiInitiatorName
.Get (
643 &gIScsiInitiatorName
,
644 &Session
->InitiatorNameLength
,
645 Session
->InitiatorName
647 if (EFI_ERROR (Status
)) {
651 Status
= gBS
->HandleProtocol (
653 &gEfiSimpleNetworkProtocolGuid
,
656 if (EFI_ERROR (Status
)) {
663 // Get the mac string, it's the name of various variable
665 IScsiMacAddrToStr (&Mode
->PermanentAddress
, Mode
->HwAddressSize
, MacString
);
668 // Get the normal configuration.
670 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
671 Status
= gRT
->GetVariable (
673 &gEfiIScsiInitiatorNameProtocolGuid
,
676 &Session
->ConfigData
.NvData
678 if (EFI_ERROR (Status
)) {
682 if (!Session
->ConfigData
.NvData
.Enabled
) {
686 // Get the CHAP Auth information.
688 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
689 Status
= gRT
->GetVariable (
691 &mIScsiCHAPAuthInfoGuid
,
694 &Session
->AuthData
.AuthConfig
697 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
701 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
708 Get the device path of the iSCSI tcp connection and update it.
710 @param[in] Private The iSCSI driver data.
712 @return The updated device path.
713 @retval NULL Other errors as indicated.
715 EFI_DEVICE_PATH_PROTOCOL
*
716 IScsiGetTcpConnDevicePath (
717 IN ISCSI_DRIVER_DATA
*Private
720 ISCSI_SESSION
*Session
;
721 ISCSI_CONNECTION
*Conn
;
723 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
725 EFI_DEV_PATH
*DPathNode
;
727 Session
= &Private
->Session
;
728 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
732 Conn
= NET_LIST_USER_STRUCT_S (
733 Session
->Conns
.ForwardLink
,
736 ISCSI_CONNECTION_SIGNATURE
738 Tcp4Io
= &Conn
->Tcp4Io
;
740 Status
= gBS
->HandleProtocol (
742 &gEfiDevicePathProtocolGuid
,
745 if (EFI_ERROR (Status
)) {
751 DevicePath
= DuplicateDevicePath (DevicePath
);
753 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
755 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
756 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
757 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
760 DPathNode
->Ipv4
.LocalPort
= 0;
761 DPathNode
->Ipv4
.StaticIpAddress
= (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
765 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
772 Abort the session when the transition from BS to RT is initiated.
774 @param[in] Event The event signaled.
775 @param[in] Context The iSCSI driver data.
779 IScsiOnExitBootService (
784 ISCSI_DRIVER_DATA
*Private
;
786 Private
= (ISCSI_DRIVER_DATA
*) Context
;
787 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
789 IScsiSessionAbort (&Private
->Session
);