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 Removes (trims) specified leading and trailing characters from a string.
30 @param str[in][out] Pointer to the null-terminated string to be trimmed. On return,
31 str will hold the trimmed string.
33 @param CharC[in] Character will be trimmed from str.
53 // Trim off the leading and trailing characters c
55 for (p1
= str
; *p1
&& *p1
== CharC
; p1
++) {
75 for (p1
= str
+ StrLen(str
) - 1; p1
>= str
&& *p1
== CharC
; p1
--) {
78 if (p1
!= str
+ StrLen(str
) - 1) {
84 Calculate the prefix length of the IPv4 subnet mask.
86 @param SubnetMask[in] The IPv4 subnet mask.
88 @retval The prefix length of the subnet mask.
92 IScsiGetSubnetMaskPrefixLength (
93 IN EFI_IPv4_ADDRESS
*SubnetMask
100 // The SubnetMask is in network byte order.
102 ReverseMask
= (SubnetMask
->Addr
[0] << 24) | (SubnetMask
->Addr
[1] << 16) | (SubnetMask
->Addr
[2] << 8) | (SubnetMask
->Addr
[3]);
107 ReverseMask
= ~ReverseMask
;
109 if (ReverseMask
& (ReverseMask
+ 1)) {
115 while (ReverseMask
!= 0) {
116 ReverseMask
= ReverseMask
>> 1;
120 return (UINT8
) (32 - Len
);
124 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
126 @param Str[in] The hexadecimal encoded LUN string.
128 @param Lun[out] Storage to return the 64-bit LUN.
130 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
132 @retval EFI_INVALID_PARAMETER The string is malformatted.
142 CHAR8
*LunUnitStr
[4];
147 ZeroMem (LunUnitStr
, sizeof (LunUnitStr
));
152 if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
153 return EFI_INVALID_PARAMETER
;
156 while (*Str
!= '\0') {
158 // Legal representations of LUN:
159 // 4752-3A4F-6b7e-2F99,
167 if (*(Str
+ 1) != '\0') {
168 if (!IsHexDigit ((UINT8
*) &Digit
, *(Str
+ 1))) {
169 return EFI_INVALID_PARAMETER
;
172 LunUnitStr
[Index
] = Str
+ 1;
174 } else if (!IsHexDigit ((UINT8
*) &Digit
, *Str
)) {
175 return EFI_INVALID_PARAMETER
;
181 for (Index
= 0; (Index
< 4) && (LunUnitStr
[Index
] != NULL
); Index
++) {
182 if (AsciiStrLen (LunUnitStr
[Index
]) > 4) {
183 return EFI_INVALID_PARAMETER
;
186 Temp
= AsciiStrHexToUintn (LunUnitStr
[Index
]);
187 *((UINT16
*) &Lun
[Index
* 2]) = HTONS (Temp
);
194 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
196 @param Lun[in] The 64-bit LUN.
198 @param Str[out] The storage to return the hexadecimal encoded LUN string.
204 IScsiLunToUnicodeStr (
214 for (Index
= 0; Index
< 4; Index
++) {
216 if ((Lun
[2 * Index
] | Lun
[2 * Index
+ 1]) == 0) {
217 StrCpy (TempStr
, L
"0-");
219 TempStr
[0] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] >> 4];
220 TempStr
[1] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
] & 0xf];
221 TempStr
[2] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] >> 4];
222 TempStr
[3] = (CHAR16
) IScsiHexString
[Lun
[2 * Index
+ 1] & 0xf];
226 StrTrim (TempStr
, L
'0');
229 TempStr
+= StrLen (TempStr
);
232 Str
[StrLen (Str
) - 1] = 0;
234 for (Index
= StrLen (Str
) - 1; Index
> 1; Index
= Index
- 2) {
235 if ((Str
[Index
] == L
'0') && (Str
[Index
- 1] == L
'-')) {
244 Convert the ASCII string into a UNICODE string.
246 @param Source[out] The ASCII string.
248 @param Destination[out] The storage to return the UNICODE string.
250 @retval CHAR16 * Pointer to the UNICODE string.
254 IScsiAsciiStrToUnicodeStr (
256 OUT CHAR16
*Destination
259 ASSERT (Destination
!= NULL
);
260 ASSERT (Source
!= NULL
);
262 while (*Source
!= '\0') {
263 *(Destination
++) = (CHAR16
) *(Source
++);
272 Convert the UNICODE string into an ASCII string.
274 @param Source[in] The UNICODE string.
276 @param Destination[out] The storage to return the ASCII string.
278 @retval CHAR8 * Pointer to the ASCII string.
282 IScsiUnicodeStrToAsciiStr (
284 OUT CHAR8
*Destination
287 ASSERT (Destination
!= NULL
);
288 ASSERT (Source
!= NULL
);
290 while (*Source
!= '\0') {
292 // If any Unicode characters in Source contain
293 // non-zero value in the upper 8 bits, then ASSERT().
295 ASSERT (*Source
< 0x100);
296 *(Destination
++) = (CHAR8
) *(Source
++);
305 Convert the decimal dotted IPv4 address into the binary IPv4 address.
307 @param Str[in] The UNICODE string.
309 @param Ip[out] The storage to return the ASCII string.
311 @retval EFI_SUCCESS The binary IP address is returned in Ip.
313 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
319 OUT EFI_IPv4_ADDRESS
*Ip
330 return EFI_INVALID_PARAMETER
;
334 while (NET_IS_DIGIT (*Str
)) {
335 Number
= Number
* 10 + (*Str
- '0');
340 return EFI_INVALID_PARAMETER
;
343 Ip
->Addr
[Index
] = (UINT8
) Number
;
345 if ((*Str
!= '\0') && (*Str
!= '.')) {
347 // The current character should be either the NULL terminator or
348 // the dot delimiter.
350 return EFI_INVALID_PARAMETER
;
355 // Skip the delimiter.
364 return EFI_INVALID_PARAMETER
;
371 Convert the mac address into a hexadecimal encoded "-" seperated string.
373 @param Mac[in] The mac address.
375 @param Len[in] Length in bytes of the mac address.
377 @param Str[out] The storage to return the mac string.
384 IN EFI_MAC_ADDRESS
*Mac
,
391 for (Index
= 0; Index
< Len
; Index
++) {
392 Str
[3 * Index
] = NibbleToHexChar ((UINT8
) (Mac
->Addr
[Index
] >> 4));
393 Str
[3 * Index
+ 1] = NibbleToHexChar (Mac
->Addr
[Index
]);
394 Str
[3 * Index
+ 2] = L
'-';
397 Str
[3 * Index
- 1] = L
'\0';
401 Convert the binary encoded buffer into a hexadecimal encoded string.
403 @param BinBuffer[in] The buffer containing the binary data.
405 @param BinLength[in] Length of the binary buffer.
407 @param HexStr[in][out] Pointer to the string.
409 @param HexLength[in][out] The length of the string.
411 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
412 and the length of the string is updated.
414 @retval EFI_BUFFER_TOO_SMALL The string is too small.
421 IN OUT CHAR8
*HexStr
,
422 IN OUT UINT32
*HexLength
427 if ((HexStr
== NULL
) || (BinBuffer
== NULL
) || (BinLength
== 0)) {
428 return EFI_INVALID_PARAMETER
;
431 if (((*HexLength
) - 3) < BinLength
* 2) {
432 *HexLength
= BinLength
* 2 + 3;
433 return EFI_BUFFER_TOO_SMALL
;
436 *HexLength
= BinLength
* 2 + 3;
438 // Prefix for Hex String
443 for (Index
= 0; Index
< BinLength
; Index
++) {
444 HexStr
[Index
* 2 + 2] = IScsiHexString
[BinBuffer
[Index
] >> 4];
445 HexStr
[Index
* 2 + 3] = IScsiHexString
[BinBuffer
[Index
] & 0xf];
448 HexStr
[Index
* 2 + 2] = '\0';
454 Convert the hexadecimal string into a binary encoded buffer.
456 @param BinBuffer[in][out] The binary buffer.
458 @param BinLength[in][out] Length of the binary buffer.
460 @param HexStr[in] The hexadecimal string.
462 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
465 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.s
470 IN OUT UINT8
*BinBuffer
,
471 IN OUT UINT32
*BinLength
,
484 // Find out how many hex characters the string has.
487 if ((HexBuf
[0] == '0') && ((HexBuf
[1] == 'x') || (HexBuf
[1] == 'X'))) {
491 for (Index
= 0, HexCount
= 0; IsHexDigit (&Digit
, HexBuf
[Index
]); Index
++, HexCount
++)
499 // Test if buffer is passed enough.
501 if (((HexCount
+ 1) / 2) > *BinLength
) {
502 *BinLength
= (HexCount
+ 1) / 2;
503 return EFI_BUFFER_TOO_SMALL
;
506 *BinLength
= (HexCount
+ 1) / 2;
508 for (Index
= 0; Index
< HexCount
; Index
++) {
510 IsHexDigit (&Digit
, HexBuf
[HexCount
- 1 - Index
]);
512 if ((Index
& 1) == 0) {
515 Byte
= BinBuffer
[*BinLength
- 1 - Index
/ 2];
517 Byte
= (UINT8
) (Byte
| (Digit
<< 4));
520 BinBuffer
[*BinLength
- 1 - Index
/ 2] = Byte
;
527 Generate random numbers.
529 @param Rand[in][out] The buffer to contain random numbers.
531 @param RandLength[in] The length of the Rand buffer.
544 while (RandLength
> 0) {
545 Random
= NET_RANDOM (NetRandomInitSeed ());
546 *Rand
++ = (UINT8
) (Random
);
552 Create the iSCSI driver data..
554 @param Image[in] The handle of the driver image.
556 @param Controller[in] The handle of the controller.
558 @retval The iSCSI driver data created.
562 IScsiCreateDriverData (
564 IN EFI_HANDLE Controller
567 ISCSI_DRIVER_DATA
*Private
;
570 Private
= AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA
));
571 if (Private
== NULL
) {
575 Private
->Signature
= ISCSI_DRIVER_DATA_SIGNATURE
;
576 Private
->Image
= Image
;
577 Private
->Controller
= Controller
;
580 // Create an event to be signal when the BS to RT transition is triggerd so
581 // as to abort the iSCSI session.
583 Status
= gBS
->CreateEvent (
584 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
586 IScsiOnExitBootService
,
588 &Private
->ExitBootServiceEvent
590 if (EFI_ERROR (Status
)) {
591 gBS
->FreePool (Private
);
595 CopyMem(&Private
->IScsiExtScsiPassThru
, &gIScsiExtScsiPassThruProtocolTemplate
, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL
));
598 // 0 is designated to the TargetId, so use another value for the AdapterId.
600 Private
->ExtScsiPassThruMode
.AdapterId
= 2;
601 Private
->ExtScsiPassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
602 Private
->ExtScsiPassThruMode
.IoAlign
= 4;
603 Private
->IScsiExtScsiPassThru
.Mode
= &Private
->ExtScsiPassThruMode
;
606 // Install the Ext SCSI PASS THRU protocol.
608 Status
= gBS
->InstallProtocolInterface (
609 &Private
->ExtScsiPassThruHandle
,
610 &gEfiExtScsiPassThruProtocolGuid
,
611 EFI_NATIVE_INTERFACE
,
612 &Private
->IScsiExtScsiPassThru
614 if (EFI_ERROR (Status
)) {
615 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
616 gBS
->FreePool (Private
);
621 IScsiSessionInit (&Private
->Session
, FALSE
);
627 Clean the iSCSI driver data.
629 @param Private[in] The iSCSI driver data.
635 IScsiCleanDriverData (
636 IN ISCSI_DRIVER_DATA
*Private
639 if (Private
->DevicePath
!= NULL
) {
640 gBS
->UninstallProtocolInterface (
641 Private
->ExtScsiPassThruHandle
,
642 &gEfiDevicePathProtocolGuid
,
646 gBS
->FreePool (Private
->DevicePath
);
649 if (Private
->ExtScsiPassThruHandle
!= NULL
) {
650 gBS
->UninstallProtocolInterface (
651 Private
->ExtScsiPassThruHandle
,
652 &gEfiExtScsiPassThruProtocolGuid
,
653 &Private
->IScsiExtScsiPassThru
657 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
659 gBS
->FreePool (Private
);
664 Get the various configuration data of this iSCSI instance.
666 @param Private[in] The iSCSI driver data.
668 @retval EFI_SUCCESS The configuration of this instance is got.
670 @retval EFI_NOT_FOUND This iSCSI instance is not configured yet.
675 IN ISCSI_DRIVER_DATA
*Private
679 ISCSI_SESSION
*Session
;
681 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
682 EFI_SIMPLE_NETWORK_MODE
*Mode
;
683 CHAR16 MacString
[65];
686 // get the iSCSI Initiator Name
688 Session
= &Private
->Session
;
689 Session
->InitiatorNameLength
= ISCSI_NAME_MAX_SIZE
;
690 Status
= gIScsiInitiatorName
.Get (
691 &gIScsiInitiatorName
,
692 &Session
->InitiatorNameLength
,
693 Session
->InitiatorName
695 if (EFI_ERROR (Status
)) {
699 Status
= gBS
->HandleProtocol (
701 &gEfiSimpleNetworkProtocolGuid
,
704 if (EFI_ERROR (Status
)) {
711 // Get the mac string, it's the name of various variable
713 IScsiMacAddrToStr (&Mode
->PermanentAddress
, Mode
->HwAddressSize
, MacString
);
716 // Get the normal configuration.
718 BufferSize
= sizeof (Session
->ConfigData
.NvData
);
719 Status
= gRT
->GetVariable (
721 &gEfiIScsiInitiatorNameProtocolGuid
,
724 &Session
->ConfigData
.NvData
726 if (EFI_ERROR (Status
)) {
730 if (!Session
->ConfigData
.NvData
.Enabled
) {
734 // Get the CHAP Auth information.
736 BufferSize
= sizeof (Session
->AuthData
.AuthConfig
);
737 Status
= gRT
->GetVariable (
739 &mIScsiCHAPAuthInfoGuid
,
742 &Session
->AuthData
.AuthConfig
745 if (!EFI_ERROR (Status
) && Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
) {
749 Status
= IScsiDoDhcp (Private
->Image
, Private
->Controller
, &Session
->ConfigData
);
756 Get the device path of the iSCSI tcp connection and update it.
758 @param Private[in] The iSCSI driver data.
760 @retval The updated device path.
763 EFI_DEVICE_PATH_PROTOCOL
*
764 IScsiGetTcpConnDevicePath (
765 IN ISCSI_DRIVER_DATA
*Private
768 ISCSI_SESSION
*Session
;
769 ISCSI_CONNECTION
*Conn
;
771 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
773 EFI_DEV_PATH
*DPathNode
;
775 Session
= &Private
->Session
;
776 if (Session
->State
!= SESSION_STATE_LOGGED_IN
) {
780 Conn
= NET_LIST_USER_STRUCT_S (
781 Session
->Conns
.ForwardLink
,
784 ISCSI_CONNECTION_SIGNATURE
786 Tcp4Io
= &Conn
->Tcp4Io
;
788 Status
= gBS
->HandleProtocol (
790 &gEfiDevicePathProtocolGuid
,
793 if (EFI_ERROR (Status
)) {
799 DevicePath
= DuplicateDevicePath (DevicePath
);
801 DPathNode
= (EFI_DEV_PATH
*) DevicePath
;
803 while (!IsDevicePathEnd (&DPathNode
->DevPath
)) {
804 if ((DevicePathType (&DPathNode
->DevPath
) == MESSAGING_DEVICE_PATH
) &&
805 (DevicePathSubType (&DPathNode
->DevPath
) == MSG_IPv4_DP
)
808 DPathNode
->Ipv4
.LocalPort
= 0;
809 DPathNode
->Ipv4
.StaticIpAddress
= (BOOLEAN
) (!Session
->ConfigData
.NvData
.InitiatorInfoFromDhcp
);
813 DPathNode
= (EFI_DEV_PATH
*) NextDevicePathNode (&DPathNode
->DevPath
);
820 Abort the session when the transition from BS to RT is initiated.
822 @param Event[in] The event signaled.
824 @param Context[in] The iSCSI driver data.
831 IScsiOnExitBootService (
836 ISCSI_DRIVER_DATA
*Private
;
838 Private
= (ISCSI_DRIVER_DATA
*) Context
;
839 gBS
->CloseEvent (Private
->ExitBootServiceEvent
);
841 IScsiSessionAbort (&Private
->Session
);