2 Miscellaneous routines for IScsi driver.
4 Copyright (c) 2004 - 2008, Intel Corporation
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.
19 Miscellaneous routines for IScsi driver.
23 #include "IScsiImpl.h"
25 STATIC CONST CHAR8 IScsiHexString
[] = "0123456789ABCDEFabcdef";
28 Determines if a Unicode character is a hexadecimal digit.
29 The test is case insensitive.
31 @param Digit[out] Pointer to byte that receives the value of the hex character.
33 @param Char[in] Unicode character to test.
35 @retval TRUE If the character is a hexadecimal digit.
37 @retval FALSE Otherwise.
47 if ((Char
>= L
'0') && (Char
<= L
'9')) {
48 *Digit
= (UINT8
) (Char
- L
'0');
52 if ((Char
>= L
'A') && (Char
<= L
'F')) {
53 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
57 if ((Char
>= L
'a') && (Char
<= L
'f')) {
58 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
66 Removes (trims) specified leading and trailing characters from a string.
68 @param str[in][out] Pointer to the null-terminated string to be trimmed. On return,
69 str will hold the trimmed string.
71 @param CharC[in] Character will be trimmed from str.
91 // Trim off the leading and trailing characters c
93 for (p1
= str
; *p1
&& *p1
== CharC
; p1
++) {
113 for (p1
= str
+ StrLen(str
) - 1; p1
>= str
&& *p1
== CharC
; p1
--) {
116 if (p1
!= str
+ StrLen(str
) - 1) {
122 Calculate the prefix length of the IPv4 subnet mask.
124 @param SubnetMask[in] The IPv4 subnet mask.
126 @retval The prefix length of the subnet mask.
130 IScsiGetSubnetMaskPrefixLength (
131 IN EFI_IPv4_ADDRESS
*SubnetMask
138 // The SubnetMask is in network byte order.
140 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
145 ReverseMask
= ~ReverseMask
;
147 if (ReverseMask
& (ReverseMask
+ 1)) {
153 while (ReverseMask
!= 0) {
154 ReverseMask
= ReverseMask
>> 1;
158 return (UINT8
) (32 - Len
);
162 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
164 @param Str[in] The hexadecimal encoded LUN string.
166 @param Lun[out] Storage to return the 64-bit LUN.
168 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
170 @retval EFI_INVALID_PARAMETER The string is malformatted.
180 CHAR8
*LunUnitStr
[4];
185 ZeroMem (LunUnitStr
, sizeof (LunUnitStr
));
190 if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
191 return EFI_INVALID_PARAMETER
;
194 while (*Str
!= '\0') {
196 // Legal representations of LUN:
197 // 4752-3A4F-6b7e-2F99,
205 if (*(Str
+ 1) != '\0') {
206 if (!IsHexDigit ((UINT8
*) &Digit
, *(Str
+ 1))) {
207 return EFI_INVALID_PARAMETER
;
210 LunUnitStr
[Index
] = Str
+ 1;
212 } else if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
213 return EFI_INVALID_PARAMETER
;
219 for (Index
= 0; (Index
< 4) && (LunUnitStr
[Index
] != NULL
); Index
++) {
220 if (AsciiStrLen (LunUnitStr
[Index
]) > 4) {
221 return EFI_INVALID_PARAMETER
;
224 Temp
= AsciiStrHexToUintn (LunUnitStr
[Index
]);
225 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Temp
);
232 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
234 @param Lun[in] The 64-bit LUN.
236 @param Str[out] The storage to return the hexadecimal encoded LUN string.
242 IScsiLunToUnicodeStr (
252 for (Index
= 0; Index
< 4; Index
++) {
254 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
255 StrCpy (TempStr
, L
"0-");
257 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
258 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0xf];
259 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
260 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0xf];
264 StrTrim (TempStr
, L
'0');
267 TempStr
+= StrLen (TempStr
);
270 Str
[StrLen (Str
) - 1] = 0;
272 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
273 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
282 Convert the ASCII string into a UNICODE string.
284 @param Source[out] The ASCII string.
286 @param Destination[out] The storage to return the UNICODE string.
288 @retval CHAR16 * Pointer to the UNICODE string.
292 IScsiAsciiStrToUnicodeStr (
294 OUT CHAR16
*Destination
297 ASSERT (Destination
!= NULL
);
298 ASSERT (Source
!= NULL
);
300 while (*Source
!= '\0') {
301 *(Destination
++) = (CHAR16
) *(Source
++);
310 Convert the UNICODE string into an ASCII string.
312 @param Source[in] The UNICODE string.
314 @param Destination[out] The storage to return the ASCII string.
316 @retval CHAR8 * Pointer to the ASCII string.
320 IScsiUnicodeStrToAsciiStr (
322 OUT CHAR8
*Destination
325 ASSERT (Destination
!= NULL
);
326 ASSERT (Source
!= NULL
);
328 while (*Source
!= '\0') {
330 // If any Unicode characters in Source contain
331 // non-zero value in the upper 8 bits, then ASSERT().
333 ASSERT (*Source
< 0x100);
334 *(Destination
++) = (CHAR8
) *(Source
++);
343 Convert the decimal dotted IPv4 address into the binary IPv4 address.
345 @param Str[in] The UNICODE string.
347 @param Ip[out] The storage to return the ASCII string.
349 @retval EFI_SUCCESS The binary IP address is returned in Ip.
351 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
357 OUT EFI_IPv4_ADDRESS
*Ip
368 return EFI_INVALID_PARAMETER
;
372 while (NET_IS_DIGIT (*Str
)) {
373 Number
= Number
* 10 + (*Str
- '0');
378 return EFI_INVALID_PARAMETER
;
381 Ip
->Addr
[Index
] = (UINT8
) Number
;
383 if ((*Str
!= '\0') && (*Str
!= '.')) {
385 // The current character should be either the NULL terminator or
386 // the dot delimiter.
388 return EFI_INVALID_PARAMETER
;
393 // Skip the delimiter.
402 return EFI_INVALID_PARAMETER
;
409 Convert the mac address into a hexadecimal encoded "-" seperated string.
411 @param Mac[in] The mac address.
413 @param Len[in] Length in bytes of the mac address.
415 @param Str[out] The storage to return the mac string.
422 IN EFI_MAC_ADDRESS
*Mac
,
429 for (Index
= 0; Index
< Len
; Index
++) {
430 Str
[3 * Index
] = NibbleToHexChar ((UINT8
) (Mac
->Addr
[Index
] >> 4));
431 Str
[3 * Index
+ 1] = NibbleToHexChar (Mac
->Addr
[Index
]);
432 Str
[3 * Index
+ 2] = L
'-';
435 Str
[3 * Index
- 1] = L
'\0';
439 Convert the binary encoded buffer into a hexadecimal encoded string.
441 @param BinBuffer[in] The buffer containing the binary data.
443 @param BinLength[in] Length of the binary buffer.
445 @param HexStr[in][out] Pointer to the string.
447 @param HexLength[in][out] The length of the string.
449 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
450 and the length of the string is updated.
452 @retval EFI_BUFFER_TOO_SMALL The string is too small.
459 IN OUT CHAR8
*HexStr
,
460 IN OUT UINT32
*HexLength
465 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
466 return EFI_INVALID_PARAMETER
;
469 if (((*HexLength
) - 3) < BinLength
* 2) {
470 *HexLength
= BinLength
* 2 + 3;
471 return EFI_BUFFER_TOO_SMALL
;
474 *HexLength
= BinLength
* 2 + 3;
476 // Prefix for Hex String
481 for (Index
= 0; Index
< BinLength
; Index
++) {
482 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
483 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
486 HexStr
[Index
* 2 + 2] = '\0';
492 Convert the hexadecimal string into a binary encoded buffer.
494 @param BinBuffer[in][out] The binary buffer.
496 @param BinLength[in][out] Length of the binary buffer.
498 @param HexStr[in] The hexadecimal string.
500 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
503 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.s
508 IN OUT UINT8
*BinBuffer
,
509 IN OUT UINT32
*BinLength
,
522 // Find out how many hex characters the string has.
525 if ((HexBuf
[0] == '0') && ((HexBuf
[1] == 'x') || (HexBuf
[1] == 'X'))) {
529 for (Index
= 0, HexCount
= 0; IsHexDigit (&Digit
, HexBuf
[Index
]); Index
++, HexCount
++)
537 // Test if buffer is passed enough.
539 if (((HexCount
+ 1) / 2) > *BinLength
) {
540 *BinLength
= (HexCount
+ 1) / 2;
541 return EFI_BUFFER_TOO_SMALL
;
544 *BinLength
= (HexCount
+ 1) / 2;
546 for (Index
= 0; Index
< HexCount
; Index
++) {
548 IsHexDigit (&Digit
, HexBuf
[HexCount
- 1 - Index
]);
550 if ((Index
& 1) == 0) {
553 Byte
= BinBuffer
[*BinLength
- 1 - Index
/ 2];
555 Byte
= (UINT8
) (Byte
| (Digit
<< 4));
558 BinBuffer
[*BinLength
- 1 - Index
/ 2] = Byte
;
565 Generate random numbers.
567 @param Rand[in][out] The buffer to contain random numbers.
569 @param RandLength[in] The length of the Rand buffer.
582 while (RandLength
> 0) {
583 Random
= NET_RANDOM (NetRandomInitSeed ());
584 *Rand
++ = (UINT8
) (Random
);
590 Create the iSCSI driver data..
592 @param Image[in] The handle of the driver image.
594 @param Controller[in] The handle of the controller.
596 @retval The iSCSI driver data created.
600 IScsiCreateDriverData (
602 IN EFI_HANDLE Controller
605 ISCSI_DRIVER_DATA
*Private
;
608 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
609 if (Private
== NULL
) {
613 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
614 Private
->Image
= Image
;
615 Private
->Controller
= Controller
;
618 // Create an event to be signal when the BS to RT transition is triggerd so
619 // as to abort the iSCSI session.
621 Status
= gBS
->CreateEvent (
622 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES
,
624 IScsiOnExitBootService
,
626 &Private
->ExitBootServiceEvent
628 if (EFI_ERROR (Status
)) {
629 gBS
->FreePool (Private
);
633 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
636 // 0 is designated to the TargetId, so use another value for the AdapterId.
638 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
639 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
640 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
641 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
644 // Install the Ext SCSI PASS THRU protocol.
646 Status
= gBS
->InstallProtocolInterface (
647 &Private
->ExtScsiPassThruHandle
,
648 &gEfiExtScsiPassThruProtocolGuid
,
649 EFI_NATIVE_INTERFACE
,
650 &Private
->IScsiExtScsiPassThru
652 if (EFI_ERROR (Status
)) {
653 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
654 gBS
->FreePool (Private
);
659 IScsiSessionInit (&Private
->Session
, FALSE
);
665 Clean the iSCSI driver data.
667 @param Private[in] The iSCSI driver data.
673 IScsiCleanDriverData (
674 IN ISCSI_DRIVER_DATA
*Private
677 if (Private
->DevicePath
!= NULL
) {
678 gBS
->UninstallProtocolInterface (
679 Private
->ExtScsiPassThruHandle
,
680 &gEfiDevicePathProtocolGuid
,
684 gBS
->FreePool (Private
->DevicePath
);
687 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
688 gBS
->UninstallProtocolInterface (
689 Private
->ExtScsiPassThruHandle
,
690 &gEfiExtScsiPassThruProtocolGuid
,
691 &Private
->IScsiExtScsiPassThru
695 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
697 gBS
->FreePool (Private
);
702 Get the various configuration data of this iSCSI instance.
704 @param Private[in] The iSCSI driver data.
706 @retval EFI_SUCCESS The configuration of this instance is got.
708 @retval EFI_NOT_FOUND This iSCSI instance is not configured yet.
713 IN ISCSI_DRIVER_DATA
*Private
717 ISCSI_SESSION
*Session
;
719 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
720 EFI_SIMPLE_NETWORK_MODE
*Mode
;
721 CHAR16 MacString
[65];
724 // get the iSCSI Initiator Name
726 Session
= &Private
->Session
;
727 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
728 Status
= gIScsiInitiatorName
.Get (
729 &gIScsiInitiatorName
,
730 &Session
->InitiatorNameLength
,
731 Session
->InitiatorName
733 if (EFI_ERROR (Status
)) {
737 Status
= gBS
->HandleProtocol (
739 &gEfiSimpleNetworkProtocolGuid
,
742 if (EFI_ERROR (Status
)) {
749 // Get the mac string, it's the name of various variable
751 IScsiMacAddrToStr (&Mode
->PermanentAddress
, Mode
->HwAddressSize
, MacString
);
754 // Get the normal configuration.
756 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
757 Status
= gRT
->GetVariable (
759 &gEfiIScsiInitiatorNameProtocolGuid
,
762 &Session
->ConfigData
.NvData
764 if (EFI_ERROR (Status
)) {
768 if (!Session
->ConfigData
.NvData
.Enabled
) {
772 // Get the CHAP Auth information.
774 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
775 Status
= gRT
->GetVariable (
777 &mIScsiCHAPAuthInfoGuid
,
780 &Session
->AuthData
.AuthConfig
783 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
787 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
794 Get the device path of the iSCSI tcp connection and update it.
796 @param Private[in] The iSCSI driver data.
798 @retval The updated device path.
801 EFI_DEVICE_PATH_PROTOCOL
*
802 IScsiGetTcpConnDevicePath (
803 IN ISCSI_DRIVER_DATA
*Private
806 ISCSI_SESSION
*Session
;
807 ISCSI_CONNECTION
*Conn
;
809 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
811 EFI_DEV_PATH
*DPathNode
;
813 Session
= &Private
->Session
;
814 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
818 Conn
= NET_LIST_USER_STRUCT_S (
819 Session
->Conns
.ForwardLink
,
822 ISCSI_CONNECTION_SIGNATURE
824 Tcp4Io
= &Conn
->Tcp4Io
;
826 Status
= gBS
->HandleProtocol (
828 &gEfiDevicePathProtocolGuid
,
831 if (EFI_ERROR (Status
)) {
837 DevicePath
= DuplicateDevicePath (DevicePath
);
839 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
841 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
842 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
843 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
846 DPathNode
->Ipv4
.LocalPort
= 0;
847 DPathNode
->Ipv4
.StaticIpAddress
= (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
851 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
858 Abort the session when the transition from BS to RT is initiated.
860 @param Event[in] The event signaled.
862 @param Context[in] The iSCSI driver data.
869 IScsiOnExitBootService (
874 ISCSI_DRIVER_DATA
*Private
;
876 Private
= (ISCSI_DRIVER_DATA
*) Context
;
877 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
879 IScsiSessionAbort (&Private
->Session
);