3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Miscellaneous routines for iSCSI driver.
22 #include "IScsiImpl.h"
24 STATIC CONST CHAR8 IScsiHexString
[] = "0123456789ABCDEFabcdef";
35 Determines if a Unicode character is a hexadecimal digit.
36 The test is case insensitive.
39 Digit - Pointer to byte that receives the value of the hex character.
40 Char - Unicode character to test.
43 TRUE - If the character is a hexadecimal digit.
48 if ((Char
>= L
'0') && (Char
<= L
'9')) {
49 *Digit
= (UINT8
) (Char
- L
'0');
53 if ((Char
>= L
'A') && (Char
<= L
'F')) {
54 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
58 if ((Char
>= L
'a') && (Char
<= L
'f')) {
59 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
76 Removes (trims) specified leading and trailing characters from a string.
80 str - Pointer to the null-terminated string to be trimmed. On return,
81 str will hold the trimmed string.
82 CharC - Character will be trimmed from str.
96 // Trim off the leading and trailing characters c
98 for (p1
= str
; *p1
&& *p1
== CharC
; p1
++) {
118 for (p1
= str
+ StrLen(str
) - 1; p1
>= str
&& *p1
== CharC
; p1
--) {
121 if (p1
!= str
+ StrLen(str
) - 1) {
127 IScsiGetSubnetMaskPrefixLength (
128 IN EFI_IPv4_ADDRESS
*SubnetMask
134 Calculate the prefix length of the IPv4 subnet mask.
138 SubnetMask - The IPv4 subnet mask.
142 The prefix length of the subnet mask.
150 // The SubnetMask is in network byte order.
152 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
157 ReverseMask
= ~ReverseMask
;
159 if (ReverseMask
& (ReverseMask
+ 1)) {
165 while (ReverseMask
!= 0) {
166 ReverseMask
= ReverseMask
>> 1;
170 return (UINT8
) (32 - Len
);
182 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
186 Str - The hexadecimal encoded LUN string.
187 Lun - Storage to return the 64-bit LUN.
191 EFI_SUCCESS - The 64-bit LUN is stored in Lun.
192 EFI_INVALID_PARAMETER - The string is malformatted.
197 CHAR8
*LunUnitStr
[4];
202 ZeroMem (LunUnitStr
, sizeof (LunUnitStr
));
207 if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
208 return EFI_INVALID_PARAMETER
;
211 while (*Str
!= '\0') {
213 // Legal representations of LUN:
214 // 4752-3A4F-6b7e-2F99,
222 if (*(Str
+ 1) != '\0') {
223 if (!IsHexDigit ((UINT8
*) &Digit
, *(Str
+ 1))) {
224 return EFI_INVALID_PARAMETER
;
227 LunUnitStr
[Index
] = Str
+ 1;
229 } else if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
230 return EFI_INVALID_PARAMETER
;
236 for (Index
= 0; (Index
< 4) && (LunUnitStr
[Index
] != NULL
); Index
++) {
237 if (AsciiStrLen (LunUnitStr
[Index
]) > 4) {
238 return EFI_INVALID_PARAMETER
;
241 Temp
= AsciiStrHexToUintn (LunUnitStr
[Index
]);
242 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Temp
);
249 IScsiLunToUnicodeStr (
257 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
261 Lun - The 64-bit LUN.
262 Str - The storage to return the hexadecimal encoded LUN string.
275 for (Index
= 0; Index
< 4; Index
++) {
277 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
278 StrCpy (TempStr
, L
"0-");
280 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
281 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0xf];
282 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
283 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0xf];
287 StrTrim (TempStr
, L
'0');
290 TempStr
+= StrLen (TempStr
);
293 Str
[StrLen (Str
) - 1] = 0;
295 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
296 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
305 IScsiAsciiStrToUnicodeStr (
307 OUT CHAR16
*Destination
313 Convert the ASCII string into a UNICODE string.
317 Source - The ASCII string.
318 Destination - The storage to return the UNICODE string.
322 Pointer to the UNICODE string.
326 ASSERT (Destination
!= NULL
);
327 ASSERT (Source
!= NULL
);
329 while (*Source
!= '\0') {
330 *(Destination
++) = (CHAR16
) *(Source
++);
339 IScsiUnicodeStrToAsciiStr (
341 OUT CHAR8
*Destination
347 Convert the UNICODE string into an ASCII string.
351 Source - The UNICODE string.
352 Destination - The storage to return the ASCII string.
356 Pointer to the ASCII string.
360 ASSERT (Destination
!= NULL
);
361 ASSERT (Source
!= NULL
);
363 while (*Source
!= '\0') {
365 // If any Unicode characters in Source contain
366 // non-zero value in the upper 8 bits, then ASSERT().
368 ASSERT (*Source
< 0x100);
369 *(Destination
++) = (CHAR8
) *(Source
++);
380 OUT EFI_IPv4_ADDRESS
*Ip
386 Convert the decimal dotted IPv4 address into the binary IPv4 address.
390 Str - The UNICODE string.
391 Ip - The storage to return the ASCII string.
395 EFI_SUCCESS - The binary IP address is returned in Ip.
396 EFI_INVALID_PARAMETER - The IP string is malformatted.
408 return EFI_INVALID_PARAMETER
;
412 while (NET_IS_DIGIT (*Str
)) {
413 Number
= Number
* 10 + (*Str
- '0');
418 return EFI_INVALID_PARAMETER
;
421 Ip
->Addr
[Index
] = (UINT8
) Number
;
423 if ((*Str
!= '\0') && (*Str
!= '.')) {
425 // The current character should be either the NULL terminator or
426 // the dot delimiter.
428 return EFI_INVALID_PARAMETER
;
433 // Skip the delimiter.
442 return EFI_INVALID_PARAMETER
;
450 IN EFI_MAC_ADDRESS
*Mac
,
458 Convert the mac address into a hexadecimal encoded "-" seperated string.
462 Mac - The mac address.
463 Len - Length in bytes of the mac address.
464 Str - The storage to return the mac string.
474 for (Index
= 0; Index
< Len
; Index
++) {
475 Str
[3 * Index
] = NibbleToHexChar ((UINT8
) (Mac
->Addr
[Index
] >> 4));
476 Str
[3 * Index
+ 1] = NibbleToHexChar (Mac
->Addr
[Index
]);
477 Str
[3 * Index
+ 2] = L
'-';
480 Str
[3 * Index
- 1] = L
'\0';
487 IN OUT CHAR8
*HexStr
,
488 IN OUT UINT32
*HexLength
494 Convert the binary encoded buffer into a hexadecimal encoded string.
498 BinBuffer - The buffer containing the binary data.
499 BinLength - Length of the binary buffer.
500 HexStr - Pointer to the string.
501 HexLength - The length of the string.
505 EFI_SUCCESS - The binary data is converted to the hexadecimal string
506 and the length of the string is updated.
507 EFI_BUFFER_TOO_SMALL - The string is too small.
513 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
514 return EFI_INVALID_PARAMETER
;
517 if (((*HexLength
) - 3) < BinLength
* 2) {
518 *HexLength
= BinLength
* 2 + 3;
519 return EFI_BUFFER_TOO_SMALL
;
522 *HexLength
= BinLength
* 2 + 3;
524 // Prefix for Hex String
529 for (Index
= 0; Index
< BinLength
; Index
++) {
530 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
531 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
534 HexStr
[Index
* 2 + 2] = '\0';
541 IN OUT UINT8
*BinBuffer
,
542 IN OUT UINT32
*BinLength
,
549 Convert the hexadecimal string into a binary encoded buffer.
553 BinBuffer - The binary buffer.
554 BinLength - Length of the binary buffer.
555 HexStr - The hexadecimal string.
559 EFI_SUCCESS - The hexadecimal string is converted into a binary
561 EFI_BUFFER_TOO_SMALL - The binary buffer is too small to hold the converted data.s
574 // Find out how many hex characters the string has.
577 if ((HexBuf
[0] == '0') && ((HexBuf
[1] == 'x') || (HexBuf
[1] == 'X'))) {
581 for (Index
= 0, HexCount
= 0; IsHexDigit (&Digit
, HexBuf
[Index
]); Index
++, HexCount
++)
589 // Test if buffer is passed enough.
591 if (((HexCount
+ 1) / 2) > *BinLength
) {
592 *BinLength
= (HexCount
+ 1) / 2;
593 return EFI_BUFFER_TOO_SMALL
;
596 *BinLength
= (HexCount
+ 1) / 2;
598 for (Index
= 0; Index
< HexCount
; Index
++) {
600 IsHexDigit (&Digit
, HexBuf
[HexCount
- 1 - Index
]);
602 if ((Index
& 1) == 0) {
605 Byte
= BinBuffer
[*BinLength
- 1 - Index
/ 2];
607 Byte
= (UINT8
) (Byte
| (Digit
<< 4));
610 BinBuffer
[*BinLength
- 1 - Index
/ 2] = Byte
;
625 Generate random numbers.
629 Rand - The buffer to contain random numbers.
630 RandLength - The length of the Rand buffer.
640 while (RandLength
> 0) {
641 Random
= NET_RANDOM (NetRandomInitSeed ());
642 *Rand
++ = (UINT8
) (Random
);
648 IScsiCreateDriverData (
650 IN EFI_HANDLE Controller
656 Create the iSCSI driver data..
660 Image - The handle of the driver image.
661 Controller - The handle of the controller.
665 The iSCSI driver data created.
669 ISCSI_DRIVER_DATA
*Private
;
672 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
673 if (Private
== NULL
) {
677 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
678 Private
->Image
= Image
;
679 Private
->Controller
= Controller
;
682 // Create an event to be signal when the BS to RT transition is triggerd so
683 // as to abort the iSCSI session.
685 Status
= gBS
->CreateEvent (
686 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES
,
688 IScsiOnExitBootService
,
690 &Private
->ExitBootServiceEvent
692 if (EFI_ERROR (Status
)) {
693 gBS
->FreePool (Private
);
697 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
700 // 0 is designated to the TargetId, so use another value for the AdapterId.
702 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
703 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
704 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
705 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
708 // Install the Ext SCSI PASS THRU protocol.
710 Status
= gBS
->InstallProtocolInterface (
711 &Private
->ExtScsiPassThruHandle
,
712 &gEfiExtScsiPassThruProtocolGuid
,
713 EFI_NATIVE_INTERFACE
,
714 &Private
->IScsiExtScsiPassThru
716 if (EFI_ERROR (Status
)) {
717 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
718 gBS
->FreePool (Private
);
723 IScsiSessionInit (&Private
->Session
, FALSE
);
729 IScsiCleanDriverData (
730 IN ISCSI_DRIVER_DATA
*Private
736 Clean the iSCSI driver data.
740 Private - The iSCSI driver data.
748 if (Private
->DevicePath
!= NULL
) {
749 gBS
->UninstallProtocolInterface (
750 Private
->ExtScsiPassThruHandle
,
751 &gEfiDevicePathProtocolGuid
,
755 gBS
->FreePool (Private
->DevicePath
);
758 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
759 gBS
->UninstallProtocolInterface (
760 Private
->ExtScsiPassThruHandle
,
761 &gEfiExtScsiPassThruProtocolGuid
,
762 &Private
->IScsiExtScsiPassThru
766 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
768 gBS
->FreePool (Private
);
773 IN ISCSI_DRIVER_DATA
*Private
779 Get the various configuration data of this iSCSI instance.
783 Private - The iSCSI driver data.
787 EFI_SUCCESS - The configuration of this instance is got.
788 EFI_NOT_FOUND - This iSCSI instance is not configured yet.
793 ISCSI_SESSION
*Session
;
795 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
796 EFI_SIMPLE_NETWORK_MODE
*Mode
;
797 CHAR16 MacString
[65];
800 // get the iSCSI Initiator Name
802 Session
= &Private
->Session
;
803 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
804 Status
= gIScsiInitiatorName
.Get (
805 &gIScsiInitiatorName
,
806 &Session
->InitiatorNameLength
,
807 Session
->InitiatorName
809 if (EFI_ERROR (Status
)) {
813 Status
= gBS
->HandleProtocol (
815 &gEfiSimpleNetworkProtocolGuid
,
818 if (EFI_ERROR (Status
)) {
825 // Get the mac string, it's the name of various variable
827 IScsiMacAddrToStr (&Mode
->PermanentAddress
, Mode
->HwAddressSize
, MacString
);
830 // Get the normal configuration.
832 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
833 Status
= gRT
->GetVariable (
835 &gEfiIScsiInitiatorNameProtocolGuid
,
838 &Session
->ConfigData
.NvData
840 if (EFI_ERROR (Status
)) {
844 if (!Session
->ConfigData
.NvData
.Enabled
) {
848 // Get the CHAP Auth information.
850 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
851 Status
= gRT
->GetVariable (
853 &mIScsiCHAPAuthInfoGuid
,
856 &Session
->AuthData
.AuthConfig
859 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
863 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
869 EFI_DEVICE_PATH_PROTOCOL
*
870 IScsiGetTcpConnDevicePath (
871 IN ISCSI_DRIVER_DATA
*Private
877 Get the device path of the iSCSI tcp connection and update it.
881 Private - The iSCSI driver data.
885 The updated device path.
889 ISCSI_SESSION
*Session
;
890 ISCSI_CONNECTION
*Conn
;
892 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
894 EFI_DEV_PATH
*DPathNode
;
896 Session
= &Private
->Session
;
897 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
901 Conn
= NET_LIST_USER_STRUCT_S (
902 Session
->Conns
.ForwardLink
,
905 ISCSI_CONNECTION_SIGNATURE
907 Tcp4Io
= &Conn
->Tcp4Io
;
909 Status
= gBS
->HandleProtocol (
911 &gEfiDevicePathProtocolGuid
,
914 if (EFI_ERROR (Status
)) {
920 DevicePath
= DuplicateDevicePath (DevicePath
);
922 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
924 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
925 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
926 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
929 DPathNode
->Ipv4
.LocalPort
= 0;
930 DPathNode
->Ipv4
.StaticIpAddress
= (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
934 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
942 IScsiOnExitBootService (
950 Abort the session when the transition from BS to RT is initiated.
954 Event - The event signaled.
955 Context - The iSCSI driver data.
963 ISCSI_DRIVER_DATA
*Private
;
965 Private
= (ISCSI_DRIVER_DATA
*) Context
;
966 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
968 IScsiSessionAbort (&Private
->Session
);